g2o
Loading...
Searching...
No Matches
linear_solver_csparse.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_SOLVERCSPARSE_H
28#define G2O_LINEAR_SOLVERCSPARSE_H
29
30#include <cassert>
31#include <iostream>
32
33#include "csparse_wrapper.h"
37#include "g2o/stuff/logger.h"
38#include "g2o/stuff/timeutil.h"
39#include "g2o_csparse_api.h"
40
41namespace g2o {
42
46template <typename MatrixType>
47class LinearSolverCSparse : public LinearSolverCCS<MatrixType> {
48 public:
50
53 delete;
54
55 virtual ~LinearSolverCSparse() = default;
56
57 virtual bool init() {
59 return true;
60 }
61
62 bool solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b) {
63 prepareSolve(A);
64
65 double t = get_monotonic_time();
66 bool ok = csparse.solve(x, b);
67 if (!ok && this->writeDebug()) {
69 "Cholesky failure, writing debug.txt (Hessian loadable by Octave)");
70 csparse.writeSparse("debug.txt");
71 } else {
72 G2O_DEBUG("Cholesky failure");
73 }
74
76 if (globalStats) {
78 globalStats->choleskyNNZ = static_cast<size_t>(csparse.choleskyNz());
79 }
80
81 return ok;
82 }
83
84 protected:
87
89 bool hasSymbolic = csparse.hasSymbolic();
90 fillCSparse(A, hasSymbolic);
91 // perform symbolic cholesky once
92 if (!hasSymbolic) {
94 assert(csparse.hasSymbolic() && "Symbolic cholesky failed");
95 }
96 }
97
99 double t = get_monotonic_time();
100 if (!this->blockOrdering()) {
101 csparse.analyze();
102 } else {
104
105 // prepare block structure for the CSparse call
106 double* structureX = nullptr;
107 int structureNz = _matrixStructure.nzMax();
108 int structureAllocated = _matrixStructure.n;
110 _matrixStructure.n, _matrixStructure.n, structureNz,
112 structureAllocated);
113
114 // AMD ordering on the block structure
115 VectorXI blockPermutation;
116 csparse.amd(auxBlock, blockPermutation);
117
118 // blow up the permutation to the scalar matrix
119 VectorXI scalarPermutation;
120 this->blockToScalarPermutation(A, blockPermutation, scalarPermutation);
121 csparse.analyze_p(scalarPermutation.data());
122 }
124 if (globalStats) {
126 }
127 }
128
129 void fillCSparse(const SparseBlockMatrix<MatrixType>& A, bool onlyValues) {
130 if (!onlyValues) this->initMatrixStructure(A);
131 int m = A.rows();
132 int n = A.cols();
133 assert(m > 0 && n > 0 && "Hessian has 0 rows/cols");
134
136
137 if (ccsA.columnsAllocated < n) {
138 // pre-allocate more space if re-allocating
139 ccsA.columnsAllocated = ccsA.columnsAllocated == 0 ? n : 2 * n;
140 delete[] ccsA.p;
141 ccsA.p = new int[ccsA.columnsAllocated + 1];
142 }
143
144 if (!onlyValues) {
145 int nzmax = A.nonZeros();
146 if (ccsA.nzmax < nzmax) {
147 // pre-allocate more space if re-allocating
148 ccsA.nzmax = ccsA.nzmax == 0 ? nzmax : 2 * nzmax;
149 delete[] ccsA.x;
150 delete[] ccsA.i;
151 ccsA.i = new int[ccsA.nzmax];
152 ccsA.x = new double[ccsA.nzmax];
153 }
154 }
155 ccsA.m = m;
156 ccsA.n = n;
157
158 if (onlyValues) {
159 this->_ccsMatrix->fillCCS(ccsA.x, true);
160 } else {
161 int nz = this->_ccsMatrix->fillCCS(ccsA.p, ccsA.i, ccsA.x, true);
162 (void)nz;
163 assert(nz <= ccsA.nzmax);
164 }
165 }
166
174 std::function<void(MarginalCovarianceCholesky&)> compute) {
175 prepareSolve(A);
176 bool ok = csparse.factorize();
177 if (ok) {
180 mcc.setCholeskyFactor(factor.n, factor.p, factor.i, factor.x,
181 factor.pinv);
182 compute(mcc);
183 } else {
184 G2O_WARN("inverse fail (numeric decomposition)");
185 }
188 if (globalStats) {
189 globalStats->choleskyNNZ = static_cast<size_t>(csparse.choleskyNz());
190 }
191 return ok;
192 }
193};
194
195} // namespace g2o
196
197#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
linear solver which uses CSparse
void computeSymbolicDecomposition(const SparseBlockMatrix< MatrixType > &A)
LinearSolverCSparse(LinearSolverCSparse< MatrixType > const &)=delete
virtual ~LinearSolverCSparse()=default
void prepareSolve(const SparseBlockMatrix< MatrixType > &A)
bool solve(const SparseBlockMatrix< MatrixType > &A, double *x, double *b)
LinearSolverCSparse & operator=(LinearSolverCSparse< MatrixType > const &)=delete
void fillCSparse(const SparseBlockMatrix< MatrixType > &A, bool onlyValues)
bool solveBlocks_impl(const SparseBlockMatrix< MatrixType > &A, std::function< void(MarginalCovarianceCholesky &)> compute)
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(const SparseView &sparseView, VectorXI &result)
compute AMD ordering on the given SparseView, store into result
bool solve(double *x, double *b) const
bool analyze_p(int *permutation)
bool writeSparse(const std::string &filename) const
#define G2O_ERROR(...)
Definition logger.h:89
#define G2O_WARN(...)
Definition logger.h:88
#define G2O_DEBUG(...)
Definition logger.h:90
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 CSparse using CCS storage.
utility functions for handling time related stuff