使用CBLAS / LAPACK的C中的对称矩阵求逆

时间:2012-05-23 11:58:27

标签: c lapack blas accelerate-framework matrix-inverse

我在C中编写一个需要矩阵和向量乘法的算法。我有一个矩阵 Q (W x W),它是通过乘以矢量 J 的转置而创建的( 1 x W)自身并添加标识矩阵 I ,使用标量 a 进行缩放。

Q = [(J ^ T)* J + aI]。

然后我必须将 向量G 相乘得到向量 M

M =(Q ^( - 1))* G。

我正在使用 cblas clapack 来开发我的算法。当矩阵 Q 使用随机数填充(类型为float)并使用例程 sgetrf _ sgetri _ 进行反转时,计算出的反函数正确

但是当矩阵Q是对称的时,乘以(J ^ T)x J就是这种情况,计算出的逆是错误的!!

在从C调用 lapack 例程时,我知道数组的行主要(在C中)和列主要(在FORTRAN中)格式,但对于对称矩阵,这不应该是问题为A ^ T = A.

我已经在下面附加了我的C函数代码用于矩阵求逆。

我相信有更好的方法来解决这个问题。任何人都可以帮我这个吗?

使用cblas的解决方案会很棒......

感谢。

void InverseMatrix_R(float *Matrix, int W)
{   
    int     LDA = W;
    int     IPIV[W];
    int     ERR_INFO;
    int     LWORK = W * W;
    float   Workspace[LWORK];

    // - Compute the LU factorization of a M by N matrix A
    sgetrf_(&W, &W, Matrix, &LDA, IPIV, &ERR_INFO);

    // - Generate inverse of the matrix given its LU decompsotion
    sgetri_(&W, Matrix, &LDA, IPIV, Workspace, &LWORK, &ERR_INFO);

    // - Display the Inverted matrix
    PrintMatrix(Matrix, W, W);

}

void PrintMatrix(float* Matrix, int row, int colm)
{
    int i,k;

    for (i =0; i < row; i++) 
    {
        for (k = 0; k < colm; k++) 
        {
            printf("%g, ",Matrix[i*colm + k]);
        }

        printf("\n");
    }
}

3 个答案:

答案 0 :(得分:4)

我不知道BLAS或LAPACK,所以我不知道是什么原因导致这种行为。

但是,对于给定形式的矩阵,计算逆是非常容易的。对此重要的是

(J^T*J)^2 = (J^T*J)*(J^T*J) = J^T*(J*J^T)*J = <J|J> * (J^T*J)

其中<u|v>表示内部产品(如果组件是真实的 - 复杂组件的规范双线性形式,但是你可能不会考虑转置而是共轭转置,你会回到内在的产品上。)

要概括,

(J^T*J)^n = (<J|J>)^(n-1) * (J^T*J), for n >= 1.

让我们用(J^T*J)表示对称方阵S,用<J|J>表示标量q。然后,对于具有足够大的绝对值(a != 0)的一般|a| > q

(a*I + S)^(-1) = 1/a * (I + a^(-1)*S)^(-1)
               = 1/a * (I + ∑ (-1)^k * a^(-k) * S^k)
                           k>0
               = 1/a * (I + (∑ (-1)^k * a^(-k) * q^(k-1)) * S)
                            k>0
               = 1/a * (I - 1/(a+q)*S)
               = 1/a*I - 1/(a*(a+q))*S

aa = 0之外的所有a = -q,该公式(通过分析性)保留,可通过计算验证

(a*I + S) * (1/a*I - 1/(a*(a+q))*S) = I + 1/a*S - 1/(a+q)*S - 1/(a*(a+q))*S^2
                                    = I + 1/a*S - 1/(a+q)*S - q/(a*(a+q))*S
                                    = I + ((a+q) - a - q)/(a*(a+q))*S
                                    = I

使用S^2 = q*S

该计算也比首次找到LU分解更简单,更有效。

答案 1 :(得分:0)

3x3矩阵求逆的示例,请访问sgetri.f了解更多

//__CLPK_integer is typedef of int
//__CLPK_real is typedef of float


__CLPK_integer ipiv[3];
{
    //Compute LU lower upper factorization of matrix
    __CLPK_integer m=3;
    __CLPK_integer n=3;
    __CLPK_real *a=(float *)this->m1;
    __CLPK_integer lda=3;
    __CLPK_integer info;
    sgetrf_(&m, &n, a, &lda, ipiv, &info);
}

{
    //compute inverse of a matrix
    __CLPK_integer n=3;
    __CLPK_real *a=(float *)this->m1;
    __CLPK_integer lda=3;
    __CLPK_real work[3];
    __CLPK_integer lwork=3;
    __CLPK_integer info;
    sgetri_(&n, a, &lda, ipiv, work, &lwork, &info);
}

答案 2 :(得分:0)

您可能想尝试Armadillo,这是一个易于使用的LAPACK C ++包装器。它提供了几个与逆相关的函数:

  • inv(),一般反向,对称正定矩阵的可选加速
  • pinv(),pseudo-inverse
  • solve(),解决一个线性方程组(可以是超定或欠定),而不做实际的反演