Solving a linear system with Lapack's dgeqrf_

后端 未结 2 1639
面向向阳花
面向向阳花 2020-12-15 02:00

I am trying to factorize a matrix with the QR factorization in C++, using Lapack\'s functions in order to solve a system of linear equations (Ax=b)

As far as I unde

2条回答
  •  伪装坚强ぢ
    2020-12-15 02:29

    According to the documentation in

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

    you are computing in vec the product Q^T*e3, where e3 is the third canonical basis vector (0,0,1,0,0,...,0). If you want to compute Q, then vec should contain a matrix sized array filled with the unit matrix, and TRANS should be "N".


    dormqr (SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, LWORK, INFO)
    
    • SIDE = "L" for the normal QR decomposition with Q left,

    • TRANS = "N" to return QC in the place of C

    • A has layout LDA x K in memory, of which the upper M x K block is used and encodes K reflectors

    • tau contains the factors for the K reflectors

    • C has layout LDC x M in memory, of which the upper M x N block will be used to hold the result QC

    • For C to hold Q on return, C must be a square M x M matrix initialized as identity, i.e., with diagonal entries all 1.


    You might consider to use the lapack numeric bindings provided for ublas, as in

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

    However, this project may be defunct or resting by now.


    Lets start again from first principles: The aim is to solve Ax=b, or at least to minimize |Ax-b|+|x|. For that to be consistent one needs colsA=rowsx and rowsA=rowsb.

    Now for the discussed code to work A has to be square or a tall rectangular matrix, colsA<=rowsA, so that the system is overdetermined.

    Computation steps

    • Solve Q*R=A: (http://www.netlib.no/netlib/lapack/double/dgeqrf.f)

      DGEQRF( rowsA, colsA, A, rowsA, TAU, WORK, LWORK, INFO )

    • Multiply by QT to get QT*b as in R*x=QT*b (http://www.netlib.no/netlib/lapack/double/dormqr.f)

      DORMQR( 'L', 'T', rowsA, 1, colsA, A, rowsA, TAU, b, rowsA, WORK, LWORK, INFO )

    • Use back-substitution using the upper right part of A (http://www.netlib.no/netlib/lapack/double/dtrtrs.f)

      DTRTRS( 'U', 'N', 'N', colsA, 1, A, rowsA, b, rowsA, INFO )

    • Now the first colsA entries of b contain the solution vector x. The euclidean norm of the remaining entries at index colsA+1 and thereafter is the error |A*x-b| of the solution.

    Remark: For the pure solution process there is no reason to compute 'Q' explicitly or to invoke the generic matrix multiplication DGEMM. These should be reserved for experiments to check if A-QR is sufficiently close to zero.

    Remark: Explore the optimal allocation of the WORK array by performing a dry run with LWORK=-1.


    To conclude some code that works, however, the connection between ublas and lapack seems suboptimal

    #include "boost/numeric/ublas/matrix.hpp"
    #include "boost/numeric/ublas/vector.hpp"
    
    typedef boost::numeric::ublas::matrix bmatrix;
    typedef boost::numeric::ublas::vector 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

提交回复
热议问题