gtsam  3.2.1
gtsam
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SymmetricBlockMatrixBlockExpr.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/Matrix.h>
21 
22 namespace gtsam { template<typename SymmetricBlockMatrixType> class SymmetricBlockMatrixBlockExpr; }
23 namespace gtsam { class SymmetricBlockMatrix; }
24 
25 // traits class for Eigen expressions
26 namespace Eigen
27 {
28  namespace internal
29  {
30  template<typename SymmetricBlockMatrixType>
31  struct traits<gtsam::SymmetricBlockMatrixBlockExpr<SymmetricBlockMatrixType> > :
32  public traits<typename gtsam::const_selector<
33  SymmetricBlockMatrixType, gtsam::SymmetricBlockMatrix, gtsam::Matrix, const gtsam::Matrix>::type>
34  {
35  };
36  }
37 }
38 
39 namespace gtsam
40 {
45  template<typename SymmetricBlockMatrixType>
46  class SymmetricBlockMatrixBlockExpr : public Eigen::EigenBase<SymmetricBlockMatrixBlockExpr<SymmetricBlockMatrixType> >
47  {
48  protected:
49  SymmetricBlockMatrixType& xpr_;
54  enum BlockType { Plain, SelfAdjoint, Transposed } blockType_;
56 
57  public:
58  // Typedefs and constants used in Eigen
59  typedef typename const_selector<SymmetricBlockMatrixType, SymmetricBlockMatrix,
60  typename Eigen::internal::traits<This>::Scalar&, typename Eigen::internal::traits<This>::Scalar>::type ScalarRef;
61  typedef typename Eigen::internal::traits<This>::Scalar Scalar;
62  typedef typename Eigen::internal::traits<This>::Index Index;
63  static const Index ColsAtCompileTime = Eigen::Dynamic;
64  static const Index RowsAtCompileTime = Eigen::Dynamic;
65 
67  DenseMatrixType;
68 
69  typedef Eigen::Map<DenseMatrixType, 0, Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> > OffDiagonal;
70  typedef Eigen::SelfAdjointView<Eigen::Block<DenseMatrixType>, Eigen::Upper> SelfAdjointView;
71  typedef Eigen::TriangularView<Eigen::Block<DenseMatrixType>, Eigen::Upper> TriangularView;
72 
73  protected:
74  mutable Eigen::Block<DenseMatrixType> myBlock_;
75  template<typename OtherSymmetricBlockMatrixType> friend class SymmetricBlockMatrixBlockExpr;
76 
77  public:
79  SymmetricBlockMatrixBlockExpr(SymmetricBlockMatrixType& blockMatrix, Index iBlock, Index jBlock) :
80  xpr_(blockMatrix), myBlock_(blockMatrix.matrix_.block(0, 0, 0, 0))
81  {
82  initIndices(iBlock, jBlock);
83  }
84 
87  SymmetricBlockMatrixBlockExpr(SymmetricBlockMatrixType& blockMatrix,
88  Index firstRowBlock, Index firstColBlock, Index rowBlocks, Index colBlocks) :
89  xpr_(blockMatrix), myBlock_(blockMatrix.matrix_.block(0, 0, 0, 0))
90  {
91  initIndices(firstRowBlock, firstColBlock, rowBlocks, colBlocks);
92  }
93 
96  SymmetricBlockMatrixBlockExpr(SymmetricBlockMatrixType& blockMatrix, Index firstBlock, Index blocks, char dummy) :
97  xpr_(blockMatrix), myBlock_(blockMatrix.matrix_.block(0, 0, 0, 0))
98  {
99  initIndices(firstBlock, firstBlock, blocks, blocks);
100  }
101 
102  inline Index rows() const { return blockType_ != Transposed ? denseRows_ : denseCols_; }
103  inline Index cols() const { return blockType_ != Transposed ? denseCols_ : denseRows_; }
104 
105  inline BlockType blockType() const { return blockType_; }
106 
107  inline ScalarRef operator()(Index row, Index col) const
108  {
109  return coeffInternal<ScalarRef>(row, col);
110  }
111 
112  inline OffDiagonal knownOffDiagonal() const
113  {
114  typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> DynamicStride;
115 
116  // We can return a Map if we are either on an off-diagonal block, or a block of size 0 or 1
117  assert(blockType_ != SelfAdjoint || (denseRows_ <= 1 && denseCols_ <= 1));
118  if(blockType_ == Transposed)
119  {
120  // Swap the inner and outer stride to produce a transposed Map
121  Eigen::Block<DenseMatrixType> block = const_cast<This&>(*this).xpr_.matrix_.block(densei_, densej_, denseRows_, denseCols_);
122  return Eigen::Map<DenseMatrixType, 0, DynamicStride>(block.data(), block.cols(), block.rows(),
123  DynamicStride(block.innerStride(), block.outerStride()));
124  }
125  else
126  {
127  Eigen::Block<DenseMatrixType> block = const_cast<This&>(*this).xpr_.matrix_.block(densei_, densej_, denseRows_, denseCols_);
128  return Eigen::Map<DenseMatrixType, 0, DynamicStride>(block.data(), block.rows(), block.cols(),
129  DynamicStride(block.outerStride(), block.innerStride()));
130  }
131  }
132 
133  inline SelfAdjointView selfadjointView() const
134  {
135  assert(blockType_ == SelfAdjoint);
136  return myBlock_;
137  }
138 
139  inline TriangularView triangularView() const
140  {
141  assert(blockType_ == SelfAdjoint);
142  return myBlock_;
143  }
144 
145  template<typename Dest> inline void evalTo(Dest& dst) const
146  {
147  // Just try to assign to the object using either a selfadjoint view or a block view
148  if(blockType_ == SelfAdjoint)
149  dst = selfadjointView();
150  else if(blockType_ == Plain)
151  dst = myBlock_;
152  else
153  dst = myBlock_.transpose();
154  }
155 
156  //template<typename MatrixType> inline void evalTo(const Eigen::SelfAdjointView<MatrixType, Eigen::Upper>& rhs) const
157  //{
158  // if(blockType_ == SelfAdjoint)
159  // rhs.nestedExpression().triangularView<Eigen::Upper>() = triangularView();
160  // else
161  // throw std::invalid_argument("Cannot assign an off-diagonal block to a self-adjoint matrix");
162  //}
163 
164  //template<typename MatrixType> inline void evalTo(const Eigen::TriangularView<MatrixType, Eigen::Upper>& rhs) const
165  //{
166  // if(blockType_ == SelfAdjoint)
167  // rhs.nestedExpression().triangularView<Eigen::Upper>() = triangularView();
168  // else
169  // throw std::invalid_argument("Cannot assign an off-diagonal block to a self-adjoint matrix");
170  //}
171 
172  template<typename RhsDerived>
173  This& operator=(const Eigen::MatrixBase<RhsDerived>& rhs)
174  {
175  // Just try to assign to the object using either a selfadjoint view or a block view
176  if(blockType_ == SelfAdjoint)
177  triangularView() = rhs.derived().template triangularView<Eigen::Upper>();
178  else if(blockType_ == Plain)
179  myBlock_ = rhs.derived();
180  else
181  myBlock_.transpose() = rhs.derived();
182  return *this;
183  }
184 
185  template<typename MatrixType>
186  This& operator=(const Eigen::SelfAdjointView<MatrixType, Eigen::Upper>& rhs)
187  {
188  if(blockType_ == SelfAdjoint)
189  triangularView() = rhs.nestedExpression().template triangularView<Eigen::Upper>();
190  else
191  throw std::invalid_argument("Cannot assign a self-adjoint matrix to an off-diagonal block");
192  return *this;
193  }
194 
195  template<typename OtherSymmetricBlockMatrixType>
196  This& operator=(const SymmetricBlockMatrixBlockExpr<OtherSymmetricBlockMatrixType>& other)
197  {
198  _doAssign(other);
199  return *this;
200  }
201 
202  This& operator=(const This& other)
203  {
204  // This version is required so GCC doesn't synthesize a default operator=.
205  _doAssign(other);
206  return *this;
207  }
208 
209  template<typename OtherSymmetricBlockMatrixType>
210  This& operator+=(const SymmetricBlockMatrixBlockExpr<OtherSymmetricBlockMatrixType>& other)
211  {
212  if(blockType_ == SelfAdjoint)
213  {
214  assert((BlockType)other.blockType() == SelfAdjoint);
215  triangularView() += other.triangularView().nestedExpression();
216  }
217  else if(blockType_ == Plain)
218  {
219  assert((BlockType)other.blockType() == Plain || (BlockType)other.blockType() == Transposed);
220  if((BlockType)other.blockType() == Transposed)
221  myBlock_ += other.myBlock_.transpose();
222  else
223  myBlock_ += other.myBlock_;
224  }
225  else
226  {
227  assert((BlockType)other.blockType() == Plain || (BlockType)other.blockType() == Transposed);
228  if((BlockType)other.blockType() == Transposed)
229  myBlock_.transpose() += other.myBlock_.transpose();
230  else
231  myBlock_.transpose() += other.myBlock_;
232  }
233  return *this;
234  }
235 
236  private:
237  void initIndices(Index iBlock, Index jBlock, Index blockRows = 1, Index blockCols = 1)
238  {
239  if(iBlock == jBlock && blockRows == blockCols)
240  {
241  densei_ = xpr_.offset(iBlock);
242  densej_ = densei_;
243  if(blockRows > 0)
244  xpr_.checkBlock(iBlock + blockRows - 1);
245  denseRows_ = xpr_.offsetUnchecked(iBlock + blockRows) - densei_;
246  if(blockCols > 0)
247  xpr_.checkBlock(jBlock + blockCols - 1);
248  denseCols_ = xpr_.offsetUnchecked(jBlock + blockCols) - densej_;
249  blockType_ = SelfAdjoint;
250  }
251  else
252  {
253  if(jBlock > iBlock || (iBlock == jBlock && blockCols > blockRows))
254  {
255  densei_ = xpr_.offset(iBlock);
256  densej_ = xpr_.offset(jBlock);
257  if(blockRows > 0)
258  xpr_.checkBlock(iBlock + blockRows - 1);
259  denseRows_ = xpr_.offsetUnchecked(iBlock + blockRows) - densei_;
260  if(blockCols > 0)
261  xpr_.checkBlock(jBlock + blockCols - 1);
262  denseCols_ = xpr_.offsetUnchecked(jBlock + blockCols) - densej_;
263  blockType_ = Plain;
264  }
265  else
266  {
267  densei_ = xpr_.offset(jBlock);
268  densej_ = xpr_.offset(iBlock);
269  if(blockCols > 0)
270  xpr_.checkBlock(jBlock + blockCols - 1);
271  denseRows_ = xpr_.offsetUnchecked(jBlock + blockCols) - densei_;
272  if(blockRows > 0)
273  xpr_.checkBlock(iBlock + blockRows - 1);
274  denseCols_ = xpr_.offsetUnchecked(iBlock + blockRows) - densej_;
275  blockType_ = Transposed;
276  }
277 
278  // Validate that the block does not cross below the diagonal (the indices have already been
279  // flipped above the diagonal for ranges starting below the diagonal).
280  if(densei_ + denseRows_ > densej_ + 1)
281  throw std::invalid_argument("Off-diagonal block ranges may not cross the diagonal");
282  }
283 
284  new (&myBlock_) Eigen::Block<DenseMatrixType>(xpr_.matrix_.block(densei_, densej_, denseRows_, denseCols_));
285  }
286 
287  template<typename ScalarType>
288  inline ScalarType coeffInternal(Index row, Index col) const
289  {
290  // We leave index checking up to the Block class
291  if(blockType_ == Plain)
292  {
293  return myBlock_(row, col);
294  }
295  else if(blockType_ == SelfAdjoint)
296  {
297  if(row <= col)
298  return myBlock_(row, col);
299  else
300  return myBlock_.transpose()(row, col);
301  }
302  else
303  {
304  return myBlock_.transpose()(row, col);
305  }
306  }
307 
308  template<typename OtherSymmetricBlockMatrixType>
309  void _doAssign(const SymmetricBlockMatrixBlockExpr<OtherSymmetricBlockMatrixType>& other)
310  {
311  if(blockType_ == SelfAdjoint)
312  {
313  assert((BlockType)other.blockType() == SelfAdjoint);
314  triangularView() = other.triangularView().nestedExpression();
315  }
316  else if(blockType_ == Plain)
317  {
318  assert((BlockType)other.blockType() == Plain || (BlockType)other.blockType() == Transposed);
319  if((BlockType)other.blockType() == Transposed)
320  myBlock_ = other.myBlock_.transpose();
321  else
322  myBlock_ = other.myBlock_;
323  }
324  else
325  {
326  assert((BlockType)other.blockType() == Plain || (BlockType)other.blockType() == Transposed);
327  if((BlockType)other.blockType() == Transposed)
328  myBlock_.transpose() = other.myBlock_.transpose();
329  else
330  myBlock_.transpose() = other.myBlock_;
331  }
332  }
333 
334 
335  };
336 
337 }
DenseIndex denseRows_
The scalar size of the referenced block.
Definition: SymmetricBlockMatrixBlockExpr.h:52
SymmetricBlockMatrixType & xpr_
The referenced SymmetricBlockMatrix.
Definition: SymmetricBlockMatrixBlockExpr.h:49
SymmetricBlockMatrixBlockExpr(SymmetricBlockMatrixType &blockMatrix, Index iBlock, Index jBlock)
Create a SymmetricBlockMatrixBlockExpr from the specified block of a SymmetricBlockMatrix.
Definition: SymmetricBlockMatrixBlockExpr.h:79
DenseIndex densei_
The scalar indices of the referenced block.
Definition: SymmetricBlockMatrixBlockExpr.h:50
const MATRIX::ConstRowXpr row(const MATRIX &A, size_t j)
Extracts a row view from a matrix that avoids a copy.
Definition: Matrix.h:246
Helper class that uses templates to select between two types based on whether TEST_TYPE is const or n...
Definition: types.h:84
A matrix expression that references a single block of a SymmetricBlockMatrix.
Definition: SymmetricBlockMatrixBlockExpr.h:22
SymmetricBlockMatrixBlockExpr(SymmetricBlockMatrixType &blockMatrix, Index firstBlock, Index blocks, char dummy)
Create a SymmetricBlockMatrixBlockExpr from the specified range of blocks of a SymmetricBlockMatrix.
Definition: SymmetricBlockMatrixBlockExpr.h:96
SymmetricBlockMatrixBlockExpr(SymmetricBlockMatrixType &blockMatrix, Index firstRowBlock, Index firstColBlock, Index rowBlocks, Index colBlocks)
Create a SymmetricBlockMatrixBlockExpr from the specified range of blocks of a SymmetricBlockMatrix.
Definition: SymmetricBlockMatrixBlockExpr.h:87
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition: types.h:74
DenseIndex densej_
The scalar indices of the referenced block.
Definition: SymmetricBlockMatrixBlockExpr.h:51
typedef and functions to augment Eigen's MatrixXd
Definition: SymmetricBlockMatrix.h:40
enum gtsam::SymmetricBlockMatrixBlockExpr::BlockType blockType_
The type of the referenced block, as determined by the block position.
DenseIndex denseCols_
The scalar size of the referenced block.
Definition: SymmetricBlockMatrixBlockExpr.h:53