1

ここでは、LAPACKE の関数 LAPACKE_zheevx() を使用しているときに遭遇した奇妙なバグについて説明します。4 つの固有値/ベクトルのうち 3 つを計算する単純なテスト コード (Intel の Web サイトの例) はうまく機能し、正しい出力が得られます。ただし、ソース コードに任意の文字列の宣言を導入すると (例: std::string OutputFIlename;)、コンパイルはうまくいきますが、実行時にセグメンテーション エラー SIGSEGV が発生します !!!

まず、機能するコードをリストします。

//===========================
#include <iostream>
#include <string>
#include <fstream>  
#include <cassert>  

#include <stdlib.h>
#include <stdio.h>
#include <complex>
#include <math.h>

#include "Headers_LAPACKE\lapacke.h"
#include "Headers_LAPACKE\lapacke_config.h"
#include "Headers_LAPACKE\lapacke_mangling.h"
#include "Headers_LAPACKE\lapacke_utils.h"

void print_matrix( char* desc, lapack_int m, lapack_int n, lapack_complex_double* a, lapack_int lda );

int main()
{
    std::cout << "Start..." << std::endl;
    //std::string fn_VALS; 

    // --------------- LAPACKE --- define variables ----------------------------------------------------------------
    //

    // Define arguments for LAPACKE_zheevx() routine:
    int matrix_layout;  // = LAPACK_ROW_MAJOR or LAPACK_COL_MAJOR

    char jobz;          // It is ="V" to calculate EigenVECTORS and
                        // ="N" if you don't do it.

    char range;         // ="A" for ALL values (don't want this),
                        // ="V" for values in in the half-open interval (vl,vu],
                        // ="I" for EigenVALUES indexed from il through iu (this is what you want).

    char uplo;          // ="U" for Upper Triangle of the matrix, or
                        // ="L" for the Lower triangle of the matrix.

    lapack_int n;       // the order of matrix "a" to be diagonalized.

    lapack_complex_double* a;   // complex array of dimension (lda,n).
                                // On entry it is Hermitian matrix "a".
                                // uplo="U" means the leading n-by-n upper triangular part of "a" contain the upper triangular part of the Hermitial matrix to be diagonalized.
                                // uplo="L" means equivalent for the lower triangular part.
                                // On exit, this content is destroyed.

    lapack_int lda;     // leading dimension of "a": lda >= max(1,n).

    double    vl;         // taken into account only if range="V": vl<vu. Not referenced if range="I" or range="A".
    double    vu;         // taken into account only if range="V": vl<vu. Not referenced if range="I" or range="A".

    lapack_int il;      // taken into account only if range="I": il<iu. Indices in ascending order of SMALLEST EigenVALUE to be returned. Not referenced if range="v" or range="A".
    lapack_int iu;      // taken into account only if range="I": il<iu. Indices in ascending order of LARGEST EigenVALUE to be returned.  Not referenced if range="v" or range="A".

    double    abstol;     // The absolute error tolerance for EigenVALUES. If abstop =<0, then EPS*|T| is used. If you get info>0 (some eigenvalues did not converge) then try abstol=2*DLAMCH('S').
    lapack_int* m;      // total number of EigenVALUES found: 0 =< m =< n, If range="A" then m=n, if range="I" then m = iu-il+1.
    double* w;          // double precision array of dimension n. On normal exit, the first m elements contain the selected EigenVALUES in ASCENDING ORDER.
    lapack_complex_double* z; // double precision array of dimension (ldz, max(1,m)). If jobz="V" and info=0, the first m-columns of z contain normalized EigenVECTORS of a, corresponding to the selected EigenVALUES, with i-th column of z contains the Eigenvectro corresponding to w(i) eigenvalue.
    lapack_int ldz;     // leading dimension of array z. ldz>=1 and if jobz="V" then ldz >= max(1,n).

        // following are  used only with LAPACKE_zheevx_work() routine:.
        //lapack_complex_double* work;    // array of dimension max(1,lwork).
        //lapack_int lwork;               // lwork=-1 means workspace query. Othewise it has to be length of the array work: lwork=2*n for n>1, and lwork >=1 for N=<1.
        //double* rwork;                  // array dimension is 7*n;
        //lapack_int* iwork;              // array dimension is 5*n;

    lapack_int* ifail;  // jobz="V" and info=0: first m elemens of ifail are zero. jobz="V" and info>0: ifail contain indices of the eigenvectors that failed to converge.
    lapack_int info;    //info=0 means successful exit. info>0 means eigenvectors failed to converge, their indices are in ifail. info<0, info=-i means i-th argument had an illegal value.
    //
    // ------------------------------------------------------------------------------------------------------------

    matrix_layout = LAPACK_ROW_MAJOR;
    jobz = 'V'; vl = 0.0; vu =100.0;
    il = 1; iu=4; // are ignored now.
    range = 'V';
    uplo ='U';
    n = 4;
    lda = n;
    ldz = n;

    z = new lapack_complex_double [ldz*n];
    w = new double [n];
    a = new lapack_complex_double [lda*n];
    a[0] =lapack_complex_double{6.51,0.0}; a[1] =lapack_make_complex_double(-5.92, 9.53); a[2]=lapack_complex_double{-2.46,2.91}; a[3]=lapack_complex_double{8.84,3.21};
    a[4] =lapack_complex_double{0.0,0.0};  a[5] =lapack_make_complex_double(-1.73,0.0);   a[6]=lapack_complex_double{6.5,2.09};    a[7]=lapack_complex_double{1.32, 8.81};
    a[8] =lapack_complex_double{0.0,0.0};  a[9] =lapack_make_complex_double(0.0,0.0);     a[10]=lapack_complex_double{6.90,0.0};   a[11]=lapack_complex_double{-0.59,2.47};
    a[12]=lapack_complex_double{0.0,0.0};  a[13]=lapack_make_complex_double(0.0,0.0);     a[14]=lapack_complex_double{0.0,0.0};    a[15]=lapack_complex_double{-2.85,0.0};

    ifail = new lapack_int [n];
    abstol = -1;  // set default tolerance for calcuation of EigVals in the assigned interval.

    print_matrix( "Entry Matrix A:", n, n, a, lda );
    std::cout << std::endl;

    info = LAPACKE_zheevx(matrix_layout, jobz, range, uplo, n, a, lda,  vl,  vu,  il, iu,  abstol, m, w, z, ldz, ifail);

    if (info>0)
    {
        std::cout << "Error: ZHEEVX failed to compute eigenvalues/vectors.";
        exit(1);
    }
    std::cout << "info = " << info << std::endl;

    std::cout << "Number of eigvals found: " << *m << std::endl;
    for (int i_e =0; i_e<*m; i_e++)
    {
         std::cout << "Eigval. " << i_e << " is " << w[i_e] << std::endl;
    }

    print_matrix( "Selected EigVECTORS (column-wise):", n, n, z, ldz );
    std::cout << std::endl;


    std::cout << "Done :-) !!!" <<std::endl;

    return 0;
}


