00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef LINEAR_SOLVER_CHOLMOD
00018 #define LINEAR_SOLVER_CHOLMOD
00019
00020 #include "g2o/core/linear_solver.h"
00021 #include "g2o/core/marginal_covariance_cholesky.h"
00022 #include "g2o/core/batch_stats.h"
00023 #include "g2o/stuff/timeutil.h"
00024 #include "g2o/stuff/sparse_helper.h"
00025
00026 #include <cholmod.h>
00027
00028 namespace g2o {
00029
00033 struct CholmodExt : public cholmod_sparse
00034 {
00035 CholmodExt()
00036 {
00037 nzmax = 0;
00038 nrow = 0;
00039 ncol = 0;
00040 p = 0;
00041 i = 0;
00042 nz = 0;
00043 x = 0;
00044 z = 0;
00045 stype = 1;
00046 itype = CHOLMOD_INT;
00047 xtype = CHOLMOD_REAL;
00048 dtype = CHOLMOD_DOUBLE;
00049 sorted = 1;
00050 packed = 1;
00051 columnsAllocated = 0;
00052 }
00053 ~CholmodExt()
00054 {
00055 delete[] (int*)p; p = 0;
00056 delete[] (double*)x; x = 0;
00057 delete[] (int*)i; i = 0;
00058 }
00059 size_t columnsAllocated;
00060 };
00061
00062
00067 template <typename MatrixType>
00068 class LinearSolverCholmod : public LinearSolver<MatrixType>
00069 {
00070 public:
00071 LinearSolverCholmod() :
00072 LinearSolver<MatrixType>()
00073 {
00074 _blockOrdering = false;
00075 _cholmodSparse = new CholmodExt();
00076 _cholmodFactor = 0;
00077 cholmod_start(&_cholmodCommon);
00078
00079
00080 _cholmodCommon.nmethods = 1 ;
00081 _cholmodCommon.method[0].ordering = CHOLMOD_AMD;
00082
00083
00084 _cholmodCommon.supernodal = CHOLMOD_AUTO;
00085
00086 }
00087
00088
00089
00090 virtual ~LinearSolverCholmod()
00091 {
00092 delete _cholmodSparse;
00093 if (_cholmodFactor)
00094 {
00095 cholmod_free_factor(&_cholmodFactor, &_cholmodCommon);
00096 _cholmodFactor = 0;
00097 }
00098 cholmod_finish(&_cholmodCommon);
00099 }
00100
00101
00102
00103 virtual bool init()
00104 {
00105 if (_cholmodFactor)
00106 {
00107 cholmod_free_factor(&_cholmodFactor, &_cholmodCommon);
00108 _cholmodFactor = 0;
00109 }
00110 return true;
00111 }
00112
00113
00114
00115 bool solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b)
00116 {
00117
00118
00119
00120
00121 fillCholmodExt(A, _cholmodFactor);
00122
00123 if (! _cholmodFactor) {
00124 computeSymbolicDecomposition(A);
00125 assert(_cholmodFactor && "Symbolic cholesky failed");
00126 }
00127 double t=get_time();
00128
00129
00130 cholmod_dense bcholmod;
00131 bcholmod.nrow = bcholmod.d = _cholmodSparse->nrow;
00132 bcholmod.ncol = 1;
00133 bcholmod.x = b;
00134 bcholmod.xtype = CHOLMOD_REAL;
00135 bcholmod.dtype = CHOLMOD_DOUBLE;
00136
00137 cholmod_factorize(_cholmodSparse, _cholmodFactor, &_cholmodCommon);
00138 if (_cholmodCommon.status == CHOLMOD_NOT_POSDEF) {
00139 std::cerr << "Cholesky failure, writing debug.txt "
00140 "(Hessian loadable by Octave)" << std::endl;
00141 writeCCSMatrix
00142 (
00143 "debug.txt", _cholmodSparse->nrow, _cholmodSparse->ncol,
00144 (int*)_cholmodSparse->p, (int*)_cholmodSparse->i,
00145 (double*)_cholmodSparse->x, true
00146 );
00147 return false;
00148 }
00149
00150 cholmod_dense* xcholmod =
00151 cholmod_solve(CHOLMOD_A, _cholmodFactor, &bcholmod, &_cholmodCommon);
00152
00153
00154 memcpy(x, xcholmod->x, sizeof(double) * bcholmod.nrow);
00155 cholmod_free_dense(&xcholmod, &_cholmodCommon);
00156
00157 if (globalStats)
00158 {
00159 globalStats->timeNumericDecomposition = get_time() - t;
00160 globalStats->choleskyNNZ = _cholmodCommon.method[0].lnz;
00161 }
00162
00163 return true;
00164 }
00165
00166
00167
00168 bool solveBlocks(double**& blocks, const SparseBlockMatrix<MatrixType>& A)
00169 {
00170
00171
00172
00173
00174 fillCholmodExt(A, _cholmodFactor);
00175
00176 if (! _cholmodFactor)
00177 {
00178 computeSymbolicDecomposition(A);
00179 assert(_cholmodFactor && "Symbolic cholesky failed");
00180 }
00181
00182 if (! blocks)
00183 {
00184 blocks = new double*[A.rows()];
00185 double **block = blocks;
00186 for (size_t i = 0; i < A.rowBlockIndices().size(); ++i)
00187 {
00188 int dim = A.rowsOfBlock(i)*A.colsOfBlock(i);
00189 *block = new double [dim];
00190 block++;
00191 }
00192 }
00193
00194 cholmod_factorize(_cholmodSparse, _cholmodFactor, &_cholmodCommon);
00195 if (_cholmodCommon.status == CHOLMOD_NOT_POSDEF) return false;
00196
00197
00198 int change_status =
00199 cholmod_change_factor
00200 (CHOLMOD_REAL, 1, 0, 1, 1, _cholmodFactor, &_cholmodCommon);
00201
00202 if (! change_status) return false;
00203
00204 assert( _cholmodFactor->is_ll && !_cholmodFactor->is_super
00205 && _cholmodFactor->is_monotonic
00206 && "Cholesky factor has wrong format");
00207
00208
00209 int* p = (int*)_cholmodFactor->Perm;
00210 VectorXi pinv; pinv.resize(_cholmodSparse->ncol);
00211
00212 for (size_t i = 0; i < _cholmodSparse->ncol; ++i) pinv(p[i]) = i;
00213
00214
00215 MarginalCovarianceCholesky mcc;
00216 mcc.setCholeskyFactor
00217 (
00218 _cholmodSparse->ncol, (int*)_cholmodFactor->p,
00219 (int*)_cholmodFactor->i, (double*)_cholmodFactor->x, pinv.data()
00220 );
00221 mcc.computeCovariance(blocks, A.rowBlockIndices());
00222
00223 if (globalStats) {
00224 globalStats->choleskyNNZ =
00225 _cholmodCommon.method[_cholmodCommon.selected].lnz;
00226 }
00227
00228 return true;
00229 }
00230
00231
00232
00233 virtual bool solvePattern
00234 (
00235 SparseBlockMatrix<MatrixXd>& spinv,
00236 const std::vector<std::pair<int, int> >& blockIndices,
00237 const SparseBlockMatrix<MatrixType>& A
00238 )
00239 {
00240
00241
00242
00243
00244 fillCholmodExt(A, _cholmodFactor);
00245
00246 if (! _cholmodFactor)
00247 {
00248 computeSymbolicDecomposition(A);
00249 assert(_cholmodFactor && "Symbolic cholesky failed");
00250 }
00251
00252 cholmod_factorize(_cholmodSparse, _cholmodFactor, &_cholmodCommon);
00253 if (_cholmodCommon.status == CHOLMOD_NOT_POSDEF) return false;
00254
00255
00256 int change_status =
00257 cholmod_change_factor
00258 (CHOLMOD_REAL, 1, 0, 1, 1, _cholmodFactor, &_cholmodCommon);
00259
00260 if (! change_status) return false;
00261
00262 assert( _cholmodFactor->is_ll && !_cholmodFactor->is_super
00263 && _cholmodFactor->is_monotonic
00264 && "Cholesky factor has wrong format");
00265
00266
00267 int* p = (int*)_cholmodFactor->Perm;
00268 VectorXi pinv; pinv.resize(_cholmodSparse->ncol);
00269 for (size_t i = 0; i < _cholmodSparse->ncol; ++i) pinv(p[i]) = i;
00270
00271
00272 MarginalCovarianceCholesky mcc;
00273 mcc.setCholeskyFactor
00274 (
00275 _cholmodSparse->ncol, (int*)_cholmodFactor->p, (int*)_cholmodFactor->i,
00276 (double*)_cholmodFactor->x, pinv.data()
00277 );
00278
00279 mcc.computeCovariance(spinv, A.rowBlockIndices(), blockIndices);
00280
00281 if (globalStats) {
00282 globalStats->choleskyNNZ =
00283 _cholmodCommon.method[_cholmodCommon.selected].lnz;
00284 }
00285
00286 return true;
00287 }
00288
00289
00290
00292 bool blockOrdering() const { return _blockOrdering;}
00293 void setBlockOrdering(bool blockOrdering) { _blockOrdering = blockOrdering;}
00294
00295 protected:
00296
00297 cholmod_common _cholmodCommon;
00298 CholmodExt* _cholmodSparse;
00299 cholmod_factor* _cholmodFactor;
00300 bool _blockOrdering;
00301 MatrixStructure _matrixStructure;
00302 VectorXi _scalarPermutation, _blockPermutation;
00303
00304
00305
00306 void computeSymbolicDecomposition(const SparseBlockMatrix<MatrixType>& A)
00307 {
00308 double t = get_time();
00309 if (! _blockOrdering) {
00310
00311 _cholmodCommon.nmethods = 1;
00312 _cholmodCommon.method[0].ordering = CHOLMOD_AMD;
00313
00314
00315 _cholmodFactor = cholmod_analyze(_cholmodSparse, &_cholmodCommon);
00316 }else
00317 {
00318
00319 A.fillBlockStructure(_matrixStructure);
00320
00321
00322 if (_blockPermutation.size() == 0)
00323 _blockPermutation.resize(_matrixStructure.n);
00324
00325
00326 if (_blockPermutation.size() < _matrixStructure.n)
00327 _blockPermutation.resize(2*_matrixStructure.n);
00328
00329
00330 cholmod_sparse auxCholmodSparse;
00331 auxCholmodSparse.nzmax = _matrixStructure.nzMax();
00332 auxCholmodSparse.nrow = auxCholmodSparse.ncol = _matrixStructure.n;
00333 auxCholmodSparse.p = _matrixStructure.Ap;
00334 auxCholmodSparse.i = _matrixStructure.Aii;
00335 auxCholmodSparse.nz = 0;
00336 auxCholmodSparse.x = 0;
00337 auxCholmodSparse.z = 0;
00338 auxCholmodSparse.stype = 1;
00339 auxCholmodSparse.xtype = CHOLMOD_PATTERN;
00340 auxCholmodSparse.itype = CHOLMOD_INT;
00341 auxCholmodSparse.dtype = CHOLMOD_DOUBLE;
00342 auxCholmodSparse.sorted = 1;
00343 auxCholmodSparse.packed = 1;
00344 int amdStatus =
00345 cholmod_amd
00346 (
00347 &auxCholmodSparse, NULL, 0, _blockPermutation.data(),
00348 &_cholmodCommon
00349 );
00350
00351 if (! amdStatus) return;
00352
00353
00354 if (_scalarPermutation.size() == 0)
00355 _scalarPermutation.resize(_cholmodSparse->ncol);
00356
00357 if (_scalarPermutation.size() < (int)_cholmodSparse->ncol)
00358 _scalarPermutation.resize(2*_cholmodSparse->ncol);
00359
00360 size_t scalarIdx = 0;
00361 for (int i = 0; i < _matrixStructure.n; ++i)
00362 {
00363 const int& p = _blockPermutation(i);
00364 int base = A.colBaseOfBlock(p);
00365 int nCols = A.colsOfBlock(p);
00366 for (int j = 0; j < nCols; ++j)
00367 _scalarPermutation(scalarIdx++) = base++;
00368 }
00369 assert(scalarIdx == _cholmodSparse->ncol);
00370
00371
00372 _cholmodCommon.nmethods = 1 ;
00373 _cholmodCommon.method[0].ordering = CHOLMOD_GIVEN;
00374 _cholmodFactor =
00375 cholmod_analyze_p
00376 (
00377 _cholmodSparse, _scalarPermutation.data(), NULL,
00378 0, &_cholmodCommon
00379 );
00380 }
00381 if (globalStats) globalStats->timeSymbolicDecomposition = get_time() - t;
00382 }
00383
00384
00385
00386 void fillCholmodExt(const SparseBlockMatrix<MatrixType>& A, bool onlyValues)
00387 {
00388 size_t m = A.rows();
00389 size_t n = A.cols();
00390
00391 if (_cholmodSparse->columnsAllocated < n)
00392 {
00393
00394
00395
00396
00397 _cholmodSparse->columnsAllocated =
00398 _cholmodSparse->columnsAllocated == 0 ? n : 2 * n;
00399 delete[] (int*)_cholmodSparse->p;
00400 _cholmodSparse->p = new int[_cholmodSparse->columnsAllocated+1];
00401 }
00402
00403 if (! onlyValues)
00404 {
00405 size_t nzmax = A.nonZeros();
00406 if (_cholmodSparse->nzmax < nzmax)
00407 {
00408
00409
00410
00411
00412 _cholmodSparse->nzmax =
00413 _cholmodSparse->nzmax == 0 ? nzmax : 2 * nzmax;
00414
00415 delete[] (double*)_cholmodSparse->x;
00416 delete[] (int*)_cholmodSparse->i;
00417 _cholmodSparse->i = new int[_cholmodSparse->nzmax];
00418 _cholmodSparse->x = new double[_cholmodSparse->nzmax];
00419 }
00420 }
00421 _cholmodSparse->ncol = n;
00422 _cholmodSparse->nrow = m;
00423
00424 if (onlyValues)
00425 A.fillCCS((double*)_cholmodSparse->x, true);
00426 else
00427 A.fillCCS
00428 (
00429 (int*)_cholmodSparse->p, (int*)_cholmodSparse->i,
00430 (double*)_cholmodSparse->x, true
00431 );
00432 }
00433
00434 };
00435
00436 }
00437
00438 #endif