使用C中的lapack计算矩阵的逆矩阵

时间:2010-08-19 08:28:24

标签: c lapack matrix-inverse

我希望能够使用lapack在C / C ++中计算一般NxN矩阵的逆矩阵。

我的理解是,在lapack中进行反转的方法是使用dgetri函数,但是,我无法弄清楚它的所有参数应该是什么。

这是我的代码:

void dgetri_(int* N, double* A, int* lda, int* IPIV, double* WORK, int* lwork, int* INFO);

int main(){

    double M [9] = {
        1,2,3,
        4,5,6,
        7,8,9
    };

    return 0;
}

如何使用dgetri _来完成它以获得3x3矩阵M的反函数?

4 个答案:

答案 0 :(得分:23)

这是使用C / C ++中的lapack计算矩阵的逆矩阵的工作代码:

#include <cstdio>

extern "C" {
    // LU decomoposition of a general matrix
    void dgetrf_(int* M, int *N, double* A, int* lda, int* IPIV, int* INFO);

    // generate inverse of a matrix given its LU decomposition
    void dgetri_(int* N, double* A, int* lda, int* IPIV, double* WORK, int* lwork, int* INFO);
}

void inverse(double* A, int N)
{
    int *IPIV = new int[N+1];
    int LWORK = N*N;
    double *WORK = new double[LWORK];
    int INFO;

    dgetrf_(&N,&N,A,&N,IPIV,&INFO);
    dgetri_(&N,A,&N,IPIV,WORK,&LWORK,&INFO);

    delete IPIV;
    delete WORK;
}

int main(){

    double A [2*2] = {
        1,2,
        3,4
    };

    inverse(A, 2);

    printf("%f %f\n", A[0], A[1]);
    printf("%f %f\n", A[2], A[3]);

    return 0;
}

答案 1 :(得分:18)

首先,M必须是二维数组,如double M[3][3]。从数学上讲,你的数组是1x9向量,它是不可逆的。

  • N是指向int的int的指针 矩阵的顺序 - 在这种情况下, N = 3。

  • A是指向LU的指针 矩阵的分解,其中 你可以通过运行LAPACK来获得 例行dgetrf

  • LDA是“领先”的整数 矩阵的元素,它让 你挑出一个更大的子集 如果你想反转一个矩阵 小块。如果你想反转 整个矩阵,LDA应该是 等于N。

  • IPIV是其中的支点 矩阵,换句话说,它是一个列表 交换什么行的说明 为了反转矩阵。 IPIV 应该由LAPACK生成 例行dgetrf

  • LWORK和WORK是“工作空间” 由LAPACK使用。如果你正在倒置 整个矩阵,LWORK应该是一个 int等于N ^ 2,而WORK应该是 带有LWORK元素的双数组。

  • INFO只是一个状态变量 告诉你是否操作 顺利完成。既然不是全部 矩阵是可逆的,我愿意 建议你发送给一些人 一种错误检查系统。对于成功操作,INFO = 0,如果第i个参数具有不正确的输入值,则INFO = -i,并且INFO&gt;如果矩阵不可逆,则为0。

所以,对于你的代码,我会做这样的事情:

int main(){

    double M[3][3] = { {1 , 2 , 3},
                       {4 , 5 , 6},
                       {7 , 8 , 9}}
    double pivotArray[3]; //since our matrix has three rows
    int errorHandler;
    double lapackWorkspace[9];

    // dgetrf(M,N,A,LDA,IPIV,INFO) means invert LDA columns of an M by N matrix 
    // called A, sending the pivot indices to IPIV, and spitting error 
    // information to INFO.
    // also don't forget (like I did) that when you pass a two-dimensional array
    // to a function you need to specify the number of "rows"
    dgetrf_(3,3,M[3][],3,pivotArray[3],&errorHandler);
    //some sort of error check

    dgetri_(3,M[3][],3,pivotArray[3],9,lapackWorkspace,&errorHandler);
    //another error check

    }

答案 2 :(得分:2)

以下是使用OpenBlas接口到LAPACKE的上述工作版本。 与openblas库链接(已包含LAPACKE)

% g++ -I [OpenBlas path]/include/ example.cpp [OpenBlas path]/lib/libopenblas.a
% a.out

+0.37858900  +0.97171100  +0.01608700  +0.03766800  +0.31239800 
+0.75637700  +0.34570800  +0.92294700  +0.84667100  +0.85610300 
+0.73251000  +0.10894200  +0.47696900  +0.39825400  +0.50704500 
+0.16260800  +0.22777000  +0.53307400  +0.80707500  +0.18033500 
+0.51700600  +0.31599200  +0.91484800  +0.46082500  +0.73198000 

+0.24335255  -2.67946180  +3.57538817  +0.83711880  +0.34704217 
+1.02790497  -1.05086895  -0.07468137  +0.71041070  +0.66708313 
-0.21087237  -4.47765165  +1.73958308  +1.73999641  +3.69324020 
-0.14100897  +2.34977565  -0.93725915  +0.47383541  -2.15554470 
-0.26329660  +6.46315378  -4.07721533  -3.37094863  -2.42580445 

示例:

{{1}}

答案 3 :(得分:0)

这是上面Spencer Nelson的一个工作版本。关于它的一个谜团是输入矩阵按行主顺序,即使它似乎调用了基础的fortran例程dgetri。我被引导相信所有潜在的fortran例程都需要列主要顺序,但我不是LAPACK的专家,事实上,我正在使用这个例子来帮助我学习它。但是,除了一个谜团:

示例中的输入矩阵是单数。 LAPACK尝试通过在3中返回errorHandler来告诉您。我将该矩阵中的9更改为19,获得errorHandler信令成功的0,并将结果与​​Mathematica的结果进行比较。比较也是成功的,并确认示例中的矩阵应按行主要顺序排列,如图所示。

