gtsam 4.1.1
gtsam
SymmetricBlockMatrix.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2
3* GTSAM Copyright 2010, Georgia Tech Research Corporation,
4* Atlanta, Georgia 30332-0415
5* All Rights Reserved
6* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8* See LICENSE for the license information
9
10* -------------------------------------------------------------------------- */
11
18#pragma once
19
21#include <gtsam/base/Matrix.h>
22#include <gtsam/base/types.h>
23#include <gtsam/dllexport.h>
24#include <boost/serialization/nvp.hpp>
25#include <cassert>
26#include <stdexcept>
27#include <array>
28
29namespace boost {
30namespace serialization {
31class access;
32} /* namespace serialization */
33} /* namespace boost */
34
35namespace gtsam {
36
37 // Forward declarations
38 class VerticalBlockMatrix;
39
51 class GTSAM_EXPORT SymmetricBlockMatrix
52 {
53 public:
55 typedef Eigen::Block<Matrix> Block;
56 typedef Eigen::Block<const Matrix> constBlock;
57
58 protected:
59 Matrix matrix_;
60 FastVector<DenseIndex> variableColOffsets_;
61
63
64 public:
67 blockStart_(0)
68 {
69 variableColOffsets_.push_back(0);
70 assertInvariants();
71 }
72
74 template<typename CONTAINER>
75 SymmetricBlockMatrix(const CONTAINER& dimensions, bool appendOneDimension = false) :
76 blockStart_(0)
77 {
78 fillOffsets(dimensions.begin(), dimensions.end(), appendOneDimension);
79 matrix_.resize(variableColOffsets_.back(), variableColOffsets_.back());
80 assertInvariants();
81 }
82
84 template<typename ITERATOR>
85 SymmetricBlockMatrix(ITERATOR firstBlockDim, ITERATOR lastBlockDim, bool appendOneDimension = false) :
86 blockStart_(0)
87 {
88 fillOffsets(firstBlockDim, lastBlockDim, appendOneDimension);
89 matrix_.resize(variableColOffsets_.back(), variableColOffsets_.back());
90 assertInvariants();
91 }
92
94 template<typename CONTAINER>
95 SymmetricBlockMatrix(const CONTAINER& dimensions, const Matrix& matrix, bool appendOneDimension = false) :
96 blockStart_(0)
97 {
98 matrix_.resize(matrix.rows(), matrix.cols());
99 matrix_.triangularView<Eigen::Upper>() = matrix.triangularView<Eigen::Upper>();
100 fillOffsets(dimensions.begin(), dimensions.end(), appendOneDimension);
101 if(matrix_.rows() != matrix_.cols())
102 throw std::invalid_argument("Requested to create a SymmetricBlockMatrix from a non-square matrix.");
103 if(variableColOffsets_.back() != matrix_.cols())
104 throw std::invalid_argument("Requested to create a SymmetricBlockMatrix with dimensions that do not sum to the total size of the provided matrix.");
105 assertInvariants();
106 }
107
111 static SymmetricBlockMatrix LikeActiveViewOf(const SymmetricBlockMatrix& other);
112
116 static SymmetricBlockMatrix LikeActiveViewOf(const VerticalBlockMatrix& other);
117
119 DenseIndex rows() const { assertInvariants(); return variableColOffsets_.back() - variableColOffsets_[blockStart_]; }
120
122 DenseIndex cols() const { return rows(); }
123
125 DenseIndex nBlocks() const { return nActualBlocks() - blockStart_; }
126
129 return calcIndices(block, block, 1, 1)[2];
130 }
131
134
137 Matrix block(DenseIndex I, DenseIndex J) const;
138
140 Eigen::SelfAdjointView<Block, Eigen::Upper> diagonalBlock(DenseIndex J) {
141 return block_(J, J).selfadjointView<Eigen::Upper>();
142 }
143
145 Eigen::SelfAdjointView<constBlock, Eigen::Upper> diagonalBlock(DenseIndex J) const {
146 return block_(J, J).selfadjointView<Eigen::Upper>();
147 }
148
150 Vector diagonal(DenseIndex J) const {
151 return block_(J, J).diagonal();
152 }
153
155 constBlock aboveDiagonalBlock(DenseIndex I, DenseIndex J) const {
156 assert(I < J);
157 return block_(I, J);
158 }
159
161 Eigen::SelfAdjointView<constBlock, Eigen::Upper> selfadjointView(
162 DenseIndex I, DenseIndex J) const {
163 assert(J > I);
164 return block_(I, I, J - I, J - I).selfadjointView<Eigen::Upper>();
165 }
166
168 Eigen::TriangularView<constBlock, Eigen::Upper> triangularView(DenseIndex I,
169 DenseIndex J) const {
170 assert(J > I);
171 return block_(I, I, J - I, J - I).triangularView<Eigen::Upper>();
172 }
173
175 constBlock aboveDiagonalRange(DenseIndex i_startBlock,
176 DenseIndex i_endBlock,
177 DenseIndex j_startBlock,
178 DenseIndex j_endBlock) const {
179 assert(i_startBlock < j_startBlock);
180 assert(i_endBlock <= j_startBlock);
181 return block_(i_startBlock, j_startBlock, i_endBlock - i_startBlock,
182 j_endBlock - j_startBlock);
183 }
184
186 Block aboveDiagonalRange(DenseIndex i_startBlock, DenseIndex i_endBlock,
187 DenseIndex j_startBlock, DenseIndex j_endBlock) {
188 assert(i_startBlock < j_startBlock);
189 assert(i_endBlock <= j_startBlock);
190 return block_(i_startBlock, j_startBlock, i_endBlock - i_startBlock,
191 j_endBlock - j_startBlock);
192 }
193
197
199 template <typename XprType>
200 void setDiagonalBlock(DenseIndex I, const XprType& xpr) {
201 block_(I, I).triangularView<Eigen::Upper>() = xpr.template triangularView<Eigen::Upper>();
202 }
203
205 template <typename XprType>
206 void setOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType& xpr) {
207 assert(I != J);
208 if (I < J) {
209 block_(I, J) = xpr;
210 } else {
211 block_(J, I) = xpr.transpose();
212 }
213 }
214
216 template <typename XprType>
217 void updateDiagonalBlock(DenseIndex I, const XprType& xpr) {
218 // TODO(gareth): Eigen won't let us add triangular or self-adjoint views
219 // here, so we do it manually.
220 auto dest = block_(I, I);
221 assert(dest.rows() == xpr.rows());
222 assert(dest.cols() == xpr.cols());
223 for (DenseIndex col = 0; col < dest.cols(); ++col) {
224 for (DenseIndex row = 0; row <= col; ++row) {
225 dest(row, col) += xpr(row, col);
226 }
227 }
228 }
229
232 template <typename XprType>
233 void updateOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType& xpr) {
234 assert(I != J);
235 if (I < J) {
236 block_(I, J).noalias() += xpr;
237 } else {
238 block_(J, I).noalias() += xpr.transpose();
239 }
240 }
241
245
247 Eigen::SelfAdjointView<Block, Eigen::Upper> selfadjointView() {
248 return full().selfadjointView<Eigen::Upper>();
249 }
250
252 Eigen::SelfAdjointView<constBlock, Eigen::Upper> selfadjointView() const {
253 return full().selfadjointView<Eigen::Upper>();
254 }
255
257 template <typename XprType>
258 void setFullMatrix(const XprType& xpr) {
259 full().triangularView<Eigen::Upper>() = xpr.template triangularView<Eigen::Upper>();
260 }
261
263 void setZero() {
264 full().triangularView<Eigen::Upper>().setZero();
265 }
266
268 void negate() {
269 full().triangularView<Eigen::Upper>() *= -1.0;
270 }
271
274 const auto identity = Matrix::Identity(rows(), rows());
275 full().triangularView<Eigen::Upper>() =
276 selfadjointView()
277 .llt()
278 .solve(identity)
279 .triangularView<Eigen::Upper>();
280 }
281
283
287 DenseIndex& blockStart() { return blockStart_; }
288
291 DenseIndex blockStart() const { return blockStart_; }
292
303 void choleskyPartial(DenseIndex nFrontals);
304
311
312 protected:
313
316 return variableColOffsets_.size();
317 }
318
321 return nOffsets() - 1;
322 }
323
326 assert(block >= 0);
327 const DenseIndex actual_index = block + blockStart();
328 assert(actual_index < nOffsets());
329 return variableColOffsets_[actual_index];
330 }
331
333 constBlock block_(DenseIndex iBlock, DenseIndex jBlock,
334 DenseIndex blockRows = 1, DenseIndex blockCols = 1) const {
335 const std::array<DenseIndex, 4> indices =
336 calcIndices(iBlock, jBlock, blockRows, blockCols);
337 return matrix_.block(indices[0], indices[1], indices[2], indices[3]);
338 }
339
341 Block block_(DenseIndex iBlock, DenseIndex jBlock, DenseIndex blockRows = 1,
342 DenseIndex blockCols = 1) {
343 const std::array<DenseIndex, 4> indices =
344 calcIndices(iBlock, jBlock, blockRows, blockCols);
345 return matrix_.block(indices[0], indices[1], indices[2], indices[3]);
346 }
347
349 constBlock full() const {
350 return block_(0, 0, nBlocks(), nBlocks());
351 }
352
354 Block full() {
355 return block_(0, 0, nBlocks(), nBlocks());
356 }
357
359 std::array<DenseIndex, 4> calcIndices(DenseIndex iBlock, DenseIndex jBlock,
360 DenseIndex blockRows,
361 DenseIndex blockCols) const {
362 assert(blockRows >= 0);
363 assert(blockCols >= 0);
364
365 // adjust indices to account for start and size of blocks
366 const DenseIndex denseI = offset(iBlock);
367 const DenseIndex denseJ = offset(jBlock);
368 const DenseIndex denseRows = offset(iBlock + blockRows) - denseI;
369 const DenseIndex denseCols = offset(jBlock + blockCols) - denseJ;
370 return {{denseI, denseJ, denseRows, denseCols}};
371 }
372
373 void assertInvariants() const
374 {
375 assert(matrix_.rows() == matrix_.cols());
376 assert(matrix_.cols() == variableColOffsets_.back());
377 assert(blockStart_ < (DenseIndex)variableColOffsets_.size());
378 }
379
380 template<typename ITERATOR>
381 void fillOffsets(ITERATOR firstBlockDim, ITERATOR lastBlockDim, bool appendOneDimension)
382 {
383 variableColOffsets_.resize((lastBlockDim-firstBlockDim) + 1 + (appendOneDimension ? 1 : 0));
384 variableColOffsets_[0] = 0;
385 DenseIndex j=0;
386 for(ITERATOR dim=firstBlockDim; dim!=lastBlockDim; ++dim) {
387 variableColOffsets_[j+1] = variableColOffsets_[j] + *dim;
388 ++ j;
389 }
390 if(appendOneDimension)
391 {
392 variableColOffsets_[j+1] = variableColOffsets_[j] + 1;
393 ++ j;
394 }
395 }
396
397 friend class VerticalBlockMatrix;
398 template<typename SymmetricBlockMatrixType> friend class SymmetricBlockMatrixBlockExpr;
399
400 private:
402 friend class boost::serialization::access;
403 template<class ARCHIVE>
404 void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
405 // Fill in the lower triangle part of the matrix, so boost::serialization won't
406 // complain about uninitialized data with an input_stream_error exception
407 // http://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/exceptions.html#stream_error
408 matrix_.triangularView<Eigen::Lower>() = matrix_.triangularView<Eigen::Upper>().transpose();
409 ar & BOOST_SERIALIZATION_NVP(matrix_);
410 ar & BOOST_SERIALIZATION_NVP(variableColOffsets_);
411 ar & BOOST_SERIALIZATION_NVP(blockStart_);
412 }
413 };
414
416 class CholeskyFailed;
417
418}
A thin wrapper around std::vector that uses a custom allocator.
Typedefs for easier changing of types.
typedef and functions to augment Eigen's MatrixXd
Global functions in a separate testing namespace.
Definition: chartTesting.h:28
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition: types.h:75
const MATRIX::ConstRowXpr row(const MATRIX &A, size_t j)
Extracts a row view from a matrix that avoids a copy.
Definition: Matrix.h:225
std::string serialize(const T &input)
serializes to a string
Definition: serialization.h:112
void split(const G &g, const PredecessorMap< KEY > &tree, G &Ab1, G &Ab2)
Split the graph into two parts: one corresponds to the given spanning tree, and the other corresponds...
Definition: graph-inl.h:255
bool choleskyPartial(Matrix &ABC, size_t nFrontal, size_t topleft)
Partial Cholesky computes a factor [R S such that [R' 0 [R S = [A B 0 L] S' I] 0 L] B' C].
Definition: cholesky.cpp:108
Definition: SymmetricBlockMatrix.h:52
Block full()
Get the full matrix as a block.
Definition: SymmetricBlockMatrix.h:354
DenseIndex blockStart_
Changes apparent matrix view, see main class comment.
Definition: SymmetricBlockMatrix.h:62
void setDiagonalBlock(DenseIndex I, const XprType &xpr)
Set a diagonal block. Only the upper triangular portion of xpr is evaluated.
Definition: SymmetricBlockMatrix.h:200
DenseIndex nActualBlocks() const
Number of actual blocks in the full matrix.
Definition: SymmetricBlockMatrix.h:320
Vector diagonal(DenseIndex J) const
Get the diagonal of the J'th diagonal block.
Definition: SymmetricBlockMatrix.h:150
Matrix matrix_
The full matrix.
Definition: SymmetricBlockMatrix.h:59
DenseIndex cols() const
Column size.
Definition: SymmetricBlockMatrix.h:122
DenseIndex getDim(DenseIndex block) const
Number of dimensions for variable on this diagonal block.
Definition: SymmetricBlockMatrix.h:128
void setZero()
Set the entire active matrix zero.
Definition: SymmetricBlockMatrix.h:263
void setOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType &xpr)
Set an off-diagonal block. Only the upper triangular portion of xpr is evaluated.
Definition: SymmetricBlockMatrix.h:206
void negate()
Negate the entire active matrix.
Definition: SymmetricBlockMatrix.h:268
void setFullMatrix(const XprType &xpr)
Set the entire active matrix. Only reads the upper triangular part of xpr.
Definition: SymmetricBlockMatrix.h:258
Eigen::SelfAdjointView< Block, Eigen::Upper > selfadjointView()
Get self adjoint view.
Definition: SymmetricBlockMatrix.h:247
constBlock aboveDiagonalBlock(DenseIndex I, DenseIndex J) const
Get block above the diagonal (I, J).
Definition: SymmetricBlockMatrix.h:155
constBlock block_(DenseIndex iBlock, DenseIndex jBlock, DenseIndex blockRows=1, DenseIndex blockCols=1) const
Get an arbitrary block from the matrix. Indices are in block units.
Definition: SymmetricBlockMatrix.h:333
void invertInPlace()
Invert the entire active matrix in place.
Definition: SymmetricBlockMatrix.h:273
constBlock full() const
Get the full matrix as a block.
Definition: SymmetricBlockMatrix.h:349
DenseIndex rows() const
Row size.
Definition: SymmetricBlockMatrix.h:119
Block aboveDiagonalRange(DenseIndex i_startBlock, DenseIndex i_endBlock, DenseIndex j_startBlock, DenseIndex j_endBlock)
Get a range [i,j) from the matrix. Indices are in block units.
Definition: SymmetricBlockMatrix.h:186
Eigen::TriangularView< constBlock, Eigen::Upper > triangularView(DenseIndex I, DenseIndex J) const
Return the square sub-matrix that contains blocks(i:j, i:j) as a triangular view.
Definition: SymmetricBlockMatrix.h:168
Eigen::SelfAdjointView< constBlock, Eigen::Upper > diagonalBlock(DenseIndex J) const
Return the J'th diagonal block as a self adjoint view.
Definition: SymmetricBlockMatrix.h:145
SymmetricBlockMatrix(const CONTAINER &dimensions, const Matrix &matrix, bool appendOneDimension=false)
Construct from a container of the sizes of each vertical block and a pre-prepared matrix.
Definition: SymmetricBlockMatrix.h:95
DenseIndex blockStart() const
Retrieve the first logical block, i.e.
Definition: SymmetricBlockMatrix.h:291
Eigen::SelfAdjointView< constBlock, Eigen::Upper > selfadjointView() const
Get self adjoint view.
Definition: SymmetricBlockMatrix.h:252
void updateOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType &xpr)
Update an off diagonal block.
Definition: SymmetricBlockMatrix.h:233
SymmetricBlockMatrix(const CONTAINER &dimensions, bool appendOneDimension=false)
Construct from a container of the sizes of each block.
Definition: SymmetricBlockMatrix.h:75
SymmetricBlockMatrix(ITERATOR firstBlockDim, ITERATOR lastBlockDim, bool appendOneDimension=false)
Construct from iterator over the sizes of each vertical block.
Definition: SymmetricBlockMatrix.h:85
DenseIndex & blockStart()
Retrieve or modify the first logical block, i.e.
Definition: SymmetricBlockMatrix.h:287
constBlock aboveDiagonalRange(DenseIndex i_startBlock, DenseIndex i_endBlock, DenseIndex j_startBlock, DenseIndex j_endBlock) const
Get a range [i,j) from the matrix. Indices are in block units.
Definition: SymmetricBlockMatrix.h:175
SymmetricBlockMatrix()
Construct from an empty matrix (asserts that the matrix is empty)
Definition: SymmetricBlockMatrix.h:66
Eigen::SelfAdjointView< Block, Eigen::Upper > diagonalBlock(DenseIndex J)
Return the J'th diagonal block as a self adjoint view.
Definition: SymmetricBlockMatrix.h:140
Block block_(DenseIndex iBlock, DenseIndex jBlock, DenseIndex blockRows=1, DenseIndex blockCols=1)
Get an arbitrary block from the matrix. Indices are in block units.
Definition: SymmetricBlockMatrix.h:341
void updateDiagonalBlock(DenseIndex I, const XprType &xpr)
Increment the diagonal block by the values in xpr. Only reads the upper triangular part of xpr.
Definition: SymmetricBlockMatrix.h:217
DenseIndex nOffsets() const
Number of offsets in the full matrix.
Definition: SymmetricBlockMatrix.h:315
std::array< DenseIndex, 4 > calcIndices(DenseIndex iBlock, DenseIndex jBlock, DenseIndex blockRows, DenseIndex blockCols) const
Compute the indices into the underlying matrix for a given block.
Definition: SymmetricBlockMatrix.h:359
DenseIndex nBlocks() const
Block count.
Definition: SymmetricBlockMatrix.h:125
FastVector< DenseIndex > variableColOffsets_
the starting columns of each block (0-based)
Definition: SymmetricBlockMatrix.h:60
Eigen::SelfAdjointView< constBlock, Eigen::Upper > selfadjointView(DenseIndex I, DenseIndex J) const
Return the square sub-matrix that contains blocks(i:j, i:j).
Definition: SymmetricBlockMatrix.h:161
DenseIndex offset(DenseIndex block) const
Get an offset for a block index (in the active view).
Definition: SymmetricBlockMatrix.h:325
Definition: VerticalBlockMatrix.h:42