LAPACKE函数中对角化所需的全矩阵或三边形部分?

时间:2019-10-01 09:14:45

标签: c++ lapack intel-mkl

我想计算对称矩阵的特征值,并希望使用C ++中的英特尔MKL库中的LAPACKE_dsyev函数。但是我对于矩阵需要传递的形式感到有些困惑。

从文档https://software.intel.com/en-us/mkl-developer-reference-c-syev中得出的结论是,我只需要传递矩阵的上/下三角形部分。关于论点,它说“它是一个包含对称矩阵A的上三角部分或下三角部分的数组”。但是,似乎实际上需要将指向完整矩阵的指针传递给例程。

说我想对角化以下矩阵:


[[-2,   0,     0.5,  0], 
[0,     0.5, -2,     0.5], 
[0.5,  -2,    0.5,  0], 
[0,     0.5,  0,    -1]], 
which has eigenvalues [ 2.56,  -2.22, -1.53, -0.81]

然后在下面的代码中,只有第一个选项给出正确的值。

#include <iostream>
#include"mkl_lapacke.h"

using namespace std;

int main(){
    MKL_INT N = 4;
    // use full matrix
    double matrix_ex_full[16] = {-2,0,0.5,0,0,0.5,-2,0.5,0.5, -2, 0.5, 0, 0,0.5,0,-1};
    double evals_full[4];
    MKL_INT test1 = LAPACKE_dsyev(LAPACK_ROW_MAJOR, 'N', 'U', N, matrix_ex_full,N, evals_full);
    cout << "success = " <<test1 << endl;
    for (MKL_INT i = 0;i<4;i++)
        cout << evals_full[i] << endl;
    // use upper triagonal only
    double matrix_ex_uppertri[10] = {-2, 0, 0.5, 0, 0.5, -2, 0.5, 0.5, 0, -1};
    double evals_uppertri[4];
    MKL_INT test2 = LAPACKE_dsyev(LAPACK_ROW_MAJOR, 'N', 'U', N, matrix_ex_uppertri,N, evals_uppertri);
    cout << "success = " <<test2 << endl;
    for (MKL_INT i = 0;i<4;i++)
        cout << evals_uppertri[i] << endl;
    // (Compiled with g++ test.cpp -o main -m64 -I/share/opt/intel/compilers_and_libraries_2018.0.128/linux/mkl/include -L/share/opt/intel/compilers_and_libraries_2018.0.128/linux/mkl/lib/intel64 -Wl,--no-as-needed -lmkl_intel_lp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl)
}

为什么在将指针传递到完整矩阵时只能得到正确的特征值?

我觉得这肯定是一个琐碎的问题,但是我想念的是什么?如果必须始终指定完整的矩阵,那么用“ U”或“ L”指定给出矩阵的哪个三角形对我来说是没有意义的。还是我在其他地方做错了?

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

根据documentation of Lapack regarding naming scheme,函数sy中的字母dsyev()表示对称矩阵,而字母d则表示双精度,而{{1} }指特征值。不过,格式ev对应于a conventional storage的二维数组,其形状与矩阵一致。根据参数UPLO的值,使用上三角部分还是下三角部分。

要使用压缩格式,请查看函数dspev(),其中字母sy对应于packed storage of symmetric matrices。来自LAPACKE的函数LAPACKE_dspev()提供了一个方便的C接口。

以下是由sp编译的示例代码:

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

LAPACKE_dspev_work()的文档所示,使用#include <iostream> #include <math.h> extern "C" { #include <lapacke.h> } using namespace std; int main(int argc, char *argv[]) { lapack_int N = 4; // use full matrix double matrix_ex_full[16] = {-2,0,0.5,0, 0,0.5,-2,0.7, 0.5, -2, 0.5, 0, 0,0.7,0,-1}; double evals_full[4]; lapack_int test1 = LAPACKE_dsyev(LAPACK_ROW_MAJOR, 'N', 'U', N, matrix_ex_full,N, evals_full); cout << "success = " <<test1 << endl; for (int i = 0;i<4;i++) cout << evals_full[i] << endl; // use upper triagonal only double matrix_ex_uppertri[10] = {-2, 0, 0.5, 0, 0.5, -2, 0.7, 0.5, 0, -1}; double evals_uppertri[4]; int test2 = LAPACKE_dspev(LAPACK_COL_MAJOR, 'N', 'L', N, matrix_ex_uppertri, evals_uppertri,NULL,N); cout << "success = " <<test2 << endl; for (int i = 0;i<4;i++) cout << evals_uppertri[i] << endl; return 0; } 可以节省一些临时数组。由于未计算特征向量,因此结果与LAPACK_COL_MAJOR保持一致。

答案 1 :(得分:1)

根据this example,看来LAPACKE_dsyev需要在完整存储方案中存储一个上部或下部三角形部分。甚至文档说,参数a应该是大小为max(1, lda * n)的数组,在您的情况下为16。

当我切换到矩阵的这个定义时:

double matrix_ex_uppertri[16] =
   { -2.0,  0.0,  0.5,  0.0,
      0.0,  0.5, -2.0,  0.5,
      0.0,  0.0,  0.5,  0.0,
      0.0,  0.0,  0.0, -1.0 };

然后,我得到了正确的特征值。

需要承认这里的文档非常容易引起误解。不明白为什么他们没有明确指定存储方案。