From 0f18eb836a66ee976d98e961b1954f4ced23f78d Mon Sep 17 00:00:00 2001 From: Mansard <nmansard@laas.fr> Date: Tue, 23 Aug 2011 11:00:50 +0200 Subject: [PATCH] First complete working version. --- unitTesting/qrt.cpp | 94 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/unitTesting/qrt.cpp b/unitTesting/qrt.cpp index 136864d..7792fec 100644 --- a/unitTesting/qrt.cpp +++ b/unitTesting/qrt.cpp @@ -23,36 +23,76 @@ std::ostream& p( const char * n ) { return std::cout << n << " = "; } namespace Eigen { - class FullRowRankColPivQR - : private ColPivHouseholderQR< MatrixXd > + + /* This class add two methods to the classical ColPiv: solveInPlace for full + * col rank matrices (and the direct consequence of pseudoInverse for + * f-c-r). And solveTranposeInPlace for full row rank matrices (and the + * direct pseudoInverseTranspose). + */ + class ColPivQRSolveInPlace + : public ColPivHouseholderQR< MatrixXd > { public: - void compute(const MatrixType& matrix) + /* Find a solution x to the problem G x = b. The input vector is b, + * completed by the 0 tail to obtain the x size. The solver only works for + * full-col rank matrices, ie matrices G = Q [ R; 0 ], with R full-rank + * (full diag) upper triangular. */ + void solveInPlace( MatrixXd& Gp ) { - assert( matrix.rows()<=matrix.cols() ); - ColPivHouseholderQR< MatrixXd >::compute( matrix.transpose() ); - assert( rank() == matrix.rows() ); + const int r = rank(), m=cols(), n=rows(); + assert( r==m ); + assert( Gp.rows() == m ); // TODO: if not proper size, resize. + + VectorXd workspace( n ); + /* P2*P1*P0 ... */ + for (int k = r-1; k >= 0 ; --k) + { + int remainingSize = n-k; + Gp.rightCols( Gp.cols()-k ) + .applyHouseholderOnTheRight(matrixQR().col(k).tail(remainingSize-1), + hCoeffs().coeff(k), &workspace.coeffRef(0)); + } + + matrixQR() + .topLeftCorner(r,r).triangularView<Upper>() + .solveInPlace(Gp); + + Gp.applyOnTheLeft( colsPermutation() ); } - void solveInPlace( MatrixXd& Gp ) + MatrixXd pseudoInverse( void ) { - /* r is the rank, nxm the size of the original matrix (ie whose transpose has - * been decomposed. */ + MatrixXd res = MatrixXd::Identity( cols(),rows() ); + solveInPlace( res ); + return res; + } + + + + /* Find a solution x to the problem G'x = b. The input vector is b, + * completed by the 0 tail to obtain the x size. The solver only works for + * full-row rank matrices, ie matrices G' = [ L 0 ] Q, with L full-rank + * (full diag) lower triangular. */ + void solveTransposeInPlace( MatrixXd& Gtp ) + { + /* r is the rank, nxm the size of the original matrix (ie whose transpose + * has been decomposed. n is the number of cols of the original matrix, + * thus number of rows of the transpose we want to inverse. */ const int r = rank(), n=cols(), m=rows(); assert( r==n ); - assert( Gp.rows() == m ); + assert( Gtp.rows() == m ); // TODO: if not proper size, resize. - /* G'E = Q R - * => G^+ = Q R^+T E' */ + /* G E = Q R :: E' G' = L Q', with L=R' + * => G^+T = Q R^+T E' */ /* Compute E'*X. */ - Gp.applyOnTheLeft( colsPermutation().transpose() ); + Gtp.applyOnTheLeft( colsPermutation().transpose() ); /* Compute R^+T E'*X. */ matrixQR() .topLeftCorner(r,r).transpose().triangularView<Lower>() - .solveInPlace(Gp.topRows(r)); + .solveInPlace(Gtp.topRows(r)); /* Compute Q R^+T E'*X. */ /* Q = P1*P2* ... *Pn */ @@ -60,11 +100,19 @@ namespace Eigen for (int k = r-1; k >= 0 ; --k) { int remainingSize = m-k; - Gp.bottomRows( Gp.rows()-k ) + Gtp.bottomRows( Gtp.rows()-k ) .applyHouseholderOnTheLeft(matrixQR().col(k).tail(remainingSize-1), hCoeffs().coeff(k), &workspace.coeffRef(0)); } } + + MatrixXd pseudoInverseTranspose( void ) + { + MatrixXd Gtp = MatrixXd::Identity( rows(),cols() ); + solveTransposeInPlace( Gtp ); + return Gtp; + } + }; } @@ -75,7 +123,7 @@ int main (void) { /* Compute the pseudo inverse of a full-col rank matrix: G = V [ R; 0 ]. */ - const unsigned int n=6, m=3, r=3; + const unsigned int n=12, m=9, r=9; MatrixXd G = MatrixXd::Random(n,m); p("G") << (MATLAB)G << endl; @@ -134,10 +182,17 @@ int main (void) Gp.applyOnTheLeft( G_qr.colsPermutation() ); p("Gp") << (MATLAB)Gp << endl; } + + { + ColPivQRSolveInPlace G_qr; G_qr.compute(G); + p("Gp") << (MATLAB)G_qr.pseudoInverse() << endl; + } + + } { /* Compute the pseudo inverse of a full-row rank matrix: G = [ L; 0 ] V'. */ - const unsigned int n=3, m=6, r=3; + const unsigned int n=9, m=12, r=9; MatrixXd G = MatrixXd::Random(n,m); p("G") << (MATLAB)G << endl; @@ -174,10 +229,11 @@ int main (void) } { - FullRowRankColPivQR G_lq; G_lq.compute(G); + ColPivQRSolveInPlace Gt_qr; Gt_qr.compute(G.transpose()); MatrixXd Gp = MatrixXd::Identity( m,r ); - G_lq.solveInPlace(Gp); + Gt_qr.solveTransposeInPlace(Gp); p("Gp") << (MATLAB)Gp << endl; + p("Gp") << (MATLAB)Gt_qr.pseudoInverseTranspose() << endl; } } -- GitLab