////////////////////////////////////////////////////////* Auxiliary routine: printing a matrix */
void print_matrix( char* desc, lapack_int m, lapack_int n, lapack_complex_double* a, lapack_int lda )
{
        lapack_int i, j;
        printf( "\n %s\n", desc );
        for( i = 0; i < m; i++ )
        {
            for( j = 0; j < n; j++ )
            {
                printf( " (%6.2f,%6.2f)", lapack_complex_double_real(a[i*lda+j]), lapack_complex_double_imag(a[i*lda+j]) );
            }
            printf( "\n" );
        }
}
//=======================================

ここで、main() で 2 行目のコメント記号 (//) を削除すると、次のようになります。 //std::string fn_VALS; これは std::string fn_VALS; になります。これでソースはコンパイルされますが、実行時にセグメンテーション エラー SIGSEGV で失敗します。

より詳しい情報:

Windows 7 Pro と Code::Blocks を使用しています。LAPACKE ヘッダーと dll は 2016 年 6 月 15 日にダウンロードされました。コンソールから: Process returned -1073741819 (0xC0000005) Code::Blocks のコール スタック ウィンドウから

.......... main() 呼び出し LAPACKE_zheevx() [lapacke.dll]

.......... LAPACKE_zheevx() は LAPACKE_zheevx_work() を呼び出します [lapacke.dll]

.......... LAPACKE_zheevx_work() は zheevx_() を呼び出します [lapack.dll]

助けてください。

4

1 に答える 1

1

次のように入力して、提供されたプログラムをコンパイルしようとしました。

g++ main.cpp -o main -llapacke -llapack -lblas -lm -Wall

フラグ-Wallはすべての警告を有効にします。警告の 1 つは興味深いものです。

警告: 'm' は、この関数で初期化されていない状態で使用されています [-Wuninitialized]

ポインターは呼び出されたときlapack_int* m;に初期化されません。LAPACKE_zheevx(..., m, ...);したがって、メモリ内の任意の場所を指すことができます。ポインターmは関数の出力パラメーターをホストすることが期待されており、LAPACKE_zheevx()または後続の関数がポインターを逆参照する可能性がありますm。これは未定義の動作につながります。m指している場所によっては、気付かれないままになったり、セグメンテーション違反を引き起こしたりする可能性があります。

lapack_int* m[1];の代わりに試していただけますlapack_int* m;か?

intel のこの例でmは、 として宣言され、MKL_INT引数によって関数 ( ) に渡されるのと同じ問題はありません&m。それはあなたが始めたものですか?

于 2016-06-21T18:33:19.413 に答える