g2o
Loading...
Searching...
No Matches
linear_solver_cholmod.h
Go to the documentation of this file.
1// g2o - General Graph Optimization
2// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright notice,
10// this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#ifndef G2O_LINEAR_SOLVER_CHOLMOD
28#define G2O_LINEAR_SOLVER_CHOLMOD
29
30#include <cassert>
31
32#include "cholmod_wrapper.h"
36#include "g2o/stuff/logger.h"
38#include "g2o/stuff/timeutil.h"
39
40namespace g2o {
41
46template <typename MatrixType>
47class LinearSolverCholmod : public LinearSolverCCS<MatrixType> {
48 public:
50
53 delete;
54
56
57 virtual bool init() {
59 return true;
60 }
61
62 bool solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b) {
63 double t;
64 bool cholState = computeCholmodFactor(A, t);
65 if (!cholState) return false;
66
67 _cholmod.solve(x, b);
68
70 if (globalStats) {
72 globalStats->choleskyNNZ = _cholmod.choleskyNz();
73 }
74
75 return true;
76 }
77
78 virtual bool saveMatrix(const std::string& fileName) {
80 writeCCSMatrix(fileName, sparseView.nrow, sparseView.ncol, sparseView.p,
81 sparseView.i, sparseView.x, true);
82 return true;
83 }
84
85 protected:
86 // temp used for cholesky with cholmod
90
92 double t = get_monotonic_time();
93 if (!this->blockOrdering()) {
94 _cholmod.analyze();
95 } else {
97
98 // get the ordering for the block matrix
99 if (_blockPermutation.size() == 0)
101 if (_blockPermutation.size() <
102 _matrixStructure.n) // double space if resizing
104
105 // prepare AMD call via CHOLMOD
106 size_t structureDim = _matrixStructure.n;
107 size_t structureNz = _matrixStructure.nzMax();
108 size_t structureAllocated = structureDim;
109 double* structureX = nullptr;
111 structureDim, structureDim, structureNz, _matrixStructure.Ap,
112 _matrixStructure.Aii, structureX, structureAllocated);
113 bool amdStatus = _cholmod.amd(amdView, _blockPermutation.data());
114 if (!amdStatus) return;
115
116 // blow up the permutation to the scalar matrix
118
119 // apply the ordering
121 }
123 if (globalStats)
125 }
126
127 void fillCholmodExt(const SparseBlockMatrix<MatrixType>& A, bool onlyValues) {
128 if (!onlyValues) this->initMatrixStructure(A);
129 size_t m = A.rows();
130 size_t n = A.cols();
131 assert(m > 0 && n > 0 && "Hessian has 0 rows/cols");
132
134
135 if (cholmodSparse.columnsAllocated < n) {
136 // pre-allocate more space if re-allocating
137 cholmodSparse.columnsAllocated =
138 cholmodSparse.columnsAllocated == 0 ? n : 2 * n;
139 delete[] cholmodSparse.p;
140 cholmodSparse.p = new int[cholmodSparse.columnsAllocated + 1];
141 }
142 if (!onlyValues) {
143 size_t nzmax = A.nonZeros();
144 if (cholmodSparse.nzmax < nzmax) {
145 // pre-allocate more space if re-allocating
146 cholmodSparse.nzmax = cholmodSparse.nzmax == 0 ? nzmax : 2 * nzmax;
147 delete[] cholmodSparse.x;
148 delete[] cholmodSparse.i;
149 cholmodSparse.i = new int[cholmodSparse.nzmax];
150 cholmodSparse.x = new double[cholmodSparse.nzmax];
151 }
152 }
153 cholmodSparse.ncol = n;
154 cholmodSparse.nrow = m;
155
156 if (onlyValues)
157 this->_ccsMatrix->fillCCS((double*)cholmodSparse.x, true);
158 else
159 this->_ccsMatrix->fillCCS((int*)cholmodSparse.p, (int*)cholmodSparse.i,
160 (double*)cholmodSparse.x, true);
161 }
162
165 // _cholmodFactor used as bool, if not existing will copy the whole
166 // structure, otherwise only the values
167 bool hasFactor = _cholmod.hasFactor();
168 fillCholmodExt(A, hasFactor);
169
170 if (!hasFactor) {
172 assert(_cholmod.hasFactor() && "Symbolic cholesky failed");
173 }
174
175 t = get_monotonic_time();
176 bool factorStatus = _cholmod.factorize();
177 if (!factorStatus) {
178 if (this->writeDebug()) {
179 G2O_ERROR(
180 "Cholesky failure, writing debug.txt (Hessian loadable by Octave)");
181 saveMatrix("debug.txt");
182 } else {
183 G2O_DEBUG("Cholesky failure");
184 }
185 return false;
186 }
187 return true;
188 }
189
192 std::function<void(MarginalCovarianceCholesky&)> compute) {
193 double t;
194 bool cholState = computeCholmodFactor(A, t);
195 if (!cholState) return false;
196
197 // convert the factorization to LL, simplical, packed, monotonic
198 int change_status = _cholmod.simplifyFactor();
199 if (!change_status) return false;
200
203
204 // invert the permutation
205 int* p = cholmodFactor.perm;
206 VectorXI pinv(cholmodSparse.ncol);
207 for (size_t i = 0; i < cholmodSparse.ncol; ++i) pinv(p[i]) = i;
208
209 // compute the marginal covariance
211 mcc.setCholeskyFactor(cholmodSparse.ncol, cholmodFactor.p, cholmodFactor.i,
212 cholmodFactor.x, pinv.data());
213 compute(mcc);
214
216 if (globalStats) {
217 globalStats->choleskyNNZ = _cholmod.choleskyNz();
218 }
219 return true;
220 }
221
223};
224
225} // namespace g2o
226#endif
Solver with faster iterating structure for the linear matrix.
void initMatrixStructure(const SparseBlockMatrix< MatrixType > &A)
SparseBlockMatrixCCS< MatrixType > * _ccsMatrix
bool blockOrdering() const
do the AMD ordering on the blocks or on the scalar matrix
basic solver for Ax = b which has to reimplemented for different linear algebra libraries
LinearSolverCholmod(LinearSolverCholmod< MatrixType > const &)=delete
bool solveBlocks_impl(const SparseBlockMatrix< MatrixType > &A, std::function< void(MarginalCovarianceCholesky &)> compute)
void computeSymbolicDecomposition(const SparseBlockMatrix< MatrixType > &A)
void fillCholmodExt(const SparseBlockMatrix< MatrixType > &A, bool onlyValues)
bool solve(const SparseBlockMatrix< MatrixType > &A, double *x, double *b)
virtual bool saveMatrix(const std::string &fileName)
bool computeCholmodFactor(const SparseBlockMatrix< MatrixType > &A, double &t)
compute the cholmodFactor for the given matrix A
LinearSolverCholmod & operator=(LinearSolverCholmod< MatrixType > const &)=delete
bool writeDebug() const
write a debug dump of the system matrix if it is not PSD in solve
static void blockToScalarPermutation(const SparseBlockMatrix< MatrixType > &A, const Eigen::MatrixBase< BlockDerived > &p, const Eigen::MatrixBase< ScalarDerived > &scalar)
computing the marginal covariance given a cholesky factor (lower triangle of the factor)
void setCholeskyFactor(int n, int *Lp, int *Li, double *Lx, int *permInv)
representing the structure of a matrix in column compressed structure (only the upper triangular part...
int * Aii
row indices of A, of size nz = Ap [n]
int n
A is m-by-n. n must be >= 0.
int nzMax() const
max number of non-zeros blocks
int * Ap
column pointers for A, of size n+1
Sparse matrix which uses blocks.
size_t nonZeros() const
number of non-zero elements
int rows() const
rows of the matrix
int cols() const
columns of the matrix
void fillBlockStructure(MatrixStructure &ms) const
exports the non zero blocks in the structure matrix ms
bool amd(SparseView &sparseView, int *result)
compute AMD ordering on the given SparseView, store into result
bool analyze_p(int *permutation)
void solve(double *x, double *b) const
#define G2O_ERROR(...)
Definition logger.h:89
#define G2O_DEBUG(...)
Definition logger.h:90
bool writeCCSMatrix(const string &filename, int rows, int cols, const int *Ap, const int *Ai, const double *Ax, bool upperTriangleSymmetric)
Eigen::Matrix< int, Eigen::Dynamic, 1, Eigen::ColMajor > VectorXI
Definition eigen_types.h:41
double get_monotonic_time()
Definition timeutil.cpp:43
statistics about the optimization
Definition batch_stats.h:40
static G2OBatchStatistics * globalStats()
Definition batch_stats.h:77
double timeNumericDecomposition
numeric decomposition (0 if not done)
Definition batch_stats.h:58
double timeSymbolicDecomposition
symbolic decomposition (0 if not done)
Definition batch_stats.h:57
size_t choleskyNNZ
number of non-zeros in the cholesky factor
Definition batch_stats.h:75
View onto the cholesky factor.
View onto the sparse matrix structure of Cholmod using CCS storage.
utility functions for handling time related stuff