diff --git a/CMakeLists.txt b/CMakeLists.txt index 56d5da37458fab855c559abc3b42092d4b8ba595..2424b023433994127582a23f8a4cefb17d65ccff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,6 @@ SET(libs task-dyn-joint-limits solver-op-space solver-dyn-reduced - solver-dyn-red2 solver-kine task-joint-limits @@ -85,12 +84,13 @@ SET(headers task-dyn-joint-limits.h solver-op-space.h solver-dyn-reduced.h - solver-dyn-red2.h task-joint-limits.h task-inequality.h solver-kine.h feature-projected-line.h + + col-piv-qr-solve-in-place.h ) # Add subdirectories. diff --git a/src/col-piv-qr-solve-in-place.h b/src/col-piv-qr-solve-in-place.h new file mode 100644 index 0000000000000000000000000000000000000000..38e411110765a8c1892a2c096855ae207f8fb398 --- /dev/null +++ b/src/col-piv-qr-solve-in-place.h @@ -0,0 +1,118 @@ +/* + * Copyright 2011, Nicolas Mansard, LAAS-CNRS + * + * This file is part of sot-dyninv. + * sot-dyninv is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * sot-dyninv is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with sot-dyninvc. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __sot_dyninv_ColPivQRSolveInPlace_H__ +#define __sot_dyninv_ColPivQRSolveInPlace_H__ + +#include <Eigen/QR> + +namespace Eigen +{ + + /* 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: + + /* 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 ) + { + 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() ); + } + + MatrixXd pseudoInverse( void ) + { + 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( Gtp.rows() == m ); // TODO: if not proper size, resize. + + /* G E = Q R :: E' G' = L Q', with L=R' + * => G^+T = Q R^+T E' */ + + /* Compute E'*X. */ + Gtp.applyOnTheLeft( colsPermutation().transpose() ); + + /* Compute R^+T E'*X. */ + matrixQR() + .topLeftCorner(r,r).transpose().triangularView<Lower>() + .solveInPlace(Gtp.topRows(r)); + + /* Compute Q R^+T E'*X. */ + /* Q = P1*P2* ... *Pn */ + VectorXd workspace( n ); + for (int k = r-1; k >= 0 ; --k) + { + int remainingSize = m-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; + } + + }; +} + + +#endif // #ifndef __sot_dyninv_ColPivQRSolveInPlace_H__ diff --git a/unitTesting/qrt.cpp b/unitTesting/qrt.cpp index 7792fec6b690390d0fd7e2beee599a5c6175c73e..30237ecc31ff79abe1f69e92fd7d43f7bb48e4ec 100644 --- a/unitTesting/qrt.cpp +++ b/unitTesting/qrt.cpp @@ -14,108 +14,15 @@ * with sot-dyninvc. If not, see <http://www.gnu.org/licenses/>. */ -#include <Eigen/QR> +#include <sot-dyninv/col-piv-qr-solve-in-place.h> #include <soth/Algebra.hpp> #include <iostream> std::ostream& p( const char * n ) { return std::cout << n << " = "; } -namespace Eigen -{ - - /* 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: - - /* 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 ) - { - 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() ); - } - - MatrixXd pseudoInverse( void ) - { - 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( Gtp.rows() == m ); // TODO: if not proper size, resize. - - /* G E = Q R :: E' G' = L Q', with L=R' - * => G^+T = Q R^+T E' */ - - /* Compute E'*X. */ - Gtp.applyOnTheLeft( colsPermutation().transpose() ); - - /* Compute R^+T E'*X. */ - matrixQR() - .topLeftCorner(r,r).transpose().triangularView<Lower>() - .solveInPlace(Gtp.topRows(r)); - - /* Compute Q R^+T E'*X. */ - /* Q = P1*P2* ... *Pn */ - VectorXd workspace( n ); - for (int k = r-1; k >= 0 ; --k) - { - int remainingSize = m-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; - } - - }; -} - int main (void) { using namespace Eigen;