web-dev-qa-db-ja.com

簡単な例でC ++のLAPACK呼び出しを理解する

私はLAPACKとC++/Fortranインターフェースの初心者です。 Mac OS-XLionでLAPACK/BLASを使用して、線形方程式と固有値の問題を解決する必要があります。 OS-X Lionは最適化されたBLASおよびLAPACKライ​​ブラリ(/ usr/lib内)を提供しており、netlibからダウンロードする代わりに、これらのライブラリをリンクしています。

私のプログラム(以下に再現)はコンパイルされて正常に実行されていますが、間違った答えが返されます。私はWebとStackoverflowで調査しましたが、この問題は、C++とFortranが異なる形式(行メジャーと列メジャー)で配列を格納する方法に対処する必要があるかもしれません。ただし、私の例でわかるように、私の例の単純な配列は、C++とFortranで同じように見えるはずです。とにかくここに行きます。

次の線形システムを解きたいとしましょう。

x + y = 2

x-y = 0

解は(x、y)=(1,1)です。今、私は次のようにLapackを使用してこれを解決しようとしました

// LAPACK test code

#include<iostream>
#include<vector>

using namespace std;
extern "C" void dgetrs(char *TRANS, int *N, int *NRHS, double *A, 
                      int *LDA, int *IPIV, double *B, int *LDB, int *INFO );

int main()
{
    char trans = 'N';
    int dim = 2;    
    int nrhs = 1;
    int LDA = dim;
    int LDB = dim;
    int info;

    vector<double> a, b;

    a.Push_back(1);
    a.Push_back(1);
    a.Push_back(1);
    a.Push_back(-1);

    b.Push_back(2);
    b.Push_back(0);

    int ipiv[3];


    dgetrs(&trans, &dim, &nrhs, & *a.begin(), &LDA, ipiv, & *b.begin(), &LDB, &info);


    std::cout << "solution is:";    
    std::cout << "[" << b[0] << ", " << b[1] << ", " << "]" << std::endl;
    std::cout << "Info = " << info << std::endl; 

    return(0);
}

このコードは次のようにコンパイルされました。

g++ -Wall -llapack -lblas lapacktest.cpp

ただし、これを実行すると、(-2,2)として解が得られますが、これは明らかに間違っています。マトリックスaの行/列の再配置のすべての組み合わせを試しました。また、aの行列表現は行と列の形式で同一である必要があることに注意してください。この簡単な例を機能させることで、LAPACKを使い始めることができ、助けていただければ幸いです。

18
RDK

dgetrfを使用してシステムを解く前に、(dgetrsを呼び出して)行列をfactorする必要があります。または、dgesvルーチンを使用して、両方の手順を実行することもできます。

ちなみに、インターフェースを自分で宣言する必要はありません。インターフェースはAccelerateヘッダーにあります。

// LAPACK test code

#include <iostream>
#include <vector>
#include <Accelerate/Accelerate.h>

using namespace std;

int main()
{
    char trans = 'N';
    int dim = 2;    
    int nrhs = 1;
    int LDA = dim;
    int LDB = dim;
    int info;

    vector<double> a, b;

    a.Push_back(1);
    a.Push_back(1);
    a.Push_back(1);
    a.Push_back(-1);

    b.Push_back(2);
    b.Push_back(0);

    int ipiv[3];

    dgetrf_(&dim, &dim, &*a.begin(), &LDA, ipiv, &info);
    dgetrs_(&trans, &dim, &nrhs, & *a.begin(), &LDA, ipiv, & *b.begin(), &LDB, &info);


    std::cout << "solution is:";    
    std::cout << "[" << b[0] << ", " << b[1] << ", " << "]" << std::endl;
    std::cout << "Info = " << info << std::endl; 

    return(0);
}
21
Stephen Canon

Accelerate Frameworkに煩わされたくない人のために、私はStephen Canonのコード(もちろん彼に感謝します)に純粋なライブラリリンクだけを提供します

// LAPACK test code
//compile with: g++ main.cpp -llapack -lblas -o testprog

#include <iostream>
#include <vector>

using namespace std;

extern "C" void dgetrf_(int* dim1, int* dim2, double* a, int* lda, int* ipiv, int* info);
extern "C" void dgetrs_(char *TRANS, int *N, int *NRHS, double *A, int *LDA, int *IPIV, double *B, int *LDB, int *INFO );

int main()
{
    char trans = 'N';
    int dim = 2;
    int nrhs = 1;
    int LDA = dim;
    int LDB = dim;
    int info;

    vector<double> a, b;

    a.Push_back(1);
    a.Push_back(1);
    a.Push_back(1);
    a.Push_back(-1);

    b.Push_back(2);
    b.Push_back(0);

    int ipiv[3];

    dgetrf_(&dim, &dim, &*a.begin(), &LDA, ipiv, &info);
    dgetrs_(&trans, &dim, &nrhs, & *a.begin(), &LDA, ipiv, & *b.begin(), &LDB, &info);


    std::cout << "solution is:";
    std::cout << "[" << b[0] << ", " << b[1] << ", " << "]" << std::endl;
    std::cout << "Info = " << info << std::endl;

    return(0);
}

また、マニュアルについては、IntelのWebサイトで完全なPDFバージョンを入手できます。HTMLドキュメントのサンプルを次に示します。

http://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-A02DB70F-9704-42A4-9071-D409D783D911.htm

C++からLAPACKを使用する場合は、 [〜#〜] flens [〜#〜] を確認することをお勧めします。 LAPACKへの低レベルおよび高レベルのインターフェースを定義しますが、一部のLAPACK関数も再実装します。

低レベルのFLENS-LAPACKインターフェイスを使用すると、独自のマトリックス/ベクトルタイプを使用できます(LAPACK準拠のメモリレイアウトがある場合)。 dgetrfの呼び出しは次のようになります。

info = lapack::getrf(NoTrans, dim, nrhs, a.begin(), LDA, ipiv);

およびdgetrsの場合

lapack::getrs(NoTrans, dim, nrhs, a.begin(), LDA, ipiv, b.begin(), LDB);

そのため、低レベルのFLENS-LAPACK関数は、要素タイプに関してオーバーロードされます。したがって、LAPACK関数sgetrsdgetrscgetrszgetrsは、FLENS-LAPACK lapack::getrsの低レベルインターフェースにあります。また、ポインタとしてではなく、値/参照によってパラメータを渡します(たとえば、&LDAの代わりにLDA)。

FLENSマトリックスタイプを使用する場合は、次のようにコーディングできます。

info = lapack::trf(NoTrans, A, ipiv);
if (info==0) {
    lapack::trs(NoTrans, A, ipiv, b);
}

または、LAPACKドライバー関数dgesvを使用するだけです。

lapack::sv(NoTrans, A, ipiv, b);

ここで FLENS-LAPACKのリスト ドライバー関数。

免責事項:はい、FLENSは私の赤ちゃんです!つまり、約95%をコーディングし、コードのすべての行に価値があったということです。

2
Michael Lehn