GTSAM  4.0.2
C++ library for smoothing and mapping (SAM)
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 
20 #include <gtsam/base/FastVector.h>
21 #include <gtsam/base/Matrix.h>
22 #include <gtsam/base/types.h>
23 #include <gtsam/dllexport.h>
24 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION
25 #include <boost/serialization/nvp.hpp>
26 #endif
27 #include <cassert>
28 #include <stdexcept>
29 #include <array>
30 
31 namespace boost {
32 namespace serialization {
33 class access;
34 } /* namespace serialization */
35 } /* namespace boost */
36 
37 namespace gtsam {
38 
39  // Forward declarations
40  class VerticalBlockMatrix;
41 
53  class GTSAM_EXPORT SymmetricBlockMatrix
54  {
55  public:
56  typedef SymmetricBlockMatrix This;
57  typedef Eigen::Block<Matrix> Block;
58  typedef Eigen::Block<const Matrix> constBlock;
59 
60  protected:
61  Matrix matrix_;
63 
65 
66  public:
69 
71  template<typename CONTAINER>
72  SymmetricBlockMatrix(const CONTAINER& dimensions, bool appendOneDimension = false) :
73  blockStart_(0)
74  {
75  fillOffsets(dimensions.begin(), dimensions.end(), appendOneDimension);
76  matrix_.resize(variableColOffsets_.back(), variableColOffsets_.back());
77  assertInvariants();
78  }
79 
81  template<typename ITERATOR>
82  SymmetricBlockMatrix(ITERATOR firstBlockDim, ITERATOR lastBlockDim, bool appendOneDimension = false) :
83  blockStart_(0)
84  {
85  fillOffsets(firstBlockDim, lastBlockDim, appendOneDimension);
86  matrix_.resize(variableColOffsets_.back(), variableColOffsets_.back());
87  assertInvariants();
88  }
89 
91  template<typename CONTAINER>
92  SymmetricBlockMatrix(const CONTAINER& dimensions, const Matrix& matrix, bool appendOneDimension = false) :
93  blockStart_(0)
94  {
95  matrix_.resize(matrix.rows(), matrix.cols());
96  matrix_.triangularView<Eigen::Upper>() = matrix.triangularView<Eigen::Upper>();
97  fillOffsets(dimensions.begin(), dimensions.end(), appendOneDimension);
98  if(matrix_.rows() != matrix_.cols())
99  throw std::invalid_argument("Requested to create a SymmetricBlockMatrix from a non-square matrix.");
100  if(variableColOffsets_.back() != matrix_.cols())
101  throw std::invalid_argument("Requested to create a SymmetricBlockMatrix with dimensions that do not sum to the total size of the provided matrix.");
102  assertInvariants();
103  }
104 
108  static SymmetricBlockMatrix LikeActiveViewOf(const SymmetricBlockMatrix& other);
109 
113  static SymmetricBlockMatrix LikeActiveViewOf(const VerticalBlockMatrix& other);
114 
116  DenseIndex rows() const { assertInvariants(); return variableColOffsets_.back() - variableColOffsets_[blockStart_]; }
117 
119  DenseIndex cols() const { return rows(); }
120 
122  DenseIndex nBlocks() const { return nActualBlocks() - blockStart_; }
123 
125  DenseIndex getDim(DenseIndex block) const {
126  return calcIndices(block, block, 1, 1)[2];
127  }
128 
131 
134  Matrix block(DenseIndex I, DenseIndex J) const;
135 
137  Eigen::SelfAdjointView<Block, Eigen::Upper> diagonalBlock(DenseIndex J) {
138  return block_(J, J).selfadjointView<Eigen::Upper>();
139  }
140 
142  Eigen::SelfAdjointView<constBlock, Eigen::Upper> diagonalBlock(DenseIndex J) const {
143  return block_(J, J).selfadjointView<Eigen::Upper>();
144  }
145 
147  Vector diagonal(DenseIndex J) const {
148  return block_(J, J).diagonal();
149  }
150 
152  constBlock aboveDiagonalBlock(DenseIndex I, DenseIndex J) const {
153  assert(I < J);
154  return block_(I, J);
155  }
156 
158  Eigen::SelfAdjointView<constBlock, Eigen::Upper> selfadjointView(
159  DenseIndex I, DenseIndex J) const {
160  assert(J > I);
161  return block_(I, I, J - I, J - I).selfadjointView<Eigen::Upper>();
162  }
163 
165  Eigen::TriangularView<constBlock, Eigen::Upper> triangularView(DenseIndex I,
166  DenseIndex J) const {
167  assert(J > I);
168  return block_(I, I, J - I, J - I).triangularView<Eigen::Upper>();
169  }
170 
172  constBlock aboveDiagonalRange(DenseIndex i_startBlock,
173  DenseIndex i_endBlock,
174  DenseIndex j_startBlock,
175  DenseIndex j_endBlock) const {
176  assert(i_startBlock < j_startBlock);
177  assert(i_endBlock <= j_startBlock);
178  return block_(i_startBlock, j_startBlock, i_endBlock - i_startBlock,
179  j_endBlock - j_startBlock);
180  }
181 
183  Block aboveDiagonalRange(DenseIndex i_startBlock, DenseIndex i_endBlock,
184  DenseIndex j_startBlock, DenseIndex j_endBlock) {
185  assert(i_startBlock < j_startBlock);
186  assert(i_endBlock <= j_startBlock);
187  return block_(i_startBlock, j_startBlock, i_endBlock - i_startBlock,
188  j_endBlock - j_startBlock);
189  }
190 
194 
196  template <typename XprType>
197  void setDiagonalBlock(DenseIndex I, const XprType& xpr) {
198  block_(I, I).triangularView<Eigen::Upper>() = xpr.template triangularView<Eigen::Upper>();
199  }
200 
202  template <typename XprType>
203  void setOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType& xpr) {
204  assert(I != J);
205  if (I < J) {
206  block_(I, J) = xpr;
207  } else {
208  block_(J, I) = xpr.transpose();
209  }
210  }
211 
213  template <typename XprType>
214  void updateDiagonalBlock(DenseIndex I, const XprType& xpr) {
215  // TODO(gareth): Eigen won't let us add triangular or self-adjoint views
216  // here, so we do it manually.
217  auto dest = block_(I, I);
218  assert(dest.rows() == xpr.rows());
219  assert(dest.cols() == xpr.cols());
220  for (DenseIndex col = 0; col < dest.cols(); ++col) {
221  for (DenseIndex row = 0; row <= col; ++row) {
222  dest(row, col) += xpr(row, col);
223  }
224  }
225  }
226 
229  template <typename XprType>
230  void updateOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType& xpr) {
231  assert(I != J);
232  if (I < J) {
233  block_(I, J).noalias() += xpr;
234  } else {
235  block_(J, I).noalias() += xpr.transpose();
236  }
237  }
238 
242 
244  Eigen::SelfAdjointView<Block, Eigen::Upper> selfadjointView() {
245  return full().selfadjointView<Eigen::Upper>();
246  }
247 
249  Eigen::SelfAdjointView<constBlock, Eigen::Upper> selfadjointView() const {
250  return full().selfadjointView<Eigen::Upper>();
251  }
252 
254  template <typename XprType>
255  void setFullMatrix(const XprType& xpr) {
256  full().triangularView<Eigen::Upper>() = xpr.template triangularView<Eigen::Upper>();
257  }
258 
260  void setZero() {
261  full().triangularView<Eigen::Upper>().setZero();
262  }
263 
265  void negate();
266 
268  void invertInPlace();
269 
271 
275  DenseIndex& blockStart() { return blockStart_; }
276 
279  DenseIndex blockStart() const { return blockStart_; }
280 
291  void choleskyPartial(DenseIndex nFrontals);
292 
299 
300  protected:
301 
304  return variableColOffsets_.size();
305  }
306 
309  return nOffsets() - 1;
310  }
311 
313  DenseIndex offset(DenseIndex block) const {
314  assert(block >= 0);
315  const DenseIndex actual_index = block + blockStart();
316  assert(actual_index < nOffsets());
317  return variableColOffsets_[actual_index];
318  }
319 
321  constBlock block_(DenseIndex iBlock, DenseIndex jBlock,
322  DenseIndex blockRows = 1, DenseIndex blockCols = 1) const {
323  const std::array<DenseIndex, 4> indices =
324  calcIndices(iBlock, jBlock, blockRows, blockCols);
325  return matrix_.block(indices[0], indices[1], indices[2], indices[3]);
326  }
327 
329  Block block_(DenseIndex iBlock, DenseIndex jBlock, DenseIndex blockRows = 1,
330  DenseIndex blockCols = 1) {
331  const std::array<DenseIndex, 4> indices =
332  calcIndices(iBlock, jBlock, blockRows, blockCols);
333  return matrix_.block(indices[0], indices[1], indices[2], indices[3]);
334  }
335 
337  constBlock full() const {
338  return block_(0, 0, nBlocks(), nBlocks());
339  }
340 
342  Block full() {
343  return block_(0, 0, nBlocks(), nBlocks());
344  }
345 
347  std::array<DenseIndex, 4> calcIndices(DenseIndex iBlock, DenseIndex jBlock,
348  DenseIndex blockRows,
349  DenseIndex blockCols) const {
350  assert(blockRows >= 0);
351  assert(blockCols >= 0);
352 
353  // adjust indices to account for start and size of blocks
354  const DenseIndex denseI = offset(iBlock);
355  const DenseIndex denseJ = offset(jBlock);
356  const DenseIndex denseRows = offset(iBlock + blockRows) - denseI;
357  const DenseIndex denseCols = offset(jBlock + blockCols) - denseJ;
358  return {{denseI, denseJ, denseRows, denseCols}};
359  }
360 
361  void assertInvariants() const
362  {
363  assert(matrix_.rows() == matrix_.cols());
364  assert(matrix_.cols() == variableColOffsets_.back());
365  assert(blockStart_ < (DenseIndex)variableColOffsets_.size());
366  }
367 
368  template<typename ITERATOR>
369  void fillOffsets(ITERATOR firstBlockDim, ITERATOR lastBlockDim, bool appendOneDimension)
370  {
371  variableColOffsets_.resize((lastBlockDim-firstBlockDim) + 1 + (appendOneDimension ? 1 : 0));
372  variableColOffsets_[0] = 0;
373  DenseIndex j=0;
374  for(ITERATOR dim=firstBlockDim; dim!=lastBlockDim; ++dim) {
375  variableColOffsets_[j+1] = variableColOffsets_[j] + *dim;
376  ++ j;
377  }
378  if(appendOneDimension)
379  {
380  variableColOffsets_[j+1] = variableColOffsets_[j] + 1;
381  ++ j;
382  }
383  }
384 
385  friend class VerticalBlockMatrix;
386  template<typename SymmetricBlockMatrixType> friend class SymmetricBlockMatrixBlockExpr;
387 
388  private:
389 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION
390 
391  friend class boost::serialization::access;
392  template<class ARCHIVE>
393  void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
394  // Fill in the lower triangle part of the matrix, so boost::serialization won't
395  // complain about uninitialized data with an input_stream_error exception
396  // http://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/exceptions.html#stream_error
397  matrix_.triangularView<Eigen::Lower>() = matrix_.triangularView<Eigen::Upper>().transpose();
398  ar & BOOST_SERIALIZATION_NVP(matrix_);
399  ar & BOOST_SERIALIZATION_NVP(variableColOffsets_);
400  ar & BOOST_SERIALIZATION_NVP(blockStart_);
401  }
402 #endif
403  };
404 
406  class CholeskyFailed;
407 
408 }
const MATRIX::ConstRowXpr row(const MATRIX &A, size_t j)
Definition: Matrix.h:221
Typedefs for easier changing of types.
constBlock full() const
Get the full matrix as a block.
Definition: SymmetricBlockMatrix.h:337
Definition: FastSet.h:35
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:203
FastVector< DenseIndex > variableColOffsets_
the starting columns of each block (0-based)
Definition: SymmetricBlockMatrix.h:62
std::string serialize(const T &input)
serializes to a string
Definition: serialization.h:113
Definition: VerticalBlockMatrix.h:42
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:172
Block full()
Get the full matrix as a block.
Definition: SymmetricBlockMatrix.h:342
Matrix matrix_
The full matrix.
Definition: SymmetricBlockMatrix.h:61
std::vector< T, typename internal::FastDefaultVectorAllocator< T >::type > FastVector
Definition: FastVector.h:34
DenseIndex blockStart_
Changes apparent matrix view, see main class comment.
Definition: SymmetricBlockMatrix.h:64
GTSAM_EXPORT bool choleskyPartial(Matrix &ABC, size_t nFrontal, size_t topleft=0)
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:329
DenseIndex nActualBlocks() const
Number of actual blocks in the full matrix.
Definition: SymmetricBlockMatrix.h:308
Eigen::SelfAdjointView< constBlock, Eigen::Upper > diagonalBlock(DenseIndex J) const
Return the J&#39;th diagonal block as a self adjoint view.
Definition: SymmetricBlockMatrix.h:142
DenseIndex blockStart() const
Definition: SymmetricBlockMatrix.h:279
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition: types.h:108
SymmetricBlockMatrix(ITERATOR firstBlockDim, ITERATOR lastBlockDim, bool appendOneDimension=false)
Construct from iterator over the sizes of each vertical block.
Definition: SymmetricBlockMatrix.h:82
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:92
Definition: SymmetricBlockMatrix.h:53
void split(const G &g, const PredecessorMap< KEY > &tree, G &Ab1, G &Ab2)
Definition: graph-inl.h:245
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:158
DenseIndex nBlocks() const
Block count.
Definition: SymmetricBlockMatrix.h:122
DenseIndex rows() const
Row size.
Definition: SymmetricBlockMatrix.h:116
void setDiagonalBlock(DenseIndex I, const XprType &xpr)
Set a diagonal block. Only the upper triangular portion of xpr is evaluated.
Definition: SymmetricBlockMatrix.h:197
DenseIndex cols() const
Column 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:183
DenseIndex nOffsets() const
Number of offsets in the full matrix.
Definition: SymmetricBlockMatrix.h:303
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:165
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:214
typedef and functions to augment Eigen&#39;s MatrixXd
Eigen::SelfAdjointView< Block, Eigen::Upper > selfadjointView()
Get self adjoint view.
Definition: SymmetricBlockMatrix.h:244
void setFullMatrix(const XprType &xpr)
Set the entire active matrix. Only reads the upper triangular part of xpr.
Definition: SymmetricBlockMatrix.h:255
A thin wrapper around std::vector that uses a custom allocator.
Definition: chartTesting.h:28
DenseIndex offset(DenseIndex block) const
Get an offset for a block index (in the active view).
Definition: SymmetricBlockMatrix.h:313
Eigen::SelfAdjointView< constBlock, Eigen::Upper > selfadjointView() const
Get self adjoint view.
Definition: SymmetricBlockMatrix.h:249
void setZero()
Set the entire active matrix zero.
Definition: SymmetricBlockMatrix.h:260
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:347
Vector diagonal(DenseIndex J) const
Get the diagonal of the J&#39;th diagonal block.
Definition: SymmetricBlockMatrix.h:147
void updateOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType &xpr)
Definition: SymmetricBlockMatrix.h:230
DenseIndex & blockStart()
Definition: SymmetricBlockMatrix.h:275
Indicate Cholesky factorization failure.
Definition: ThreadsafeException.h:115
Eigen::SelfAdjointView< Block, Eigen::Upper > diagonalBlock(DenseIndex J)
Return the J&#39;th diagonal block as a self adjoint view.
Definition: SymmetricBlockMatrix.h:137
DenseIndex getDim(DenseIndex block) const
Number of dimensions for variable on this diagonal block.
Definition: SymmetricBlockMatrix.h:125
SymmetricBlockMatrix(const CONTAINER &dimensions, bool appendOneDimension=false)
Construct from a container of the sizes of each block.
Definition: SymmetricBlockMatrix.h:72
constBlock aboveDiagonalBlock(DenseIndex I, DenseIndex J) const
Get block above the diagonal (I, J).
Definition: SymmetricBlockMatrix.h:152
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:321