【问题标题】:Solving a linear system with Lapack's dgeqrf_使用 Lapack 的 dgeqrf_ 求解线性系统
【发布时间】:2014-03-25 02:20:09
【问题描述】:

我正在尝试用 C++ 中的QR factorization 分解矩阵,使用 Lapack 的函数来求解线性方程组 (Ax=b)

据我了解,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);

我的代码有什么问题?

如何分解矩阵并求解相应的线性方程组?

【问题讨论】:

  • 请检查您的 in_A 结构。列索引是 (0,1,2) 还是 (1,2,3)?

标签: c++ math visual-studio-2012 linear-algebra lapack


【解决方案1】:

根据

中的文档

(http://www.netlib.org/lapack/explore-html/da/d82/dormqr_8f.html)

您在 vec 中计算乘积 Q^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 代替 C

  • A在内存中有布局LDA x K,其中上部的M x K块被使用并编码K个反射器

  • tau 包含 K 反射器的因子

  • C在内存中有布局LDC x M,上面的M x N块将用于保存结果QC

  • 要让 C 在返回时保持 Q,C 必须是一个初始化为单位的 M x M 方阵,即,对角线项全为 1。


您可以考虑使用为 ublas 提供的 lapack 数字绑定,如

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

但是,这个项目现在可能已经停止或停止。


让我们从第一原理重新开始: 目的是解决 Ax=b,或至少最小化 |Ax-b|+|x|。为了保持一致,需要colsA=rowsxrowsA=rowsb

现在讨论的代码A 必须是正方形或高矩形矩阵colsA&lt;=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;
}

【讨论】:

  • 谢谢,我改编了 TRANS 并将 vec 更改为这个 vec = (double ) malloc( m * n * sizeof( double ) ); for(size_t row = 0; row rows +排; vec[idx] = 1; } } } 不幸的是,结果没有改变!
  • 你是否也调整了控制A和C=vec的内存大小和布局以及实际计算范围的整数参数?有 ldA、ldC、引线尺寸,M 和 N 给出 C 的大小,M 和 K 给出 A 的大小。Q 因子 C 应该是方阵。
  • 在我的代码中 k 等于 n(A 的列数),C 的大小与 A 相同。我更新了代码:codepad.org/pfve8cmU
  • n 丢失变量one,你想要Q 的所有列,而不仅仅是第一列。矩阵A 没有改变,结果在vec 中计算,所以你最后的输出应该打印vec 的组件。 -- 一般性:C++ 不使用 malloc 和 free,而是使用 new 和 delete。你必须表明你没有使用std::vector,而是boost::...::vector。命名空间的别名可能会有所帮助。您可以编写 display_matrix 过程以避免代码重复。在定义它们之后使用行和列。
  • 我设法让它工作,我会将您的答案标记为解决方案并尽快发布摘要
【解决方案2】:

虽然这是一个老问题,但如果您正在寻找一种使用 QR 和 LAPACK 解决 LLS 的方法,请使用 dgels,它与上面的答案相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-03
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2019-01-15
    • 2012-03-31
    相关资源
    最近更新 更多