linear_solver_csparse.h
Go to the documentation of this file.
00001 // g2o - General Graph Optimization
00002 // Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
00003 // 
00004 // g2o is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser General Public License as published
00006 // by the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 // 
00009 // g2o is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 // 
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef LINEAR_SOLVERCSPARSE_H
00018 #define LINEAR_SOLVERCSPARSE_H
00019 
00020 #include "csparse_helper.h"
00021 
00022 #include "g2o/core/linear_solver.h"
00023 #include "g2o/core/batch_stats.h"
00024 #include "g2o/core/marginal_covariance_cholesky.h"
00025 #include "g2o/stuff/timeutil.h"
00026 
00027 #include <iostream>
00028 
00029 namespace g2o {
00030 
00034 struct CSparseExt : public cs
00035 {
00036   CSparseExt()
00037   {
00038     nzmax = 0;
00039     m = 0;
00040     n = 0;
00041     p = 0;
00042     i = 0;
00043     x = 0;
00044     nz = 0;
00045     columnsAllocated = 0;
00046   }
00047   ~CSparseExt()
00048   {
00049     delete[] p;
00050     delete[] i;
00051     delete[] x;
00052   }
00053   int columnsAllocated;
00054 };
00055 
00059 template <typename MatrixType>
00060 class LinearSolverCSparse : public LinearSolver<MatrixType>
00061 {
00062   public:
00063     LinearSolverCSparse() :
00064       LinearSolver<MatrixType>()
00065     {
00066       _symbolicDecomposition = 0;
00067       _csWorkspaceSize = -1;
00068       _csWorkspace = 0;
00069       _csIntWorkspace = 0;
00070       _ccsA = new CSparseExt;
00071       _blockOrdering = true;
00072     }
00073 
00074     virtual ~LinearSolverCSparse()
00075     {
00076       if (_symbolicDecomposition) {
00077         cs_sfree(_symbolicDecomposition);
00078         _symbolicDecomposition = 0;
00079       }
00080       delete[] _csWorkspace; _csWorkspace = 0;
00081       delete[] _csIntWorkspace; _csIntWorkspace = 0;
00082       delete _ccsA;
00083     }
00084 
00085     virtual bool init()
00086     {
00087       if (_symbolicDecomposition) {
00088         cs_sfree(_symbolicDecomposition);
00089         _symbolicDecomposition = 0;
00090       }
00091       return true;
00092     }
00093 
00094     bool solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b)
00095     {
00096       fillCSparse(A, _symbolicDecomposition);
00097       // perform symbolic cholesky once
00098       if (_symbolicDecomposition == 0) {
00099         computeSymbolicDecomposition(A);
00100       }
00101       // re-allocate the temporary workspace for cholesky
00102       if (_csWorkspaceSize < _ccsA->n) {
00103         _csWorkspaceSize = 2 * _ccsA->n;
00104         delete[] _csWorkspace;
00105         _csWorkspace = new double[_csWorkspaceSize];
00106         delete[] _csIntWorkspace;
00107         _csIntWorkspace = new int[2*_csWorkspaceSize];
00108       }
00109 
00110       double t=get_time();
00111       // _x = _b for calling csparse
00112       if (x != b)
00113         memcpy(x, b, _ccsA->n * sizeof(double));
00114       int ok = cs_cholsolsymb(_ccsA, x, _symbolicDecomposition, _csWorkspace, _csIntWorkspace);
00115       if (! ok) {
00116         std::cerr << "Cholesky failure, writing debug.txt (Hessian loadable by Octave)" << std::endl;
00117         writeCs2Octave("debug.txt", _ccsA, true);
00118         return false;
00119       }
00120 
00121       if (globalStats){
00122         globalStats->timeNumericDecomposition = get_time() - t;
00123         globalStats->choleskyNNZ = _symbolicDecomposition->lnz;
00124       }
00125 
00126       return ok;
00127     }
00128 
00129     bool solveBlocks(double**& blocks, const SparseBlockMatrix<MatrixType>& A) {
00130       fillCSparse(A, _symbolicDecomposition);
00131       // perform symbolic cholesky once
00132       if (_symbolicDecomposition == 0) {
00133         computeSymbolicDecomposition(A);
00134         assert(_symbolicDecomposition && "Symbolic cholesky failed");
00135       }
00136       // re-allocate the temporary workspace for cholesky
00137       if (_csWorkspaceSize < _ccsA->n) {
00138         _csWorkspaceSize = 2 * _ccsA->n;
00139         delete[] _csWorkspace;
00140         _csWorkspace = new double[_csWorkspaceSize];
00141         delete[] _csIntWorkspace;
00142         _csIntWorkspace = new int[2*_csWorkspaceSize];
00143       }
00144 
00145       if (! blocks){
00146         blocks=new double*[A.rows()];
00147         double **block=blocks;
00148         for (size_t i=0; i < A.rowBlockIndices().size(); ++i){
00149           int dim = A.rowsOfBlock(i) * A.colsOfBlock(i);
00150           *block = new double [dim];
00151           block++;
00152         }
00153       }
00154 
00155       int ok = 1;
00156       csn* numericCholesky = cs_chol_workspace(_ccsA, _symbolicDecomposition, _csIntWorkspace, _csWorkspace);
00157       if (numericCholesky) {
00158         MarginalCovarianceCholesky mcc;
00159         mcc.setCholeskyFactor(_ccsA->n, numericCholesky->L->p, numericCholesky->L->i, numericCholesky->L->x, _symbolicDecomposition->pinv);
00160         mcc.computeCovariance(blocks, A.rowBlockIndices());
00161         cs_nfree(numericCholesky);
00162       } else {
00163         ok = 0;
00164         std::cerr << "inverse fail (numeric decomposition)" << std::endl;
00165       }
00166 
00167       if (globalStats){
00168         globalStats->choleskyNNZ = _symbolicDecomposition->lnz;
00169       }
00170 
00171       return ok;
00172     }
00173 
00174     virtual bool solvePattern(SparseBlockMatrix<MatrixXd>& spinv, const std::vector<std::pair<int, int> >& blockIndices, const SparseBlockMatrix<MatrixType>& A) {
00175       fillCSparse(A, _symbolicDecomposition);
00176       // perform symbolic cholesky once
00177       if (_symbolicDecomposition == 0) {
00178         computeSymbolicDecomposition(A);
00179         assert(_symbolicDecomposition && "Symbolic cholesky failed");
00180       }
00181       // re-allocate the temporary workspace for cholesky
00182       if (_csWorkspaceSize < _ccsA->n) {
00183         _csWorkspaceSize = 2 * _ccsA->n;
00184         delete[] _csWorkspace;
00185         _csWorkspace = new double[_csWorkspaceSize];
00186         delete[] _csIntWorkspace;
00187         _csIntWorkspace = new int[2*_csWorkspaceSize];
00188       }
00189 
00190 
00191       int ok = 1;
00192       csn* numericCholesky = cs_chol_workspace(_ccsA, _symbolicDecomposition, _csIntWorkspace, _csWorkspace);
00193       if (numericCholesky) {
00194         MarginalCovarianceCholesky mcc;
00195         mcc.setCholeskyFactor(_ccsA->n, numericCholesky->L->p, numericCholesky->L->i, numericCholesky->L->x, _symbolicDecomposition->pinv);
00196         mcc.computeCovariance(spinv, A.rowBlockIndices(), blockIndices);
00197         cs_nfree(numericCholesky);
00198       } else {
00199         ok = 0;
00200         std::cerr << "inverse fail (numeric decomposition)" << std::endl;
00201       }
00202 
00203       if (globalStats){
00204         globalStats->choleskyNNZ = _symbolicDecomposition->lnz;
00205       }
00206 
00207       return ok;
00208     }
00209 
00211     bool blockOrdering() const { return _blockOrdering;}
00212     void setBlockOrdering(bool blockOrdering) { _blockOrdering = blockOrdering;}
00213 
00214   protected:
00215     css* _symbolicDecomposition;
00216     int _csWorkspaceSize;
00217     double* _csWorkspace;
00218     int* _csIntWorkspace;
00219     CSparseExt* _ccsA;
00220     bool _blockOrdering;
00221     MatrixStructure _matrixStructure;
00222     VectorXi _scalarPermutation;
00223 
00224     void computeSymbolicDecomposition(const SparseBlockMatrix<MatrixType>& A)
00225     {
00226       double t=get_time();
00227       if (! _blockOrdering) {
00228         _symbolicDecomposition = cs_schol (1, _ccsA) ;
00229       } else {
00230         A.fillBlockStructure(_matrixStructure);
00231 
00232         // prepare block structure for the CSparse call
00233         cs auxBlock;
00234         auxBlock.nzmax = _matrixStructure.nzMax();
00235         auxBlock.m = auxBlock.n = _matrixStructure.n;
00236         auxBlock.p = _matrixStructure.Ap;
00237         auxBlock.i = _matrixStructure.Aii;
00238         auxBlock.x = NULL; // no values
00239         auxBlock.nz = -1; // CCS format
00240 
00241         // AMD ordering on the block structure
00242         const int& n = _ccsA->n;
00243         int* P = cs_amd(1, &auxBlock);
00244 
00245         // blow up the permutation to the scalar matrix
00246         if (_scalarPermutation.size() == 0)
00247           _scalarPermutation.resize(n);
00248         if (_scalarPermutation.size() < n)
00249           _scalarPermutation.resize(2*n);
00250         size_t scalarIdx = 0;
00251         for (int i = 0; i < _matrixStructure.n; ++i) {
00252           const int& p = P[i];
00253           int base  = A.colBaseOfBlock(p);
00254           int nCols = A.colsOfBlock(p);
00255           for (int j = 0; j < nCols; ++j)
00256             _scalarPermutation(scalarIdx++) = base++;
00257         }
00258         assert((int)scalarIdx == n);
00259         cs_free(P);
00260 
00261         // apply the scalar permutation to finish symbolic decomposition
00262         _symbolicDecomposition = (css*) cs_calloc(1, sizeof(css));       /* allocate result S */
00263         _symbolicDecomposition->pinv = cs_pinv(_scalarPermutation.data(), n);
00264         cs* C = cs_symperm(_ccsA, _symbolicDecomposition->pinv, 0);
00265         _symbolicDecomposition->parent = cs_etree(C, 0);
00266         int* post = cs_post(_symbolicDecomposition->parent, n);
00267         int* c = cs_counts(C, _symbolicDecomposition->parent, post, 0);
00268         cs_free(post);
00269         cs_spfree(C);
00270         _symbolicDecomposition->cp = (int*) cs_malloc(n+1, sizeof(int));
00271         _symbolicDecomposition->unz = _symbolicDecomposition->lnz = cs_cumsum(_symbolicDecomposition->cp, c, n);
00272         cs_free(c);
00273         if (_symbolicDecomposition->lnz < 0) {
00274           cs_sfree(_symbolicDecomposition);
00275           _symbolicDecomposition = 0;
00276         }
00277 
00278       }
00279       if (globalStats){
00280         globalStats->timeSymbolicDecomposition = get_time() - t;
00281       }
00282 
00283       /* std::cerr << "# Number of nonzeros in L: " << (int)_symbolicDecomposition->lnz << " by " */
00284       /*   << (_blockOrdering ? "block" : "scalar") << " AMD ordering " << std::endl; */
00285     }
00286 
00287     void fillCSparse(const SparseBlockMatrix<MatrixType>& A, bool onlyValues)
00288     {
00289       int m = A.rows();
00290       int n = A.cols();
00291 
00292       if (_ccsA->columnsAllocated < n) {
00293         _ccsA->columnsAllocated = _ccsA->columnsAllocated == 0 ? n : 2 * n; // pre-allocate more space if re-allocating
00294         delete[] _ccsA->p;
00295         _ccsA->p = new int[_ccsA->columnsAllocated+1];
00296       }
00297 
00298       if (! onlyValues) {
00299         int nzmax = A.nonZeros();
00300         if (_ccsA->nzmax < nzmax) {
00301           _ccsA->nzmax = _ccsA->nzmax == 0 ? nzmax : 2 * nzmax; // pre-allocate more space if re-allocating
00302           delete[] _ccsA->x;
00303           delete[] _ccsA->i;
00304           _ccsA->i = new int[_ccsA->nzmax];
00305           _ccsA->x = new double[_ccsA->nzmax];
00306         }
00307       }
00308       _ccsA->m = m;
00309       _ccsA->n = n;
00310 
00311       if (onlyValues) {
00312         A.fillCCS(_ccsA->x, true);
00313       } else {
00314         int nz = A.fillCCS(_ccsA->p, _ccsA->i, _ccsA->x, true); (void) nz;
00315         assert(nz <= _ccsA->nzmax);
00316       }
00317       _ccsA->nz=-1; // tag as CCS formatted matrix
00318     }
00319 };
00320 
00321 } // end namespace
00322 
00323 #endif


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:31:39