00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00098 if (_symbolicDecomposition == 0) {
00099 computeSymbolicDecomposition(A);
00100 }
00101
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
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
00132 if (_symbolicDecomposition == 0) {
00133 computeSymbolicDecomposition(A);
00134 assert(_symbolicDecomposition && "Symbolic cholesky failed");
00135 }
00136
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
00177 if (_symbolicDecomposition == 0) {
00178 computeSymbolicDecomposition(A);
00179 assert(_symbolicDecomposition && "Symbolic cholesky failed");
00180 }
00181
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
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;
00239 auxBlock.nz = -1;
00240
00241
00242 const int& n = _ccsA->n;
00243 int* P = cs_amd(1, &auxBlock);
00244
00245
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
00262 _symbolicDecomposition = (css*) cs_calloc(1, sizeof(css));
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
00284
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;
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;
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;
00318 }
00319 };
00320
00321 }
00322
00323 #endif