Eigen-unsupported  5.0.1-dev+284dcc12
 
Loading...
Searching...
No Matches
BlockSparseMatrix.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
5// Copyright (C) 2013 Gael Guennebaud <gael.guennebaud@inria.fr>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11#ifndef EIGEN_SPARSEBLOCKMATRIX_H
12#define EIGEN_SPARSEBLOCKMATRIX_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17namespace Eigen {
57template <typename Scalar_, int _BlockAtCompileTime = Dynamic, int Options_ = ColMajor, typename StorageIndex_ = int>
59
60template <typename BlockSparseMatrixT>
61class BlockSparseMatrixView;
62
63namespace internal {
64template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename Index_>
65struct traits<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, Index_> > {
66 typedef Scalar_ Scalar;
67 typedef Index_ Index;
68 typedef Sparse StorageKind; // FIXME Where is it used ??
69 typedef MatrixXpr XprKind;
70 enum {
71 RowsAtCompileTime = Dynamic,
72 ColsAtCompileTime = Dynamic,
73 MaxRowsAtCompileTime = Dynamic,
74 MaxColsAtCompileTime = Dynamic,
75 BlockSize = _BlockAtCompileTime,
76 Flags = Options_ | NestByRefBit | LvalueBit,
77 CoeffReadCost = NumTraits<Scalar>::ReadCost,
78 SupportedAccessPatterns = InnerRandomAccessPattern
79 };
80};
81template <typename BlockSparseMatrixT>
82struct traits<BlockSparseMatrixView<BlockSparseMatrixT> > {
83 typedef Ref<
84 Matrix<typename BlockSparseMatrixT::Scalar, BlockSparseMatrixT::BlockSize, BlockSparseMatrixT::BlockSize> >
85 Scalar;
86 typedef Ref<
87 Matrix<typename BlockSparseMatrixT::RealScalar, BlockSparseMatrixT::BlockSize, BlockSparseMatrixT::BlockSize> >
88 RealScalar;
89};
90
91// Function object to sort a triplet list
92template <typename Iterator, bool IsColMajor>
93struct TripletComp {
94 typedef typename Iterator::value_type Triplet;
95 bool operator()(const Triplet& a, const Triplet& b) {
96 if (IsColMajor)
97 return ((a.col() == b.col() && a.row() < b.row()) || (a.col() < b.col()));
98 else
99 return ((a.row() == b.row() && a.col() < b.col()) || (a.row() < b.row()));
100 }
101};
102} // end namespace internal
103
104/* Proxy to view the block sparse matrix as a regular sparse matrix */
105template <typename BlockSparseMatrixT>
106class BlockSparseMatrixView : public SparseMatrixBase<BlockSparseMatrixT> {
107 public:
108 typedef Ref<typename BlockSparseMatrixT::BlockScalar> Scalar;
109 typedef Ref<typename BlockSparseMatrixT::BlockRealScalar> RealScalar;
110 typedef typename BlockSparseMatrixT::Index Index;
111 typedef BlockSparseMatrixT Nested;
112 enum {
113 Flags = BlockSparseMatrixT::Options,
114 Options = BlockSparseMatrixT::Options,
115 RowsAtCompileTime = BlockSparseMatrixT::RowsAtCompileTime,
116 ColsAtCompileTime = BlockSparseMatrixT::ColsAtCompileTime,
117 MaxColsAtCompileTime = BlockSparseMatrixT::MaxColsAtCompileTime,
118 MaxRowsAtCompileTime = BlockSparseMatrixT::MaxRowsAtCompileTime
119 };
120
121 public:
122 BlockSparseMatrixView(const BlockSparseMatrixT& spblockmat) : m_spblockmat(spblockmat) {}
123
124 Index outerSize() const { return (Flags & RowMajorBit) == 1 ? this->rows() : this->cols(); }
125 Index cols() const { return m_spblockmat.blockCols(); }
126 Index rows() const { return m_spblockmat.blockRows(); }
127 Scalar coeff(Index row, Index col) { return m_spblockmat.coeff(row, col); }
128 Scalar coeffRef(Index row, Index col) { return m_spblockmat.coeffRef(row, col); }
129 // Wrapper to iterate over all blocks
130 class InnerIterator : public BlockSparseMatrixT::BlockInnerIterator {
131 public:
132 InnerIterator(const BlockSparseMatrixView& mat, Index outer)
133 : BlockSparseMatrixT::BlockInnerIterator(mat.m_spblockmat, outer) {}
134 };
135
136 protected:
137 const BlockSparseMatrixT& m_spblockmat;
138};
139
140// Proxy to view a regular vector as a block vector
141template <typename BlockSparseMatrixT, typename VectorType>
142class BlockVectorView {
143 public:
144 enum {
145 BlockSize = BlockSparseMatrixT::BlockSize,
146 ColsAtCompileTime = VectorType::ColsAtCompileTime,
147 RowsAtCompileTime = VectorType::RowsAtCompileTime,
148 Flags = VectorType::Flags
149 };
150 typedef Ref<const Matrix<typename BlockSparseMatrixT::Scalar, (RowsAtCompileTime == 1) ? 1 : BlockSize,
151 (ColsAtCompileTime == 1) ? 1 : BlockSize> >
152 Scalar;
153 typedef typename BlockSparseMatrixT::Index Index;
154
155 public:
156 BlockVectorView(const BlockSparseMatrixT& spblockmat, const VectorType& vec) : m_spblockmat(spblockmat), m_vec(vec) {}
157 inline Index cols() const { return m_vec.cols(); }
158 inline Index size() const { return m_spblockmat.blockRows(); }
159 inline Scalar coeff(Index bi) const {
160 Index startRow = m_spblockmat.blockRowsIndex(bi);
161 Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
162 return m_vec.middleRows(startRow, rowSize);
163 }
164 inline Scalar coeff(Index bi, Index j) const {
165 Index startRow = m_spblockmat.blockRowsIndex(bi);
166 Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
167 return m_vec.block(startRow, j, rowSize, 1);
168 }
169
170 protected:
171 const BlockSparseMatrixT& m_spblockmat;
172 const VectorType& m_vec;
173};
174
175template <typename VectorType, typename Index>
176class BlockVectorReturn;
177
178// Proxy to view a regular vector as a block vector
179template <typename BlockSparseMatrixT, typename VectorType>
180class BlockVectorReturn {
181 public:
182 enum {
183 ColsAtCompileTime = VectorType::ColsAtCompileTime,
184 RowsAtCompileTime = VectorType::RowsAtCompileTime,
185 Flags = VectorType::Flags
186 };
187 typedef Ref<Matrix<typename VectorType::Scalar, RowsAtCompileTime, ColsAtCompileTime> > Scalar;
188 typedef typename BlockSparseMatrixT::Index Index;
189
190 public:
191 BlockVectorReturn(const BlockSparseMatrixT& spblockmat, VectorType& vec) : m_spblockmat(spblockmat), m_vec(vec) {}
192 inline Index size() const { return m_spblockmat.blockRows(); }
193 inline Scalar coeffRef(Index bi) {
194 Index startRow = m_spblockmat.blockRowsIndex(bi);
195 Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
196 return m_vec.middleRows(startRow, rowSize);
197 }
198 inline Scalar coeffRef(Index bi, Index j) {
199 Index startRow = m_spblockmat.blockRowsIndex(bi);
200 Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
201 return m_vec.block(startRow, j, rowSize, 1);
202 }
203
204 protected:
205 const BlockSparseMatrixT& m_spblockmat;
206 VectorType& m_vec;
207};
208
209// Block version of the sparse dense product
210template <typename Lhs, typename Rhs>
211class BlockSparseTimeDenseProduct;
212
213namespace internal {
214
215template <typename BlockSparseMatrixT, typename VecType>
216struct traits<BlockSparseTimeDenseProduct<BlockSparseMatrixT, VecType> > {
217 typedef Dense StorageKind;
218 typedef MatrixXpr XprKind;
219 typedef typename BlockSparseMatrixT::Scalar Scalar;
220 typedef typename BlockSparseMatrixT::Index Index;
221 enum {
222 RowsAtCompileTime = Dynamic,
223 ColsAtCompileTime = Dynamic,
224 MaxRowsAtCompileTime = Dynamic,
225 MaxColsAtCompileTime = Dynamic,
226 Flags = 0,
227 CoeffReadCost = internal::traits<BlockSparseMatrixT>::CoeffReadCost
228 };
229};
230} // end namespace internal
231
232template <typename Lhs, typename Rhs>
233class BlockSparseTimeDenseProduct : public ProductBase<BlockSparseTimeDenseProduct<Lhs, Rhs>, Lhs, Rhs> {
234 public:
235 EIGEN_PRODUCT_PUBLIC_INTERFACE(BlockSparseTimeDenseProduct)
236
237 BlockSparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs, rhs) {}
238
239 template <typename Dest>
240 void scaleAndAddTo(Dest& dest, const typename Rhs::Scalar& alpha) const {
241 BlockVectorReturn<Lhs, Dest> tmpDest(m_lhs, dest);
242 internal::sparse_time_dense_product(BlockSparseMatrixView<Lhs>(m_lhs), BlockVectorView<Lhs, Rhs>(m_lhs, m_rhs),
243 tmpDest, alpha);
244 }
245
246 private:
247 BlockSparseTimeDenseProduct& operator=(const BlockSparseTimeDenseProduct&);
248};
249
250template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_>
251class BlockSparseMatrix
252 : public SparseMatrixBase<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_> > {
253 public:
254 typedef Scalar_ Scalar;
255 typedef typename NumTraits<Scalar>::Real RealScalar;
256 typedef StorageIndex_ StorageIndex;
257 typedef
258 typename internal::ref_selector<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_> >::type
259 Nested;
260
261 enum {
262 Options = Options_,
263 Flags = Options,
264 BlockSize = _BlockAtCompileTime,
265 RowsAtCompileTime = Dynamic,
266 ColsAtCompileTime = Dynamic,
267 MaxRowsAtCompileTime = Dynamic,
268 MaxColsAtCompileTime = Dynamic,
269 IsVectorAtCompileTime = 0,
270 IsColMajor = Flags & RowMajorBit ? 0 : 1
271 };
274 BlockRealScalar;
275 typedef std::conditional_t<_BlockAtCompileTime == Dynamic, Scalar, BlockScalar> BlockScalarReturnType;
276 typedef BlockSparseMatrix<Scalar, BlockSize, IsColMajor ? ColMajor : RowMajor, StorageIndex> PlainObject;
277
278 public:
279 // Default constructor
280 BlockSparseMatrix()
281 : m_innerBSize(0),
282 m_outerBSize(0),
283 m_innerOffset(0),
284 m_outerOffset(0),
285 m_nonzerosblocks(0),
286 m_values(0),
287 m_blockPtr(0),
288 m_indices(0),
289 m_outerIndex(0),
290 m_blockSize(BlockSize) {}
291
297 : m_innerBSize(IsColMajor ? brow : bcol),
298 m_outerBSize(IsColMajor ? bcol : brow),
299 m_innerOffset(0),
300 m_outerOffset(0),
301 m_nonzerosblocks(0),
302 m_values(0),
303 m_blockPtr(0),
304 m_indices(0),
305 m_outerIndex(0),
306 m_blockSize(BlockSize) {}
307
311 BlockSparseMatrix(const BlockSparseMatrix& other)
312 : m_innerBSize(other.m_innerBSize),
313 m_outerBSize(other.m_outerBSize),
314 m_nonzerosblocks(other.m_nonzerosblocks),
315 m_nonzeros(other.m_nonzeros),
316 m_blockPtr(0),
317 m_blockSize(other.m_blockSize) {
318 // should we allow copying between variable-size blocks and fixed-size blocks ??
319 eigen_assert(m_blockSize == BlockSize && " CAN NOT COPY BETWEEN FIXED-SIZE AND VARIABLE-SIZE BLOCKS");
320
321 std::copy(other.m_innerOffset, other.m_innerOffset + m_innerBSize + 1, m_innerOffset);
322 std::copy(other.m_outerOffset, other.m_outerOffset + m_outerBSize + 1, m_outerOffset);
323 std::copy(other.m_values, other.m_values + m_nonzeros, m_values);
324
325 if (m_blockSize != Dynamic) std::copy(other.m_blockPtr, other.m_blockPtr + m_nonzerosblocks, m_blockPtr);
326
327 std::copy(other.m_indices, other.m_indices + m_nonzerosblocks, m_indices);
328 std::copy(other.m_outerIndex, other.m_outerIndex + m_outerBSize, m_outerIndex);
329 }
330
331 friend void swap(BlockSparseMatrix& first, BlockSparseMatrix& second) {
332 std::swap(first.m_innerBSize, second.m_innerBSize);
333 std::swap(first.m_outerBSize, second.m_outerBSize);
334 std::swap(first.m_innerOffset, second.m_innerOffset);
335 std::swap(first.m_outerOffset, second.m_outerOffset);
336 std::swap(first.m_nonzerosblocks, second.m_nonzerosblocks);
337 std::swap(first.m_nonzeros, second.m_nonzeros);
338 std::swap(first.m_values, second.m_values);
339 std::swap(first.m_blockPtr, second.m_blockPtr);
340 std::swap(first.m_indices, second.m_indices);
341 std::swap(first.m_outerIndex, second.m_outerIndex);
342 std::swap(first.m_BlockSize, second.m_blockSize);
343 }
344
345 BlockSparseMatrix& operator=(BlockSparseMatrix other) {
346 // Copy-and-swap paradigm ... avoid leaked data if thrown
347 swap(*this, other);
348 return *this;
349 }
350
351 // Destructor
352 ~BlockSparseMatrix() {
353 delete[] m_outerIndex;
354 delete[] m_innerOffset;
355 delete[] m_outerOffset;
356 delete[] m_indices;
357 delete[] m_blockPtr;
358 delete[] m_values;
359 }
360
365 template <typename MatrixType>
366 inline BlockSparseMatrix(const MatrixType& spmat) : m_blockSize(BlockSize) {
367 EIGEN_STATIC_ASSERT((m_blockSize != Dynamic), THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE);
368
369 *this = spmat;
370 }
371
380 template <typename MatrixType>
381 inline BlockSparseMatrix& operator=(const MatrixType& spmat) {
382 eigen_assert((m_innerBSize != 0 && m_outerBSize != 0) &&
383 "Trying to assign to a zero-size matrix, call resize() first");
384 eigen_assert(((MatrixType::Options & RowMajorBit) != IsColMajor) && "Wrong storage order");
386 MatrixPatternType blockPattern(blockRows(), blockCols());
387 m_nonzeros = 0;
388
389 // First, compute the number of nonzero blocks and their locations
390 for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
391 // Browse each outer block and compute the structure
392 std::vector<bool> nzblocksFlag(m_innerBSize, false); // Record the existing blocks
393 blockPattern.startVec(bj);
394 for (StorageIndex j = blockOuterIndex(bj); j < blockOuterIndex(bj + 1); ++j) {
395 typename MatrixType::InnerIterator it_spmat(spmat, j);
396 for (; it_spmat; ++it_spmat) {
397 StorageIndex bi = innerToBlock(it_spmat.index()); // Index of the current nonzero block
398 if (!nzblocksFlag[bi]) {
399 // Save the index of this nonzero block
400 nzblocksFlag[bi] = true;
401 blockPattern.insertBackByOuterInnerUnordered(bj, bi) = true;
402 // Compute the total number of nonzeros (including explicit zeros in blocks)
403 m_nonzeros += blockOuterSize(bj) * blockInnerSize(bi);
404 }
405 }
406 } // end current outer block
407 }
408 blockPattern.finalize();
409
410 // Allocate the internal arrays
411 setBlockStructure(blockPattern);
412
413 for (StorageIndex nz = 0; nz < m_nonzeros; ++nz) m_values[nz] = Scalar(0);
414 for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
415 // Now copy the values
416 for (StorageIndex j = blockOuterIndex(bj); j < blockOuterIndex(bj + 1); ++j) {
417 // Browse the outer block column by column (for column-major matrices)
418 typename MatrixType::InnerIterator it_spmat(spmat, j);
419 for (; it_spmat; ++it_spmat) {
420 StorageIndex idx = 0; // Position of this block in the column block
421 StorageIndex bi = innerToBlock(it_spmat.index()); // Index of the current nonzero block
422 // Go to the inner block where this element belongs to
423 while (bi > m_indices[m_outerIndex[bj] + idx]) ++idx; // Not expensive for ordered blocks
424 StorageIndex idxVal; // Get the right position in the array of values for this element
425 if (m_blockSize == Dynamic) {
426 // Offset from all blocks before ...
427 idxVal = m_blockPtr[m_outerIndex[bj] + idx];
428 // ... and offset inside the block
429 idxVal += (j - blockOuterIndex(bj)) * blockOuterSize(bj) + it_spmat.index() - m_innerOffset[bi];
430 } else {
431 // All blocks before
432 idxVal = (m_outerIndex[bj] + idx) * m_blockSize * m_blockSize;
433 // inside the block
434 idxVal += (j - blockOuterIndex(bj)) * m_blockSize + (it_spmat.index() % m_blockSize);
435 }
436 // Insert the value
437 m_values[idxVal] = it_spmat.value();
438 } // end of this column
439 } // end of this block
440 } // end of this outer block
441
442 return *this;
443 }
444
462 template <typename MatrixType>
463 void setBlockStructure(const MatrixType& blockPattern) {
464 resize(blockPattern.rows(), blockPattern.cols());
465 reserve(blockPattern.nonZeros());
466
467 // Browse the block pattern and set up the various pointers
468 m_outerIndex[0] = 0;
469 if (m_blockSize == Dynamic) m_blockPtr[0] = 0;
470 for (StorageIndex nz = 0; nz < m_nonzeros; ++nz) m_values[nz] = Scalar(0);
471 for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
472 // Browse each outer block
473
474 // First, copy and save the indices of nonzero blocks
475 // FIXME : find a way to avoid this ...
476 std::vector<int> nzBlockIdx;
477 typename MatrixType::InnerIterator it(blockPattern, bj);
478 for (; it; ++it) {
479 nzBlockIdx.push_back(it.index());
480 }
481 std::sort(nzBlockIdx.begin(), nzBlockIdx.end());
482
483 // Now, fill block indices and (eventually) pointers to blocks
484 for (StorageIndex idx = 0; idx < nzBlockIdx.size(); ++idx) {
485 StorageIndex offset = m_outerIndex[bj] + idx; // offset in m_indices
486 m_indices[offset] = nzBlockIdx[idx];
487 if (m_blockSize == Dynamic)
488 m_blockPtr[offset] = m_blockPtr[offset - 1] + blockInnerSize(nzBlockIdx[idx]) * blockOuterSize(bj);
489 // There is no blockPtr for fixed-size blocks... not needed !???
490 }
491 // Save the pointer to the next outer block
492 m_outerIndex[bj + 1] = m_outerIndex[bj] + nzBlockIdx.size();
493 }
494 }
495
499 inline void resize(Index brow, Index bcol) {
500 m_innerBSize = IsColMajor ? brow : bcol;
501 m_outerBSize = IsColMajor ? bcol : brow;
502 }
503
509 inline void setBlockSize(Index blockSize) { m_blockSize = blockSize; }
510
520 inline void setBlockLayout(const VectorXi& rowBlocks, const VectorXi& colBlocks) {
521 const VectorXi& innerBlocks = IsColMajor ? rowBlocks : colBlocks;
522 const VectorXi& outerBlocks = IsColMajor ? colBlocks : rowBlocks;
523 eigen_assert(m_innerBSize == innerBlocks.size() && "CHECK THE NUMBER OF ROW OR COLUMN BLOCKS");
524 eigen_assert(m_outerBSize == outerBlocks.size() && "CHECK THE NUMBER OF ROW OR COLUMN BLOCKS");
525 m_outerBSize = outerBlocks.size();
526 // starting index of blocks... cumulative sums
527 m_innerOffset = new StorageIndex[m_innerBSize + 1];
528 m_outerOffset = new StorageIndex[m_outerBSize + 1];
529 m_innerOffset[0] = 0;
530 m_outerOffset[0] = 0;
531 std::partial_sum(&innerBlocks[0], &innerBlocks[m_innerBSize - 1] + 1, &m_innerOffset[1]);
532 std::partial_sum(&outerBlocks[0], &outerBlocks[m_outerBSize - 1] + 1, &m_outerOffset[1]);
533
534 // Compute the total number of nonzeros
535 m_nonzeros = 0;
536 for (StorageIndex bj = 0; bj < m_outerBSize; ++bj)
537 for (StorageIndex bi = 0; bi < m_innerBSize; ++bi) m_nonzeros += outerBlocks[bj] * innerBlocks[bi];
538 }
539
550 inline void reserve(const Index nonzerosblocks) {
551 eigen_assert((m_innerBSize != 0 && m_outerBSize != 0) &&
552 "TRYING TO RESERVE ZERO-SIZE MATRICES, CALL resize() first");
553
554 // FIXME Should free if already allocated
555 m_outerIndex = new StorageIndex[m_outerBSize + 1];
556
557 m_nonzerosblocks = nonzerosblocks;
558 if (m_blockSize != Dynamic) {
559 m_nonzeros = nonzerosblocks * (m_blockSize * m_blockSize);
560 m_blockPtr = 0;
561 } else {
562 // m_nonzeros is already computed in setBlockLayout()
563 m_blockPtr = new StorageIndex[m_nonzerosblocks + 1];
564 }
565 m_indices = new StorageIndex[m_nonzerosblocks + 1];
566 m_values = new Scalar[m_nonzeros];
567 }
568
579 template <typename InputIterator>
580 void setFromTriplets(const InputIterator& begin, const InputIterator& end) {
581 eigen_assert((m_innerBSize != 0 && m_outerBSize != 0) && "ZERO BLOCKS, PLEASE CALL resize() before");
582
583 /* First, sort the triplet list
584 * FIXME This can be unnecessarily expensive since only the inner indices have to be sorted
585 * The best approach is like in SparseMatrix::setFromTriplets()
586 */
587 internal::TripletComp<InputIterator, IsColMajor> tripletcomp;
588 std::sort(begin, end, tripletcomp);
589
590 /* Count the number of rows and column blocks,
591 * and the number of nonzero blocks per outer dimension
592 */
593 VectorXi rowBlocks(m_innerBSize); // Size of each block row
594 VectorXi colBlocks(m_outerBSize); // Size of each block column
595 rowBlocks.setZero();
596 colBlocks.setZero();
597 VectorXi nzblock_outer(m_outerBSize); // Number of nz blocks per outer vector
598 VectorXi nz_outer(m_outerBSize); // Number of nz per outer vector...for variable-size blocks
599 nzblock_outer.setZero();
600 nz_outer.setZero();
601 for (InputIterator it(begin); it != end; ++it) {
602 eigen_assert(it->row() >= 0 && it->row() < this->blockRows() && it->col() >= 0 && it->col() < this->blockCols());
603 eigen_assert((it->value().rows() == it->value().cols() && (it->value().rows() == m_blockSize)) ||
604 (m_blockSize == Dynamic));
605
606 if (m_blockSize == Dynamic) {
607 eigen_assert((rowBlocks[it->row()] == 0 || rowBlocks[it->row()] == it->value().rows()) &&
608 "NON CORRESPONDING SIZES FOR ROW BLOCKS");
609 eigen_assert((colBlocks[it->col()] == 0 || colBlocks[it->col()] == it->value().cols()) &&
610 "NON CORRESPONDING SIZES FOR COLUMN BLOCKS");
611 rowBlocks[it->row()] = it->value().rows();
612 colBlocks[it->col()] = it->value().cols();
613 }
614 nz_outer(IsColMajor ? it->col() : it->row()) += it->value().rows() * it->value().cols();
615 nzblock_outer(IsColMajor ? it->col() : it->row())++;
616 }
617 // Allocate member arrays
618 if (m_blockSize == Dynamic) setBlockLayout(rowBlocks, colBlocks);
619 StorageIndex nzblocks = nzblock_outer.sum();
620 reserve(nzblocks);
621
622 // Temporary markers
623 VectorXi block_id(m_outerBSize); // To be used as a block marker during insertion
624
625 // Setup outer index pointers and markers
626 m_outerIndex[0] = 0;
627 if (m_blockSize == Dynamic) m_blockPtr[0] = 0;
628 for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
629 m_outerIndex[bj + 1] = m_outerIndex[bj] + nzblock_outer(bj);
630 block_id(bj) = m_outerIndex[bj];
631 if (m_blockSize == Dynamic) {
632 m_blockPtr[m_outerIndex[bj + 1]] = m_blockPtr[m_outerIndex[bj]] + nz_outer(bj);
633 }
634 }
635
636 // Fill the matrix
637 for (InputIterator it(begin); it != end; ++it) {
638 StorageIndex outer = IsColMajor ? it->col() : it->row();
639 StorageIndex inner = IsColMajor ? it->row() : it->col();
640 m_indices[block_id(outer)] = inner;
641 StorageIndex block_size = it->value().rows() * it->value().cols();
642 StorageIndex nz_marker = blockPtr(block_id[outer]);
643 memcpy(&(m_values[nz_marker]), it->value().data(), block_size * sizeof(Scalar));
644 if (m_blockSize == Dynamic) {
645 m_blockPtr[block_id(outer) + 1] = m_blockPtr[block_id(outer)] + block_size;
646 }
647 block_id(outer)++;
648 }
649
650 // An alternative when the outer indices are sorted...no need to use an array of markers
651 // for(Index bcol = 0; bcol < m_outerBSize; ++bcol)
652 // {
653 // Index id = 0, id_nz = 0, id_nzblock = 0;
654 // for(InputIterator it(begin); it!=end; ++it)
655 // {
656 // while (id<bcol) // one pass should do the job unless there are empty columns
657 // {
658 // id++;
659 // m_outerIndex[id+1]=m_outerIndex[id];
660 // }
661 // m_outerIndex[id+1] += 1;
662 // m_indices[id_nzblock]=brow;
663 // Index block_size = it->value().rows()*it->value().cols();
664 // m_blockPtr[id_nzblock+1] = m_blockPtr[id_nzblock] + block_size;
665 // id_nzblock++;
666 // memcpy(&(m_values[id_nz]),it->value().data(), block_size*sizeof(Scalar));
667 // id_nz += block_size;
668 // }
669 // while(id < m_outerBSize-1) // Empty columns at the end
670 // {
671 // id++;
672 // m_outerIndex[id+1]=m_outerIndex[id];
673 // }
674 // }
675 }
676
680 inline Index rows() const {
681 // return blockRows();
682 return (IsColMajor ? innerSize() : outerSize());
683 }
684
688 inline Index cols() const {
689 // return blockCols();
690 return (IsColMajor ? outerSize() : innerSize());
691 }
692
693 inline Index innerSize() const {
694 if (m_blockSize == Dynamic)
695 return m_innerOffset[m_innerBSize];
696 else
697 return (m_innerBSize * m_blockSize);
698 }
699
700 inline Index outerSize() const {
701 if (m_blockSize == Dynamic)
702 return m_outerOffset[m_outerBSize];
703 else
704 return (m_outerBSize * m_blockSize);
705 }
707 inline Index blockRows() const { return (IsColMajor ? m_innerBSize : m_outerBSize); }
709 inline Index blockCols() const { return (IsColMajor ? m_outerBSize : m_innerBSize); }
710
711 inline Index outerBlocks() const { return m_outerBSize; }
712 inline Index innerBlocks() const { return m_innerBSize; }
713
715 inline Index outerToBlock(Index outer) const {
716 eigen_assert(outer < outerSize() && "OUTER INDEX OUT OF BOUNDS");
717
718 if (m_blockSize != Dynamic) return (outer / m_blockSize); // Integer division
719
720 StorageIndex b_outer = 0;
721 while (m_outerOffset[b_outer] <= outer) ++b_outer;
722 return b_outer - 1;
723 }
724
725 inline Index innerToBlock(Index inner) const {
726 eigen_assert(inner < innerSize() && "OUTER INDEX OUT OF BOUNDS");
727
728 if (m_blockSize != Dynamic) return (inner / m_blockSize); // Integer division
729
730 StorageIndex b_inner = 0;
731 while (m_innerOffset[b_inner] <= inner) ++b_inner;
732 return b_inner - 1;
733 }
734
739 eigen_assert(brow < blockRows() && "BLOCK ROW INDEX OUT OF BOUNDS");
740 eigen_assert(bcol < blockCols() && "BLOCK nzblocksFlagCOLUMN OUT OF BOUNDS");
741
742 StorageIndex rsize = IsColMajor ? blockInnerSize(brow) : blockOuterSize(bcol);
743 StorageIndex csize = IsColMajor ? blockOuterSize(bcol) : blockInnerSize(brow);
744 StorageIndex inner = IsColMajor ? brow : bcol;
745 StorageIndex outer = IsColMajor ? bcol : brow;
746 StorageIndex offset = m_outerIndex[outer];
747 while (offset < m_outerIndex[outer + 1] && m_indices[offset] != inner) offset++;
748 if (m_indices[offset] == inner) {
749 return Map<BlockScalar>(&(m_values[blockPtr(offset)]), rsize, csize);
750 } else {
751 // FIXME the block does not exist, Insert it !!!!!!!!!
752 eigen_assert("DYNAMIC INSERTION IS NOT YET SUPPORTED");
753 }
754 }
755
760 eigen_assert(brow < blockRows() && "BLOCK ROW INDEX OUT OF BOUNDS");
761 eigen_assert(bcol < blockCols() && "BLOCK COLUMN OUT OF BOUNDS");
762
763 StorageIndex rsize = IsColMajor ? blockInnerSize(brow) : blockOuterSize(bcol);
764 StorageIndex csize = IsColMajor ? blockOuterSize(bcol) : blockInnerSize(brow);
765 StorageIndex inner = IsColMajor ? brow : bcol;
766 StorageIndex outer = IsColMajor ? bcol : brow;
767 StorageIndex offset = m_outerIndex[outer];
768 while (offset < m_outerIndex[outer + 1] && m_indices[offset] != inner) offset++;
769 if (m_indices[offset] == inner) {
770 return Map<const BlockScalar>(&(m_values[blockPtr(offset)]), rsize, csize);
771 } else
772 // return BlockScalar::Zero(rsize, csize);
773 eigen_assert("NOT YET SUPPORTED");
774 }
775
776 // Block Matrix times vector product
777 template <typename VecType>
778 BlockSparseTimeDenseProduct<BlockSparseMatrix, VecType> operator*(const VecType& lhs) const {
779 return BlockSparseTimeDenseProduct<BlockSparseMatrix, VecType>(*this, lhs);
780 }
781
783 inline Index nonZerosBlocks() const { return m_nonzerosblocks; }
785 inline Index nonZeros() const { return m_nonzeros; }
786
787 inline BlockScalarReturnType* valuePtr() { return static_cast<BlockScalarReturnType*>(m_values); }
788 // inline Scalar *valuePtr(){ return m_values; }
789 inline StorageIndex* innerIndexPtr() { return m_indices; }
790 inline const StorageIndex* innerIndexPtr() const { return m_indices; }
791 inline StorageIndex* outerIndexPtr() { return m_outerIndex; }
792 inline const StorageIndex* outerIndexPtr() const { return m_outerIndex; }
793
795 inline bool isCompressed() const { return true; }
799 inline Index blockRowsIndex(Index bi) const { return IsColMajor ? blockInnerIndex(bi) : blockOuterIndex(bi); }
800
804 inline Index blockColsIndex(Index bj) const { return IsColMajor ? blockOuterIndex(bj) : blockInnerIndex(bj); }
805
806 inline Index blockOuterIndex(Index bj) const {
807 return (m_blockSize == Dynamic) ? m_outerOffset[bj] : (bj * m_blockSize);
808 }
809 inline Index blockInnerIndex(Index bi) const {
810 return (m_blockSize == Dynamic) ? m_innerOffset[bi] : (bi * m_blockSize);
811 }
812
813 // Not needed ???
814 inline Index blockInnerSize(Index bi) const {
815 return (m_blockSize == Dynamic) ? (m_innerOffset[bi + 1] - m_innerOffset[bi]) : m_blockSize;
816 }
817 inline Index blockOuterSize(Index bj) const {
818 return (m_blockSize == Dynamic) ? (m_outerOffset[bj + 1] - m_outerOffset[bj]) : m_blockSize;
819 }
820
824 class InnerIterator; // Browse column by column
825
829 class BlockInnerIterator; // Browse block by block
830
831 friend std::ostream& operator<<(std::ostream& s, const BlockSparseMatrix& m) {
832 for (StorageIndex j = 0; j < m.outerBlocks(); ++j) {
833 BlockInnerIterator itb(m, j);
834 for (; itb; ++itb) {
835 s << "(" << itb.row() << ", " << itb.col() << ")\n";
836 s << itb.value() << "\n";
837 }
838 }
839 s << std::endl;
840 return s;
841 }
842
846 Index blockPtr(Index id) const {
847 if (m_blockSize == Dynamic)
848 return m_blockPtr[id];
849 else
850 return id * m_blockSize * m_blockSize;
851 // return blockDynIdx(id, std::conditional_t<(BlockSize==Dynamic), internal::true_type, internal::false_type>());
852 }
853
854 protected:
855 // inline Index blockDynIdx(Index id, internal::true_type) const
856 // {
857 // return m_blockPtr[id];
858 // }
859 // inline Index blockDynIdx(Index id, internal::false_type) const
860 // {
861 // return id * BlockSize * BlockSize;
862 // }
863
864 // To be implemented
865 // Insert a block at a particular location... need to make a room for that
866 Map<BlockScalar> insert(Index brow, Index bcol);
867
868 Index m_innerBSize; // Number of block rows
869 Index m_outerBSize; // Number of block columns
870 StorageIndex* m_innerOffset; // Starting index of each inner block (size m_innerBSize+1)
871 StorageIndex* m_outerOffset; // Starting index of each outer block (size m_outerBSize+1)
872 Index m_nonzerosblocks; // Total nonzeros blocks (lower than m_innerBSize x m_outerBSize)
873 Index m_nonzeros; // Total nonzeros elements
874 Scalar* m_values; // Values stored block column after block column (size m_nonzeros)
875 StorageIndex* m_blockPtr; // Pointer to the beginning of each block in m_values, size m_nonzeroblocks ... null for
876 // fixed-size blocks
877 StorageIndex* m_indices; // Inner block indices, size m_nonzerosblocks ... OK
878 StorageIndex* m_outerIndex; // Starting pointer of each block column in m_indices (size m_outerBSize)... OK
879 Index m_blockSize; // Size of a block for fixed-size blocks, otherwise -1
880};
881
882template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_>
883class BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_>::BlockInnerIterator {
884 public:
885 enum { Flags = Options_ };
886
887 BlockInnerIterator(const BlockSparseMatrix& mat, const Index outer)
888 : m_mat(mat), m_outer(outer), m_id(mat.m_outerIndex[outer]), m_end(mat.m_outerIndex[outer + 1]) {}
889
890 inline BlockInnerIterator& operator++() {
891 m_id++;
892 return *this;
893 }
894
895 inline const Map<const BlockScalar> value() const {
896 return Map<const BlockScalar>(&(m_mat.m_values[m_mat.blockPtr(m_id)]), rows(), cols());
897 }
898 inline Map<BlockScalar> valueRef() {
899 return Map<BlockScalar>(&(m_mat.m_values[m_mat.blockPtr(m_id)]), rows(), cols());
900 }
901 // Block inner index
902 inline Index index() const { return m_mat.m_indices[m_id]; }
903 inline Index outer() const { return m_outer; }
904 // block row index
905 inline Index row() const { return index(); }
906 // block column index
907 inline Index col() const { return outer(); }
908 // FIXME Number of rows in the current block
909 inline Index rows() const {
910 return (m_mat.m_blockSize == Dynamic) ? (m_mat.m_innerOffset[index() + 1] - m_mat.m_innerOffset[index()])
911 : m_mat.m_blockSize;
912 }
913 // Number of columns in the current block ...
914 inline Index cols() const {
915 return (m_mat.m_blockSize == Dynamic) ? (m_mat.m_outerOffset[m_outer + 1] - m_mat.m_outerOffset[m_outer])
916 : m_mat.m_blockSize;
917 }
918 inline operator bool() const { return (m_id < m_end); }
919
920 protected:
921 const BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex>& m_mat;
922 const Index m_outer;
923 Index m_id;
924 Index m_end;
925};
926
927template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_>
928class BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_>::InnerIterator {
929 public:
930 InnerIterator(const BlockSparseMatrix& mat, Index outer)
931 : m_mat(mat),
932 m_outerB(mat.outerToBlock(outer)),
933 m_outer(outer),
934 itb(mat, mat.outerToBlock(outer)),
935 m_offset(outer - mat.blockOuterIndex(m_outerB)) {
936 if (itb) {
937 m_id = m_mat.blockInnerIndex(itb.index());
938 m_start = m_id;
939 m_end = m_mat.blockInnerIndex(itb.index() + 1);
940 }
941 }
942 inline InnerIterator& operator++() {
943 m_id++;
944 if (m_id >= m_end) {
945 ++itb;
946 if (itb) {
947 m_id = m_mat.blockInnerIndex(itb.index());
948 m_start = m_id;
949 m_end = m_mat.blockInnerIndex(itb.index() + 1);
950 }
951 }
952 return *this;
953 }
954 inline const Scalar& value() const { return itb.value().coeff(m_id - m_start, m_offset); }
955 inline Scalar& valueRef() { return itb.valueRef().coeff(m_id - m_start, m_offset); }
956 inline Index index() const { return m_id; }
957 inline Index outer() const { return m_outer; }
958 inline Index col() const { return outer(); }
959 inline Index row() const { return index(); }
960 inline operator bool() const { return itb; }
961
962 protected:
963 const BlockSparseMatrix& m_mat;
964 const Index m_outer;
965 const Index m_outerB;
966 BlockInnerIterator itb; // Iterator through the blocks
967 const Index m_offset; // Position of this column in the block
968 Index m_start; // starting inner index of this block
969 Index m_id; // current inner index in the block
970 Index m_end; // starting inner index of the next block
971};
972} // end namespace Eigen
973
974#endif // EIGEN_SPARSEBLOCKMATRIX_H
A versatile sparse matrix representation where each element is a block.
Definition BlockSparseMatrix.h:252
Ref< BlockScalar > coeffRef(Index brow, Index bcol)
Definition BlockSparseMatrix.h:738
Index innerToBlock(Index inner) const
Definition BlockSparseMatrix.h:725
void setBlockStructure(const MatrixType &blockPattern)
Set the nonzero block pattern of the matrix.
Definition BlockSparseMatrix.h:463
Index blockCols() const
Definition BlockSparseMatrix.h:709
BlockSparseMatrix(Index brow, Index bcol)
Construct and resize.
Definition BlockSparseMatrix.h:296
Index blockPtr(Index id) const
Definition BlockSparseMatrix.h:846
void reserve(const Index nonzerosblocks)
Allocate the internal array of pointers to blocks and their inner indices.
Definition BlockSparseMatrix.h:550
Index outerToBlock(Index outer) const
Definition BlockSparseMatrix.h:715
Index blockRowsIndex(Index bi) const
Definition BlockSparseMatrix.h:799
Index cols() const
Definition BlockSparseMatrix.h:688
BlockSparseMatrix(const MatrixType &spmat)
Constructor from a sparse matrix.
Definition BlockSparseMatrix.h:366
Index rows() const
Definition BlockSparseMatrix.h:680
void setFromTriplets(const InputIterator &begin, const InputIterator &end)
Fill values in a matrix from a triplet list.
Definition BlockSparseMatrix.h:580
void setBlockLayout(const VectorXi &rowBlocks, const VectorXi &colBlocks)
Set the row and column block layouts,.
Definition BlockSparseMatrix.h:520
Index nonZeros() const
Definition BlockSparseMatrix.h:785
BlockSparseMatrix(const BlockSparseMatrix &other)
Copy-constructor.
Definition BlockSparseMatrix.h:311
Index blockRows() const
Definition BlockSparseMatrix.h:707
void resize(Index brow, Index bcol)
Set the number of rows and columns blocks.
Definition BlockSparseMatrix.h:499
BlockSparseMatrix & operator=(const MatrixType &spmat)
Assignment from a sparse matrix with the same storage order.
Definition BlockSparseMatrix.h:381
Map< const BlockScalar > coeff(Index brow, Index bcol) const
Definition BlockSparseMatrix.h:759
bool isCompressed() const
for compatibility purposes with the SparseMatrix class
Definition BlockSparseMatrix.h:795
Index blockColsIndex(Index bj) const
Definition BlockSparseMatrix.h:804
Index nonZerosBlocks() const
Definition BlockSparseMatrix.h:783
void setBlockSize(Index blockSize)
set the block size at runtime for fixed-size block layout
Definition BlockSparseMatrix.h:509
Derived & setZero(Index rows, Index cols)
const unsigned int LvalueBit
const unsigned int RowMajorBit
Matrix< int, Dynamic, 1 > VectorXi
Namespace containing all symbols from the Eigen library.
std::enable_if_t< std::is_base_of< DenseBase< std::decay_t< DerivedA > >, std::decay_t< DerivedA > >::value &&std::is_base_of< DenseBase< std::decay_t< DerivedB > >, std::decay_t< DerivedB > >::value, void > swap(DerivedA &&a, DerivedB &&b)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
const Product< Inverse< PermutationType >, SparseDerived, AliasFreeProduct > operator*(const InverseImpl< PermutationType, PermutationStorage > &tperm, const SparseMatrixBase< SparseDerived > &matrix)
const int Dynamic