g2o
Loading...
Searching...
No Matches
linear_solver_pcg.hpp
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// helpers for doing fixed or variable size operations on the matrices
28
29#include <cassert>
30
31#include "g2o/stuff/logger.h"
32
33namespace internal {
34
35#ifdef _MSC_VER
36// MSVC does not like the template specialization, seems like MSVC applies type
37// conversion which results in calling a fixed size method (segment<int>) on the
38// dynamically sized matrices
39template <typename MatrixType>
40void pcg_axy(const MatrixType& A, const VectorX& x, int xoff, VectorX& y,
41 int yoff) {
42 y.segment(yoff, A.rows()) = A * x.segment(xoff, A.cols());
43}
44#else
45template <typename MatrixType>
46inline void pcg_axy(const MatrixType& A, const VectorX& x, int xoff, VectorX& y,
47 int yoff) {
48 y.segment<MatrixType::RowsAtCompileTime>(yoff) =
49 A * x.segment<MatrixType::ColsAtCompileTime>(xoff);
50}
51
52template <>
53inline void pcg_axy(const MatrixX& A, const VectorX& x, int xoff, VectorX& y,
54 int yoff) {
55 y.segment(yoff, A.rows()) = A * x.segment(xoff, A.cols());
56}
57#endif
58
59template <typename MatrixType>
60inline void pcg_axpy(const MatrixType& A, const VectorX& x, int xoff,
61 VectorX& y, int yoff) {
62 y.segment<MatrixType::RowsAtCompileTime>(yoff) +=
63 A * x.segment<MatrixType::ColsAtCompileTime>(xoff);
64}
65
66template <>
67inline void pcg_axpy(const MatrixX& A, const VectorX& x, int xoff, VectorX& y,
68 int yoff) {
69 y.segment(yoff, A.rows()) += A * x.segment(xoff, A.cols());
70}
71
72template <typename MatrixType>
73inline void pcg_atxpy(const MatrixType& A, const VectorX& x, int xoff,
74 VectorX& y, int yoff) {
75 y.segment<MatrixType::ColsAtCompileTime>(yoff) +=
76 A.transpose() * x.segment<MatrixType::RowsAtCompileTime>(xoff);
77}
78
79template <>
80inline void pcg_atxpy(const MatrixX& A, const VectorX& x, int xoff, VectorX& y,
81 int yoff) {
82 y.segment(yoff, A.cols()) += A.transpose() * x.segment(xoff, A.rows());
83}
84} // namespace internal
85// helpers end
86
87template <typename MatrixType>
89 double* x, double* b) {
90 const bool indexRequired = _indices.size() == 0;
91 _diag.clear();
92 _J.clear();
93
94 // put the block matrix once in a linear structure, makes mult faster
95 int colIdx = 0;
96 for (size_t i = 0; i < A.blockCols().size(); ++i) {
98 A.blockCols()[i];
99 if (col.size() > 0) {
101 for (it = col.begin(); it != col.end(); ++it) {
102 if (it->first == (int)i) { // only the upper triangular block is needed
103 _diag.push_back(it->second);
104 _J.push_back(it->second->inverse());
105 break;
106 }
107 if (indexRequired) {
108 _indices.push_back(std::make_pair(
109 it->first > 0 ? A.rowBlockIndices()[it->first - 1] : 0, colIdx));
110 _sparseMat.push_back(it->second);
111 }
112 }
113 }
114 colIdx = A.colBlockIndices()[i];
115 }
116
117 int n = A.rows();
118 assert(n > 0 && "Hessian has 0 rows/cols");
119 Eigen::Map<VectorX> xvec(x, A.cols());
120 const Eigen::Map<VectorX> bvec(b, n);
121 xvec.setZero();
122
123 VectorX r, d, q, s;
124 d.setZero(n);
125 q.setZero(n);
126 s.setZero(n);
127
128 r = bvec;
129 multDiag(A.colBlockIndices(), _J, r, d);
130 double dn = r.dot(d);
131 double d0 = _tolerance * dn;
132
133 if (_absoluteTolerance) {
134 if (_residual > 0.0 && _residual > d0) d0 = _residual;
135 }
136
137 int maxIter = _maxIter < 0 ? A.rows() : _maxIter;
138
139 int iteration;
140 for (iteration = 0; iteration < maxIter; ++iteration) {
141 G2O_DEBUG("residual [{}]: {}", iteration, dn);
142 if (dn <= d0) break; // done
143 mult(A.colBlockIndices(), d, q);
144 double a = dn / d.dot(q);
145 xvec += a * d;
146 // TODO: reset residual here every 50 iterations
147 r -= a * q;
148 multDiag(A.colBlockIndices(), _J, r, s);
149 double dold = dn;
150 dn = r.dot(s);
151 double ba = dn / dold;
152 d = s + ba * d;
153 }
154 _residual = 0.5 * dn;
155 G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
156 if (globalStats) {
157 globalStats->iterationsLinearSolver = iteration;
158 }
159
160 return true;
161}
162
163template <typename MatrixType>
165 const std::vector<int>& colBlockIndices, MatrixVector& A,
166 const VectorX& src, VectorX& dest) {
167 int row = 0;
168 for (size_t i = 0; i < A.size(); ++i) {
169 internal::pcg_axy(A[i], src, row, dest, row);
170 row = colBlockIndices[i];
171 }
172}
173
174template <typename MatrixType>
176 const std::vector<int>& colBlockIndices, MatrixPtrVector& A,
177 const VectorX& src, VectorX& dest) {
178 int row = 0;
179 for (size_t i = 0; i < A.size(); ++i) {
180 internal::pcg_axy(*A[i], src, row, dest, row);
181 row = colBlockIndices[i];
182 }
183}
184
185template <typename MatrixType>
186void LinearSolverPCG<MatrixType>::mult(const std::vector<int>& colBlockIndices,
187 const VectorX& src, VectorX& dest) {
188 // first multiply with the diagonal
189 multDiag(colBlockIndices, _diag, src, dest);
190
191 // now multiply with the upper triangular block
192 for (size_t i = 0; i < _sparseMat.size(); ++i) {
193 const int& srcOffset = _indices[i].second;
194 const int& destOffsetT = srcOffset;
195 const int& destOffset = _indices[i].first;
196 const int& srcOffsetT = destOffset;
197
199 _sparseMat[i];
200 // destVec += *a * srcVec (according to the sub-vector parts)
201 internal::pcg_axpy(*a, src, srcOffset, dest, destOffset);
202 // destVec += *a.transpose() * srcVec (according to the sub-vector parts)
203 internal::pcg_atxpy(*a, src, srcOffsetT, dest, destOffsetT);
204 }
205}
linear solver using PCG, pre-conditioner is block Jacobi
std::vector< MatrixType > MatrixVector
std::vector< const MatrixType * > MatrixPtrVector
Sparse matrix which uses blocks.
const std::vector< IntBlockMap > & blockCols() const
the block matrices per block-column
const std::vector< int > & colBlockIndices() const
indices of the column blocks
std::map< int, SparseMatrixBlock * > IntBlockMap
int rows() const
rows of the matrix
MatrixType SparseMatrixBlock
this is the type of the elementary block, it is an Eigen::Matrix.
int cols() const
columns of the matrix
const std::vector< int > & rowBlockIndices() const
indices of the row blocks
#define G2O_DEBUG(...)
Definition logger.h:90
VectorN< Eigen::Dynamic > VectorX
Definition eigen_types.h:55
void pcg_axpy(const MatrixType &A, const VectorX &x, int xoff, VectorX &y, int yoff)
void pcg_axy(const MatrixType &A, const VectorX &x, int xoff, VectorX &y, int yoff)
void pcg_atxpy(const MatrixType &A, const VectorX &x, int xoff, VectorX &y, int yoff)
statistics about the optimization
Definition batch_stats.h:40