简体   繁体   English

使用BLAS和LAPACKE在C ++中用SVD计算伪逆

[英]Computation of Pseidoinverse with SVD in C++ using BLAS and LAPACKE

I am trying to implement the pseudoinverse computation A* of a matrix in order to solve the Ax=b for a square nxn matrix A with dimensions in C++. 我正在尝试实现矩阵的伪逆计算A *,以解决C ++中具有尺寸的正方形nxn矩阵A的Ax = b的问题。 The arithmetic formula for A* is through the SVD decomposition. A *的算术公式是通过SVD分解得出的。

So first I compute SVD(A)=USV^T and then A*=VS U^T, where S is the inverse diagonal S where its non-zero element si becomes 1/si in S*. 因此,首先我计算SVD(A)= USV ^ T,然后计算A * = VS U ^ T,其中S是反对角线S,其中非零元素si在S *中变为1 / si。 Finally i compute the solution x=A*b 最后我计算出解x = A * b

However I am not getting the correct result. 但是我没有得到正确的结果。 I am using LAPACKE interface for c++ and cblas for matrix multiplication. 我正在使用LAPACKE接口进行c ++和cblas进行矩阵乘法。 Here is my code: 这是我的代码:

double a[n * n] = {2, -1, 2,1};
double b[n]={3,4};
double u[n * n], s[n],vt[n * n];

int lda = n, ldu = n, ldvt = n;

int info = LAPACKE_dgesdd(LAPACK_COL_MAJOR, 'A', n, n, a, lda, s,
               u, ldu, vt, ldvt);




for (int i = 0; i < n; i++) {
        s[i] = 1.0 / s[i];       
}

const int a = 1;
const int c = 0;

double r1[n];
double r2[n];
double res[n];

//compute the  first multiplication s*u^T
cblas_dgemm( CblasColMajor,CblasNoTrans, CblasTrans, n, n, n, a, u, ldvt, s, ldu, c, r1, n);

//compute the second multiplication v^T^T=vs*u^T
cblas_dgemm( CblasColMajor,CblasTrans, CblasNoTrans, n, n, n, a, vt, ldvt, r1, ldu, c, r2, n);

//now that we have the pseudoinverse A* solve by multiplying with b.
cblas_dgemm( CblasColMajor,CblasNoTrans, CblasNoTrans, n, 1, n, a, r2, ldvt, b, ldu, c, res, n);

after the second cblas_dgemm it is expected to have A* the pseudoinverse in r2. 在第二个cblas_dgemm之后,期望在r2中具有A *伪逆。 However after comparing with matlab pinv I am not getting the same result. 但是,与matlab pinv比较后,我没有得到相同的结果。 If I print r2 the result gives: 如果我打印r2,则结果为:

 0.25   0.50
 0.25   0.50

but it should be 但应该是

0.25   -0.50
0.25   0.50

The argument S of LAPACKE_dgesdd() represents the singular values of the matrix in the SVD decomposition . LAPACKE_dgesdd()的参数S表示SVD分解中矩阵的奇异值。 While it is of length n , it does not depict a vector as it represents a diagonal matrix. 虽然长度为n ,但它不表示向量,因为它表示对角矩阵。 Indeed, the outcome of Su^T is a matrix of size n*n . 实际上,Su ^ T的结果是大小为n*n的矩阵。

The routine cblas_dscal() can be applied in a loop to compute the matrix product involving the diagonal matrix, though the resulting Su^t is still transposed. 例程cblas_dscal()可以循环应用,以计算涉及对角矩阵的矩阵乘积,尽管所得Su ^ t仍会转置。 See what is the best way to multiply a diagonal matrix in fortran 了解在fortran中对角矩阵相乘的最佳方法是什么

The following code can be compiled by g++ main.cpp -o main -llapacke -llapack -lgslcblas -lblas -lm -Wall (or -lcblas`...) 以下代码可以由g++ main.cpp -o main -llapacke -llapack -lgslcblas -lblas -lm -Wall (或-lcblas` ...)编译。

#include <iostream>
#include <string>
#include <fstream>  

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



extern "C" { 
#include <lapacke.h>
#include <cblas.h>
}

int main(int argc, char *argv[])
{
const int n=2;

double a[n * n] = {2, -1, 2,1};
double b[n]={3,4};
double u[n * n], s[n],vt[n * n];

int lda = n, ldu = n, ldvt = n;

//computing the SVD
int info = LAPACKE_dgesdd(LAPACK_COL_MAJOR, 'A', n, n, a, lda, s,
               u, ldu, vt, ldvt);
if (info !=0){
std::cerr<<"Lapack error occured in dgesdd. error code :"<<info<<std::endl;
}


for (int i = 0; i < n; i++) {
        s[i] = 1.0 / s[i];       
}

const int aa = 1;
const int c = 0;

//double r1[n*n];
double r2[n*n];
double res[n];

//compute the  first multiplication s*u^T
// here : s is not a vector : it is a diagonal matrix. The ouput must be of size n*n
//cblas_dgemm( CblasColMajor,CblasNoTrans, CblasTrans, n, n, n, aa, u, ldvt, s, ldu, c, r1, n);
for (int i = 0; i < n; i++) {
cblas_dscal(n,s[i],&u[i*n],1);
}

//compute the second multiplication v^T^T=vs*u^T
cblas_dgemm( CblasColMajor,CblasTrans, CblasTrans, n, n, n, aa, vt, ldvt, u, ldu, c, r2, n);
//now, r2 is the pseudoinverse of a.
//now that we have the pseudoinverse A* solve by multiplying with b.
cblas_dgemm( CblasColMajor,CblasNoTrans, CblasNoTrans, n, 1, n, aa, r2, ldvt, b, ldu, c, res, n);


for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
    std::cout<<r2[i*n+j]<<" ";
}
}

std::cout<<std::endl;
}

It prints the expected result: 它输出预期结果:

0.25 0.25 -0.5 0.5 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM