2014-02-23 36 views
2

我試圖因式分解與C++中的QR factorization,使用LAPACK的函數的矩陣,以求解線性方程系統(Ax = b的)求解的線性系統具有LAPACK的dgeqrf_

據我理解, dgeqrf計算QR分解並覆蓋輸入矩陣。輸出清楚地包含L(上三角)的值,但是如何獲得Q?

我試圖dormqr,據說這是從dgeqrf的輸出計算Q,但結果是相同的基質如在先前的呼叫。

這裏是我的完整代碼:

boost::numeric::ublas::matrix<double> in_A(4, 3); 
in_A(0, 0) = 1.0; 
in_A(0, 1) = 2.0; 
in_A(0, 2) = 3.0; 

in_A(1, 1) = -3.0; 
in_A(1, 2) = 2.0; 
in_A(1, 3) = 1.0; 

in_A(2, 1) = 2.0; 
in_A(2, 2) = 0.0; 
in_A(2, 3) = -1.0; 

in_A(3, 1) = 3.0; 
in_A(3, 2) = -1.0; 
in_A(3, 3) = 2.0; 

boost::numeric::ublas::vector<double> in_b(4); 
in_b(0) = 2; 
in_b(1) = 4; 
in_b(2) = 6; 
in_b(3) = 8; 

int rows = in_A.size1(); 
int cols = in_A.size2(); 
double *A = (double *)malloc(rows*cols*sizeof(double)); 
double *b = (double *)malloc(in_b.size()*sizeof(double)); 

//Lapack has column-major order 
for(size_t col=0; col<in_A.size2(); ++col) 
{ 
    for(size_t row = 0; row<in_A.size1(); ++row) 
{ 
    int D1_idx = col*in_A.size1() + row; 
    A[D1_idx] = in_A(row, col); 
} 
b[col] = in_b(col); 
} 

integer m = rows; 
integer n = cols; 

integer info = 0; 
integer k = n;   /* k = min(m,n);  */ 
integer lda = m;  /* lda = max(m,1);  */ 
integer lwork = n;  /* lwork = max(n,1); */ 
int max = lwork; /* max = max(lwork,1); */ 

double *work; 
double *tau; 

char *side = "L"; 
char *TR = "T"; 
integer one = 1; 
int i; 

double *vec; 

work = (double *) malloc(max * sizeof(double)); 
tau = (double *) malloc(k * sizeof(double)); 
vec = (double *) malloc(m * sizeof(double)); 

memset(work, 0, max * sizeof(double)); 
memset(tau, 0, k * sizeof(double)); 
std::cout << std::endl; 
for(size_t row = 0; row < rows; ++row) 
{ 
for(size_t col = 0; col < cols; ++col) 
{ 
size_t idx = col*rows + row; 
std::cout << A[idx] << " "; 
} 
std::cout << std::endl; 
} 
dgeqrf_(&m, &n, A, &lda, tau, work, &lwork, &info); 
//printf("tau[0] = %f tau[1] = %f\n",tau[0],tau[1]); 

std::cout << std::endl; 
for(size_t row = 0; row < rows; ++row) 
{ 
    for(size_t col = 0; col < cols; ++col) 
    { 
    size_t idx = col*rows + row; 
    std::cout << A[idx] << " "; 
    } 
std::cout << std::endl; 
} 

memset(vec, 0, m * sizeof(double)); 
vec[2] = 1.0; 

dormqr_(side, TR, &m, &one, &k, A, &lda, tau, vec, &lda, work, &lwork, &info); 

free(vec); 
free(tau); 
free(work); 

這有什麼錯我的代碼?

如何分解矩陣並求解相應的線性方程組?

+0

請檢查您的IN_A的建設。列索引(0,1,2)或(1,2,3)是否? – LutzL

回答

6

根據

http://www.netlib.org/lapack/explore-html/da/d82/dormqr_8f.html)的文檔

您VEC的乘積C 1-4 T * E3,E3,其中是第三標準基底向量(0,0,1,0計算中, 0,...,0)。如果你想計算Q,那麼vec應該包含一個用單位矩陣填充的矩陣大小的數組,而TRANS應該是「N」。


dormqr (SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, LWORK, INFO) 
  • SIDE = 「L」 爲具有Q正常QR分解左,

  • TRANS = 「N」 以在Ç

  • 的地方返回QC A在存儲器中具有佈局LDA x K,其中使用上部M x K塊並且編碼K個反射器

  • tau蛋白包含因子K個反射器

  • C具有在存儲器佈局LDC×M個,其中的上的M×N塊將用於保存結果QC

  • 對於C上保持Q迴歸,C必須是一個方形的M×M矩陣初始化爲標識,即對角線條目,將全部1.


你可能會考慮使用提供的uBLAS的LAPACK數字綁定,如

http://boost.2283326.n4.nabble.com/How-to-use-the-qr-decomposition-correctly-td2710159.html

但是,這個項目可能已經停止或現在休息。


允許從第一原理重新開始:目的是要解決的X = B,或至少最小化| A X-B | + | X |。爲了保持一致,需要colsA=rowsxrowsA=rowsb

現在要討論的代碼工作A必須是正方形或高矩形矩陣colsA<=rowsA,以便系統超定。

計算步驟

備註:對於純溶液方法沒有理由以計算「Q」明確地或以調用通用矩陣乘法DGEMM。這些應該保留用於實驗以檢查A-QR是否足夠接近零。

備註:通過使用LWORK = -1執行幹運行,探索WORK陣列的最佳分配。


總之一些代碼工作,但是,與uBLAS庫LAPACK之間的聯繫似乎欠佳

#include "boost/numeric/ublas/matrix.hpp" 
#include "boost/numeric/ublas/vector.hpp" 

typedef boost::numeric::ublas::matrix<double> bmatrix; 
typedef boost::numeric::ublas::vector<double> bvector; 


namespace lapack { 


    extern "C" { 
     void dgeqrf_(int* M, int* N, 
        double* A, int* LDA, double* TAU, 
        double* WORK, int* LWORK, int* INFO); 

     void dormqr_(char* SIDE, char* TRANS, 
        int* M, int* N, int* K, 
        double* A, int* LDA, double* TAU, 
        double* C, int* LDC, 
        double* WORK, int* LWORK, int* INFO); 

     void dtrtrs_(char* UPLO, char* TRANS, char* DIAG, 
        int* N, int* NRHS, 
        double* A, int* LDA, 
        double* B, int* LDB, 
        int* INFO); 
    } 

    int geqrf(int m, int n, 
       double* A, int lda, double *tau) { 
     int info=0; 
     int lwork=-1; 
     double iwork; 
     dgeqrf_(&m, &n, A, &lda, tau, 
         &iwork, &lwork, &info); 
     lwork = (int)iwork; 
     double* work = new double[lwork]; 
     dgeqrf_(&m, &n, A, &lda, tau, 
         work, &lwork, &info); 
     delete[] work; 
     return info; 
    } 

    int ormqr(char side, char trans, int m, int n, int k, 
       double *A, int lda, double *tau, double* C, int ldc) { 
     int info=0; 
     int lwork=-1; 
     double iwork; 
     dormqr_(&side, &trans, &m, &n, &k, 
       A, &lda, tau, C, &ldc, &iwork, &lwork, &info); 
     lwork = (int)iwork; 
     double* work = new double[lwork]; 
     dormqr_(&side, &trans, &m, &n, &k, 
       A, &lda, tau, C, &ldc, work, &lwork, &info); 
     delete[] work; 
     return info; 
    } 

    int trtrs(char uplo, char trans, char diag, 
       int n, int nrhs, 
       double* A, int lda, double* B, int ldb 
    ) { 
     int info = 0; 
     dtrtrs_(&uplo, &trans, &diag, &n, &nrhs, 
       A, &lda, B, &ldb, &info); 
     return info; 
    } 

} 

static void PrintMatrix(double A[], size_t rows, size_t cols) { 
    std::cout << std::endl; 
    for(size_t row = 0; row < rows; ++row) 
    { 
     for(size_t col = 0; col < cols; ++col) 
     { 
      // Lapack uses column major format 
      size_t idx = col*rows + row; 
      std::cout << A[idx] << " "; 
     } 
     std::cout << std::endl; 
    } 
} 

static int SolveQR(
    const bmatrix &in_A, // IN 
    const bvector &in_b, // IN 
    bvector &out_x // OUT 
) { 


    size_t rows = in_A.size1(); 
    size_t cols = in_A.size2(); 

    double *A = new double[rows*cols]; 
    double *b = new double[in_b.size()]; 

    //Lapack has column-major order 
    for(size_t col=0, D1_idx=0; col<cols; ++col) 
    { 
     for(size_t row = 0; row<rows; ++row) 
     { 
      // Lapack uses column major format 
      A[D1_idx++] = in_A(row, col); 
     } 
     b[col] = in_b(col); 
    } 

    for(size_t row = 0; row<rows; ++row) 
    { 
     b[row] = in_b(row); 
    } 

    // DGEQRF for Q*R=A, i.e., A and tau hold R and Householder reflectors 


    double* tau = new double[cols]; 

    PrintMatrix(A, rows, cols); 

    lapack::geqrf(rows, cols, A, rows, tau); 

    PrintMatrix(A, rows, cols); 

    // DORMQR: to compute b := Q^T*b 

    lapack::ormqr('L', 'T', rows, 1, cols, A, rows, tau, b, rows); 


    PrintMatrix(b, rows, 1); 

    // DTRTRS: solve Rx=b by back substitution 

    lapack::trtrs('U', 'N', 'N', cols, 1, A, rows, b, rows); 

    for(size_t col=0; col<cols; col++) { 
     out_x(col)=b[col]; 
    } 

    PrintMatrix(b,cols,1); 

    delete[] A; 
    delete[] b; 
    delete[] tau; 

    return 0; 
} 


int main() { 
    bmatrix in_A(4, 3); 
    in_A(0, 0) = 1.0; in_A(0, 1) = 2.0; in_A(0, 2) = 3.0; 
    in_A(1, 0) = -3.0; in_A(1, 1) = 2.0; in_A(1, 2) = 1.0; 
    in_A(2, 0) = 2.0; in_A(2, 1) = 0.0; in_A(2, 2) = -1.0; 
    in_A(3, 0) = 3.0; in_A(3, 1) = -1.0; in_A(3, 2) = 2.0; 

    bvector in_b(4); 
    in_b(0) = 2; 
    in_b(1) = 4; 
    in_b(2) = 6; 
    in_b(3) = 8; 

    bvector out_x(3); 

    SolveQR(in_A, in_b, out_x); 

    return 0; 
} 
+0

謝謝,我修改了TRANS並將vec更改爲這個 vec =(double *)malloc(m * n * sizeof(double)); 爲(爲size_t行= 0;行 bogus

+0

您是否也調整了控制A和C = vec的內存大小和佈局以及實際計算範圍的整數參數?有ldA,ldC,鉛的尺寸,M和N給出C的大小,M和K給出A的大小.Q因子C應該是一個方形矩陣。 – LutzL

+0

在我的代碼k等於n(A列的列數)中,C與A的大小相同。我更新了我的代碼:http://codepad.org/pfve8cmU – bogus

相關問題