opensurgsim
SparseMatrix.h
Go to the documentation of this file.
1 // This file is a part of the OpenSurgSim project.
2 // Copyright 2012-2015, SimQuest Solutions Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
18 
19 #ifndef SURGSIM_MATH_SPARSEMATRIX_H
20 #define SURGSIM_MATH_SPARSEMATRIX_H
21 
22 #include <Eigen/Sparse>
23 
25 #include "SurgSim/Math/Matrix.h"
26 
27 namespace SurgSim
28 {
29 namespace Math
30 {
32 typedef Eigen::SparseMatrix<double> SparseMatrix;
33 
38 template < class DerivedSub, class SparseType,
39  int StorageOrder =
40  ((SparseType::Flags & Eigen::RowMajorBit) == Eigen::RowMajorBit) ? Eigen::RowMajor : Eigen::ColMajor >
41 class Operation
42 {
43 public :
44  typedef typename SparseType::Scalar T;
45  typedef typename SparseType::StorageIndex StorageIndex;
46 
53  void assign(T* ptr, StorageIndex start, Eigen::Index n, Eigen::Index m,
54  const Eigen::Ref<const DerivedSub>& subMatrix, Eigen::Index colRowId) {}
55 
59  void assign(T* ptr, const T& value) {}
60 
67  void add(T* ptr, StorageIndex start, Eigen::Index n, Eigen::Index m,
68  const Eigen::Ref<const DerivedSub>& subMatrix, Eigen::Index colRowId) {}
69 
73  void add(T* ptr, const T& value) {}
74 };
75 
77 template <class DerivedSub, class SparseType>
78 class Operation<DerivedSub, SparseType, Eigen::ColMajor>
79 {
80 public:
81  typedef typename SparseType::Scalar T;
82  typedef typename SparseType::StorageIndex StorageIndex;
83 
84  void assign(T* ptr, StorageIndex start, Eigen::Index n, Eigen::Index m,
85  const Eigen::Ref<const DerivedSub>& subMatrix, Eigen::Index colRowId)
86  {
87  typedef Eigen::Matrix < T, Eigen::Dynamic, 1, Eigen::DontAlign | Eigen::ColMajor > ColVector;
88 
89  // ptr[start] is the 1st element in the column
90  // The elements exists and are contiguous in memory, we use Eigen::Map functionality to optimize the operation
91  Eigen::Map<ColVector>(&ptr[start], n).operator = (subMatrix.col(colRowId).segment(0, n));
92  }
93 
94  void assign(T* ptr, const T& value)
95  {
96  *ptr = value;
97  }
98 
99  void add(T* ptr, StorageIndex start, Eigen::Index n, Eigen::Index m,
100  const Eigen::Ref<const DerivedSub>& subMatrix, Eigen::Index colRowId)
101  {
102  typedef Eigen::Matrix < T, Eigen::Dynamic, 1, Eigen::DontAlign | Eigen::ColMajor > ColVector;
103 
104  // ptr[start] is the 1st element in the column
105  // The elements exists and are contiguous in memory, we use Eigen::Map functionality to optimize the operation
106  Eigen::Map<ColVector>(&ptr[start], n).operator += (subMatrix.col(colRowId).segment(0, n));
107  }
108 
109  void add(T* ptr, const T& value)
110  {
111  *ptr += value;
112  }
113 };
114 
116 template <class DerivedSub, class SparseType>
117 class Operation<DerivedSub, SparseType, Eigen::RowMajor>
118 {
119 public:
120  typedef typename SparseType::Scalar T;
121  typedef typename SparseType::StorageIndex StorageIndex;
122 
123  void assign(T* ptr, StorageIndex start, Eigen::Index n, Eigen::Index m,
124  const Eigen::Ref<const DerivedSub>& subMatrix, Eigen::Index colRowId)
125  {
126  typedef Eigen::Matrix < T, 1, Eigen::Dynamic, Eigen::DontAlign | Eigen::RowMajor > RowVector;
127 
128  // ptr[start] is the 1st element in the row
129  // The elements exists and are contiguous in memory, we use Eigen::Map functionality to optimize the operation
130  Eigen::Map<RowVector>(&ptr[start], m).operator = (subMatrix.row(colRowId).segment(0, m));
131  }
132 
133  void assign(T* ptr, const T& value)
134  {
135  *ptr = value;
136  }
137 
138  void add(T* ptr, StorageIndex start, Eigen::Index n, Eigen::Index m,
139  const Eigen::Ref<const DerivedSub>& subMatrix, Eigen::Index colRowId)
140  {
141  typedef Eigen::Matrix < T, 1, Eigen::Dynamic, Eigen::DontAlign | Eigen::RowMajor > RowVector;
142 
143  // ptr[start] is the 1st element in the row
144  // The elements exists and are contiguous in memory, we use Eigen::Map functionality to optimize the operation
145  Eigen::Map<RowVector>(&ptr[start], m).operator += (subMatrix.row(colRowId).segment(0, m));
146  }
147 
148  void add(T* ptr, const T& value)
149  {
150  *ptr += value;
151  }
152 };
153 
178 template <int Opt, typename StorageIndex>
179 void blockWithSearch(const Eigen::Ref<const Matrix>& subMatrix,
180  Eigen::Index rowStart, Eigen::Index columnStart, Eigen::Index n, Eigen::Index m,
181  Eigen::SparseMatrix<double, Opt, StorageIndex>* matrix,
182  void (Operation<Matrix, Eigen::SparseMatrix<double, Opt, StorageIndex>>::*op)
183  (double*, StorageIndex, Eigen::Index, Eigen::Index, const Eigen::Ref<const Matrix>&, Eigen::Index))
184 {
186  SURGSIM_ASSERT(nullptr != matrix) << "Invalid recipient matrix, nullptr found";
187 
188  SURGSIM_ASSERT(subMatrix.rows() >= n) << "subMatrix doesn't have enough rows";
189  SURGSIM_ASSERT(subMatrix.cols() >= m) << "subMatrix doesn't have enough columns";
190 
191  SURGSIM_ASSERT(matrix->rows() >= rowStart + n) << "The block is out of range in matrix";
192  SURGSIM_ASSERT(matrix->cols() >= columnStart + m) << "The block is out of range in matrix";
193  SURGSIM_ASSERT(matrix->valuePtr() != nullptr) << "The matrix is not initialized correctly, null pointer to values";
194 
195  double* ptr = matrix->valuePtr();
196  const StorageIndex* innerIndices = matrix->innerIndexPtr();
197  const StorageIndex* outerIndices = matrix->outerIndexPtr();
198 
199  using Eigen::Index;
200  const Index outerStart = (Opt == Eigen::ColMajor ? columnStart : rowStart);
201  const Index innerStart = (Opt == Eigen::ColMajor ? rowStart : columnStart);
202  const Index outerSize = (Opt == Eigen::ColMajor ? m : n);
203  const Index innerSize = (Opt == Eigen::ColMajor ? n : m);
204 
205  for (Index outerLoop = 0; outerLoop < outerSize; ++outerLoop)
206  {
207  // outerIndices[outerStart + outerLoop] is the index in ptr and innerIndices of the first non-zero element in
208  // the outer element (outerStart + outerLoop)
209  const StorageIndex innerStartIdInCurrentOuter = outerIndices[outerStart + outerLoop];
210  const StorageIndex innerStartIdInNextOuter = outerIndices[outerStart + outerLoop + 1];
211 
212  // Look for the index of innerStart in this outer (the column/row may contain elements before)
213  StorageIndex innerFirstElement;
214  if (static_cast<Index>(innerIndices[innerStartIdInCurrentOuter]) == innerStart)
215  {
216  innerFirstElement = innerStartIdInCurrentOuter;
217  }
218  else
219  {
220  innerFirstElement = static_cast<StorageIndex>(matrix->data().searchLowerIndex(
221  static_cast<Index>(innerStartIdInCurrentOuter), static_cast<Index>(innerStartIdInNextOuter) - 1,
222  innerStart));
223  }
224 
225  // Make sure we actually found the 1st element of the block in this outer
226  SURGSIM_ASSERT(static_cast<Index>(innerIndices[innerFirstElement]) == innerStart) <<
227  "matrix is missing an element of the block (1st element on a row/column)";
228 
229  // Make sure that we are not going to write out of the range...
230  // i.e. The column/row (starting at the beginning of the block) has at least innerSize elements
231  SURGSIM_ASSERT(innerSize <= static_cast<Index>(innerStartIdInNextOuter - innerFirstElement)) <<
232  "matrix is missing elements of the block (but not the 1st element on a row/column)";
233 
234  // Make sure that the last element corresponding to the block size has the expected index
235  SURGSIM_ASSERT((innerStart + innerSize - 1) == \
236  static_cast<Index>(innerIndices[static_cast<Index>(innerFirstElement) + innerSize - 1])) <<
237  "The last element of the block does not have the expected index. " <<
238  "The matrix is missing elements of the block (but not the 1st element on a row/column)";
239 
240  (operation.*op)(ptr, innerFirstElement, n, m, subMatrix, outerLoop);
241  }
242 }
243 
266 template <int Opt, typename StorageIndex>
267 void blockOperation(const Eigen::Ref<const Matrix>& subMatrix, Eigen::Index rowStart, Eigen::Index columnStart,
268  Eigen::SparseMatrix<double, Opt, StorageIndex>* matrix,
269  void (Operation<Matrix, Eigen::SparseMatrix<double, Opt, StorageIndex>>::*op)(double*, const double&))
270 {
272  SURGSIM_ASSERT(nullptr != matrix) << "Invalid recipient matrix, nullptr found";
273 
274  using Eigen::Index;
275  Index n = subMatrix.rows();
276  Index m = subMatrix.cols();
277  SURGSIM_ASSERT(matrix->rows() >= rowStart + n) << "The block is out of range in matrix";
278  SURGSIM_ASSERT(matrix->cols() >= columnStart + m) << "The block is out of range in matrix";
279 
280  for (Index row = 0; row < n; ++row)
281  {
282  for (Index column = 0; column < m; ++column)
283  {
284  (operation.*op)(&matrix->coeffRef(rowStart + row, columnStart + column), subMatrix(row, column));
285  }
286  }
287 }
288 
296 template <int Opt, typename StorageIndex>
297 void addSubMatrix(const Eigen::Ref<const Matrix>& subMatrix, Eigen::Index blockIdRow,
298  Eigen::Index blockIdCol, Eigen::SparseMatrix<double, Opt, StorageIndex>* matrix)
299 {
300  blockOperation(subMatrix, subMatrix.rows() * blockIdRow, subMatrix.cols() * blockIdCol, matrix,
302 }
303 
311 template <int Opt, typename StorageIndex>
312 void addSubMatrixNoInitialize(const Eigen::Ref<const Matrix>& subMatrix, Eigen::Index blockIdRow,
313  Eigen::Index blockIdCol, Eigen::SparseMatrix<double, Opt, StorageIndex>* matrix)
314 {
315  blockWithSearch(subMatrix, subMatrix.rows() * blockIdRow, subMatrix.cols() * blockIdCol,
316  subMatrix.rows(), subMatrix.cols(), matrix,
318 }
319 
326 template <int Opt, typename StorageIndex>
327 void assignSubMatrix(const Eigen::Ref<const Matrix>& subMatrix, Eigen::Index blockIdRow, Eigen::Index blockIdCol,
328  Eigen::SparseMatrix<double, Opt, StorageIndex>* matrix)
329 {
330  blockOperation(subMatrix, subMatrix.rows() * blockIdRow, subMatrix.cols() * blockIdCol, matrix,
332 }
333 
340 template <int Opt, typename StorageIndex>
341 void assignSubMatrixNoInitialize(const Eigen::Ref<const Matrix>& subMatrix,
342  Eigen::Index blockIdRow, Eigen::Index blockIdCol, Eigen::SparseMatrix<double, Opt, StorageIndex>* matrix)
343 {
344  blockWithSearch(subMatrix, subMatrix.rows() * blockIdRow, subMatrix.cols() * blockIdCol,
345  subMatrix.rows(), subMatrix.cols(), matrix,
347 }
348 
352 template <typename T, int Opt, typename StorageIndex>
353 void zeroRow(Eigen::Index row, Eigen::SparseMatrix<T, Opt, StorageIndex>* matrix)
354 {
355  for (Eigen::Index column = 0; column < matrix->cols(); ++column)
356  {
357  if (matrix->coeff(row, column))
358  {
359  matrix->coeffRef(row, column) = 0;
360  }
361  }
362 }
363 
367 template <typename T, int Opt, typename StorageIndex>
368 inline void zeroColumn(Eigen::Index column, Eigen::SparseMatrix<T, Opt, StorageIndex>* matrix)
369 {
370  for (Eigen::Index row = 0; row < matrix->rows(); ++row)
371  {
372  if (matrix->coeff(row, column))
373  {
374  matrix->coeffRef(row, column) = 0;
375  }
376  }
377 }
378 
383 template <typename T, int Opt, typename StorageIndex>
384 inline void clearMatrix(Eigen::SparseMatrix<T, Opt, StorageIndex>* matrix)
385 {
386  SURGSIM_ASSERT(matrix->isCompressed()) << "Invalid matrix. Matrix must be in compressed form.";
387  T* ptr = matrix->valuePtr();
388  for (Eigen::Index value = 0; value < matrix->nonZeros(); ++value)
389  {
390  *ptr = 0;
391  ++ptr;
392  }
393 }
394 
395 }; // namespace Math
396 }; // namespace SurgSim
397 
398 #endif // SURGSIM_MATH_SPARSEMATRIX_H
Wraps glewInit() to separate the glew opengl definitions from the osg opengl definitions only imgui n...
Definition: AddRandomSphereBehavior.cpp:36
Helper class to run operation a column/row of a matrix to a chunk of memory where the size is dynamic...
Definition: SparseMatrix.h:41
void zeroColumn(size_t column, Eigen::DenseBase< Derived > *matrix)
Helper method to zero a column of a matrix.
Definition: Matrix.h:235
void add(T *ptr, StorageIndex start, Eigen::Index n, Eigen::Index m, const Eigen::Ref< const DerivedSub > &subMatrix, Eigen::Index colRowId)
Do the addition of a row/column of a matrix to a chunk of memory.
Definition: SparseMatrix.h:67
Eigen::SparseMatrix< double > SparseMatrix
A sparse matrix.
Definition: SparseMatrix.h:32
void assignSubMatrix(const Eigen::Ref< const Matrix > &subMatrix, Eigen::Index blockIdRow, Eigen::Index blockIdCol, Eigen::SparseMatrix< double, Opt, StorageIndex > *matrix)
Assign a dense sub-matrix into a matrix that may need the memory locations to be initialized.
Definition: SparseMatrix.h:327
Definition: Aabb.h:118
#define SURGSIM_ASSERT(condition)
Assert that condition is true.
Definition: Assert.h:77
void add(T *ptr, const T &value)
Do the addition of a single matrix element (operator +=)
Definition: SparseMatrix.h:73
void assignSubMatrixNoInitialize(const Eigen::Ref< const Matrix > &subMatrix, Eigen::Index blockIdRow, Eigen::Index blockIdCol, Eigen::SparseMatrix< double, Opt, StorageIndex > *matrix)
Assign a dense sub-matrix into a sparse matrix that does not need the memory locations to be initiali...
Definition: SparseMatrix.h:341
void blockWithSearch(const Eigen::Ref< const Matrix > &subMatrix, Eigen::Index rowStart, Eigen::Index columnStart, Eigen::Index n, Eigen::Index m, Eigen::SparseMatrix< double, Opt, StorageIndex > *matrix, void(Operation< Matrix, Eigen::SparseMatrix< double, Opt, StorageIndex >>::*op)(double *, StorageIndex, Eigen::Index, Eigen::Index, const Eigen::Ref< const Matrix > &, Eigen::Index))
Runs a given operation on a SparseMatrix block(i, j, n, m) from a (n x m) &#39;subMatrix&#39; with searching ...
Definition: SparseMatrix.h:179
void addSubMatrix(const SubMatrix &subMatrix, size_t blockIdRow, size_t blockIdCol, size_t blockSizeRow, size_t blockSizeCol, Matrix *matrix)
Helper method to add a sub-matrix into a matrix, for the sake of clarity.
Definition: Matrix.h:157
void zeroRow(size_t row, Eigen::DenseBase< Derived > *matrix)
Helper method to zero a row of a matrix.
Definition: Matrix.h:225
void assign(T *ptr, StorageIndex start, Eigen::Index n, Eigen::Index m, const Eigen::Ref< const DerivedSub > &subMatrix, Eigen::Index colRowId)
Do the assignment of a row/column of a matrix to a chunk of memory.
Definition: SparseMatrix.h:53
Definitions of small fixed-size square matrix types.
void blockOperation(const Eigen::Ref< const Matrix > &subMatrix, Eigen::Index rowStart, Eigen::Index columnStart, Eigen::SparseMatrix< double, Opt, StorageIndex > *matrix, void(Operation< Matrix, Eigen::SparseMatrix< double, Opt, StorageIndex >>::*op)(double *, const double &))
Runs a given operation on a SparseMatrix block(i, j, n, m) from a (n x m) &#39;subMatrix&#39; with searching ...
Definition: SparseMatrix.h:267
The header that provides the assertion API.
void addSubMatrixNoInitialize(const Eigen::Ref< const Matrix > &subMatrix, Eigen::Index blockIdRow, Eigen::Index blockIdCol, Eigen::SparseMatrix< double, Opt, StorageIndex > *matrix)
Add a dense sub-matrix into a sparse matrix that does not need the memory locations to be initialized...
Definition: SparseMatrix.h:312
void assign(T *ptr, const T &value)
Do the assignment of a single matrix element (operator =)
Definition: SparseMatrix.h:59
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > Matrix
A dynamic size matrix.
Definition: Matrix.h:65
void clearMatrix(Eigen::SparseMatrix< T, Opt, StorageIndex > *matrix)
Helper method to zero all entries of a matrix specialized for Sparse Matrices.
Definition: SparseMatrix.h:384