g2o
Loading...
Searching...
No Matches
marginal_covariance_cholesky.cpp
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
28
29#include <algorithm>
30#include <cassert>
31
33
34using namespace std;
35
36namespace g2o {
37
38struct MatrixElem {
39 int r, c;
40 MatrixElem(int r_, int c_) : r(r_), c(c_) {}
41 bool operator<(const MatrixElem& other) const {
42 return c > other.c || (c == other.c && r > other.r);
43 }
44};
45
47 : _n(0), _Ap(0), _Ai(0), _Ax(0), _perm(0) {}
48
50
52 double* Lx, int* permInv) {
53 _n = n;
54 _Ap = Lp;
55 _Ai = Li;
56 _Ax = Lx;
57 _perm = permInv;
58
59 // pre-compute reciprocal values of the diagonal of L
60 _diag.resize(n);
61 for (int r = 0; r < n; ++r) {
62 const int& sc = _Ap[r]; // L is lower triangular, thus the first elem in
63 // the column is the diagonal entry
64 assert(r == _Ai[sc] && "Error in CCS storage of L");
65 _diag[r] = 1.0 / _Ax[sc];
66 }
67}
68
70 assert(r <= c);
71 int idx = computeIndex(r, c);
72
73 LookupMap::const_iterator foundIt = _map.find(idx);
74 if (foundIt != _map.end()) {
75 return foundIt->second;
76 }
77
78 // compute the summation over column r
79 double s = 0.;
80 const int& sc = _Ap[r];
81 const int& ec = _Ap[r + 1];
82 for (int j = sc + 1; j < ec;
83 ++j) { // sum over row r while skipping the element on the diagonal
84 const int& rr = _Ai[j];
85 double val = rr < c ? computeEntry(rr, c) : computeEntry(c, rr);
86 s += val * _Ax[j];
87 }
88
89 double result;
90 if (r == c) {
91 const double& diagElem = _diag[r];
92 result = diagElem * (diagElem - s);
93 } else {
94 result = -s * _diag[r];
95 }
96 _map[idx] = result;
97 return result;
98}
99
101 double** covBlocks, const std::vector<int>& blockIndices) {
102 _map.clear();
103 int base = 0;
104 vector<MatrixElem> elemsToCompute;
105 for (size_t i = 0; i < blockIndices.size(); ++i) {
106 int nbase = blockIndices[i];
107 int vdim = nbase - base;
108 for (int rr = 0; rr < vdim; ++rr)
109 for (int cc = rr; cc < vdim; ++cc) {
110 int r = _perm ? _perm[rr + base] : rr + base; // apply permutation
111 int c = _perm ? _perm[cc + base] : cc + base;
112 if (r > c) // make sure it's still upper triangular after applying the
113 // permutation
114 swap(r, c);
115 elemsToCompute.push_back(MatrixElem(r, c));
116 }
117 base = nbase;
118 }
119
120 // sort the elems to reduce the recursive calls
121 sort(elemsToCompute.begin(), elemsToCompute.end());
122
123 // compute the inverse elements we need
124 for (size_t i = 0; i < elemsToCompute.size(); ++i) {
125 const MatrixElem& me = elemsToCompute[i];
126 computeEntry(me.r, me.c);
127 }
128
129 // set the marginal covariance for the vertices, by writing to the blocks
130 // memory
131 base = 0;
132 for (size_t i = 0; i < blockIndices.size(); ++i) {
133 int nbase = blockIndices[i];
134 int vdim = nbase - base;
135 double* cov = covBlocks[i];
136 for (int rr = 0; rr < vdim; ++rr)
137 for (int cc = rr; cc < vdim; ++cc) {
138 int r = _perm ? _perm[rr + base] : rr + base; // apply permutation
139 int c = _perm ? _perm[cc + base] : cc + base;
140 if (r > c) // upper triangle
141 swap(r, c);
142 int idx = computeIndex(r, c);
143 LookupMap::const_iterator foundIt = _map.find(idx);
144 assert(foundIt != _map.end());
145 cov[rr * vdim + cc] = foundIt->second;
146 if (rr != cc) cov[cc * vdim + rr] = foundIt->second;
147 }
148 base = nbase;
149 }
150}
151
153 SparseBlockMatrix<MatrixX>& spinv, const std::vector<int>& rowBlockIndices,
154 const std::vector<std::pair<int, int> >& blockIndices) {
155 // allocate the sparse
156 spinv = SparseBlockMatrix<MatrixX>(&rowBlockIndices[0], &rowBlockIndices[0],
157 rowBlockIndices.size(),
158 rowBlockIndices.size(), true);
159 _map.clear();
160 vector<MatrixElem> elemsToCompute;
161 for (size_t i = 0; i < blockIndices.size(); ++i) {
162 int blockRow = blockIndices[i].first;
163 int blockCol = blockIndices[i].second;
164 assert(blockRow >= 0);
165 assert(blockRow < (int)rowBlockIndices.size());
166 assert(blockCol >= 0);
167 assert(blockCol < (int)rowBlockIndices.size());
168
169 int rowBase = spinv.rowBaseOfBlock(blockRow);
170 int colBase = spinv.colBaseOfBlock(blockCol);
171
172 MatrixX* block = spinv.block(blockRow, blockCol, true);
173 assert(block);
174 for (int iRow = 0; iRow < block->rows(); ++iRow)
175 for (int iCol = 0; iCol < block->cols(); ++iCol) {
176 int rr = rowBase + iRow;
177 int cc = colBase + iCol;
178 int r = _perm ? _perm[rr] : rr; // apply permutation
179 int c = _perm ? _perm[cc] : cc;
180 if (r > c) swap(r, c);
181 elemsToCompute.push_back(MatrixElem(r, c));
182 }
183 }
184
185 // sort the elems to reduce the number of recursive calls
186 sort(elemsToCompute.begin(), elemsToCompute.end());
187
188 // compute the inverse elements we need
189 for (size_t i = 0; i < elemsToCompute.size(); ++i) {
190 const MatrixElem& me = elemsToCompute[i];
191 computeEntry(me.r, me.c);
192 }
193
194 // set the marginal covariance
195 for (size_t i = 0; i < blockIndices.size(); ++i) {
196 int blockRow = blockIndices[i].first;
197 int blockCol = blockIndices[i].second;
198 int rowBase = spinv.rowBaseOfBlock(blockRow);
199 int colBase = spinv.colBaseOfBlock(blockCol);
200
201 MatrixX* block = spinv.block(blockRow, blockCol);
202 assert(block);
203 for (int iRow = 0; iRow < block->rows(); ++iRow)
204 for (int iCol = 0; iCol < block->cols(); ++iCol) {
205 int rr = rowBase + iRow;
206 int cc = colBase + iCol;
207 int r = _perm ? _perm[rr] : rr; // apply permutation
208 int c = _perm ? _perm[cc] : cc;
209 if (r > c) swap(r, c);
210 int idx = computeIndex(r, c);
211 LookupMap::const_iterator foundIt = _map.find(idx);
212 assert(foundIt != _map.end());
213 (*block)(iRow, iCol) = foundIt->second;
214 }
215 }
216}
217
218} // namespace g2o
void computeCovariance(double **covBlocks, const std::vector< int > &blockIndices)
double * _Ax
values of the cholesky factor
int * _Ai
row indices of the CCS storage
void setCholeskyFactor(int n, int *Lp, int *Li, double *Lx, int *permInv)
int * _Ap
column pointer of the CCS storage
std::vector< double > _diag
cache 1 / H_ii to avoid recalculations
LookupMap _map
hash look up table for the already computed entries
int computeIndex(int r, int c) const
compute the index used for hashing
Sparse matrix which uses blocks.
int colBaseOfBlock(int c) const
where does the col at block-col r starts?
SparseMatrixBlock * block(int r, int c, bool alloc=false)
int rowBaseOfBlock(int r) const
where does the row at block-row r starts?
MatrixN< Eigen::Dynamic > MatrixX
Definition eigen_types.h:74
Definition jet.h:876
bool operator<(const MatrixElem &other) const