以下是工作代码:

#include <stdio.h>
#include <stddef.h>
#include <lapacke.h>

int main() {
    int N = 3;
    int NN = 9;
    double M[3][3] = { {1 , 2 , 3},
                       {4 , 5 , 6},
                       {7 , 8 , 9} };
    int pivotArray[3]; //since our matrix has three rows
    int errorHandler;
    double lapackWorkspace[9];

    // dgetrf(M,N,A,LDA,IPIV,INFO) means invert LDA columns of an M by N matrix
    // called A, sending the pivot indices to IPIV, and spitting error information
    // to INFO. also don't forget (like I did) that when you pass a two-dimensional
    // array to a function you need to specify the number of "rows"
    dgetrf_(&N, &N, M[0], &N, pivotArray, &errorHandler);
    printf ("dgetrf eh, %d, should be zero\n", errorHandler);

    dgetri_(&N, M[0], &N, pivotArray, lapackWorkspace, &NN, &errorHandler);
    printf ("dgetri eh, %d, should be zero\n", errorHandler);

    for (size_t row = 0; row < N; ++row)
    {   for (size_t col = 0; col < N; ++col)
        {   printf ("%g", M[row][col]);
            if (N-1 != col)
            {   printf (", ");   }   }
        if (N-1 != row)
        {   printf ("\n");   }   }

    return 0;   }

我在Mac上构建并运行如下:

gcc main.c -llapacke -llapack
./a.out

我在LAPACKE库上做了nm,发现了以下内容:

liblapacke.a(lapacke_dgetri.o):
                 U _LAPACKE_dge_nancheck
0000000000000000 T _LAPACKE_dgetri
                 U _LAPACKE_dgetri_work
                 U _LAPACKE_xerbla
                 U _free
                 U _malloc

liblapacke.a(lapacke_dgetri_work.o):
                 U _LAPACKE_dge_trans
0000000000000000 T _LAPACKE_dgetri_work
                 U _LAPACKE_xerbla
                 U _dgetri_
                 U _free
                 U _malloc

看起来有一个LAPACKE [sic]包装器可能会让我们不得不为了fortran的方便而到处寻找地址,但我可能不会去尝试它,因为我有前进的方向。 / p>

修改

这是一个可以直接使用LAPACK fortran例程绕过LAPACKE [sic]的工作版本。我不明白为什么行主要输入会产生正确的结果,但我在Mathematica中再次确认了它。

#include <stdio.h>
#include <stddef.h>

int main() {
    int N = 3;
    int NN = 9;
    double M[3][3] = { {1 , 2 ,  3},
                       {4 , 5 ,  6},
                       {7 , 8 , 19} };
    int pivotArray[3]; //since our matrix has three rows
    int errorHandler;
    double lapackWorkspace[9];
    /* from http://www.netlib.no/netlib/lapack/double/dgetrf.f
      SUBROUTINE DGETRF( M, N, A, LDA, IPIV, INFO )
      *
      *  -- LAPACK routine (version 3.1) --
      *     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
      *     November 2006
      *
      *     .. Scalar Arguments ..
      INTEGER            INFO, LDA, M, N
      *     ..
      *     .. Array Arguments ..
      INTEGER            IPIV( * )
      DOUBLE PRECISION   A( LDA, * )
    */

    extern void dgetrf_ (int * m, int * n, double * A, int * LDA, int * IPIV,
                         int * INFO);

    /* from http://www.netlib.no/netlib/lapack/double/dgetri.f
       SUBROUTINE DGETRI( N, A, LDA, IPIV, WORK, LWORK, INFO )
       *
       *  -- LAPACK routine (version 3.1) --
       *     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
       *     November 2006
       *
       *     .. Scalar Arguments ..
       INTEGER            INFO, LDA, LWORK, N
       *     ..
       *     .. Array Arguments ..
       INTEGER            IPIV( * )
       DOUBLE PRECISION   A( LDA, * ), WORK( * )
    */

    extern void dgetri_ (int * n, double * A, int * LDA, int * IPIV,
                         double * WORK, int * LWORK, int * INFO);

    // dgetrf(M,N,A,LDA,IPIV,INFO) means invert LDA columns of an M by N matrix
    // called A, sending the pivot indices to IPIV, and spitting error information
    // to INFO. also don't forget (like I did) that when you pass a two-dimensional
    // array to a function you need to specify the number of "rows"
    dgetrf_(&N, &N, M[0], &N, pivotArray, &errorHandler);
    printf ("dgetrf eh, %d, should be zero\n", errorHandler);

    dgetri_(&N, M[0], &N, pivotArray, lapackWorkspace, &NN, &errorHandler);
    printf ("dgetri eh, %d, should be zero\n", errorHandler);

    for (size_t row = 0; row < N; ++row)
    {   for (size_t col = 0; col < N; ++col)
        {   printf ("%g", M[row][col]);
            if (N-1 != col)
            {   printf (", ");   }   }
        if (N-1 != row)
        {   printf ("\n");   }   }
    return 0;   }

建立并运行如下:

$ gcc foo.c -llapack
$ ./a.out
dgetrf eh, 0, should be zero
dgetri eh, 0, should be zero
-1.56667, 0.466667, 0.1
1.13333, 0.0666667, -0.2
0.1, -0.2, 0.1

修改

这个谜团似乎不再是一个谜。我认为计算是按照列主要顺序进行的,因为它们必须如此,但我输入和打印矩阵就像它们按行主顺序一样。我有两个相互抵消的错误,所以即使它们是列式的,它们看起来仍然是行列式的。