2013-09-20 18:54:17 +02:00
|
|
|
// This file is part of Eigen, a lightweight C++ template library
|
|
|
|
|
// for linear algebra.
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
|
|
|
|
|
// Copyright (C) 2013 Gael Guennebaud <gael.guennebaud@inria.fr>
|
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla
|
|
|
|
|
// Public License v. 2.0. If a copy of the MPL was not distributed
|
|
|
|
|
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
|
|
#ifndef EIGEN_SPARSEBLOCKMATRIX_H
|
|
|
|
|
#define EIGEN_SPARSEBLOCKMATRIX_H
|
|
|
|
|
|
2023-08-21 16:25:22 +00:00
|
|
|
// IWYU pragma: private
|
2021-09-10 19:12:26 +00:00
|
|
|
#include "./InternalHeaderCheck.h"
|
|
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
namespace Eigen {
|
|
|
|
|
/** \ingroup SparseCore_Module
|
|
|
|
|
*
|
|
|
|
|
* \class BlockSparseMatrix
|
|
|
|
|
*
|
|
|
|
|
* \brief A versatile sparse matrix representation where each element is a block
|
|
|
|
|
*
|
|
|
|
|
* This class provides routines to manipulate block sparse matrices stored in a
|
|
|
|
|
* BSR-like representation. There are two main types :
|
|
|
|
|
*
|
|
|
|
|
* 1. All blocks have the same number of rows and columns, called block size
|
|
|
|
|
* in the following. In this case, if this block size is known at compile time,
|
|
|
|
|
* it can be given as a template parameter like
|
|
|
|
|
* \code
|
|
|
|
|
* BlockSparseMatrix<Scalar, 3, ColMajor> bmat(b_rows, b_cols);
|
|
|
|
|
* \endcode
|
|
|
|
|
* Here, bmat is a b_rows x b_cols block sparse matrix
|
|
|
|
|
* where each coefficient is a 3x3 dense matrix.
|
|
|
|
|
* If the block size is fixed but will be given at runtime,
|
|
|
|
|
* \code
|
|
|
|
|
* BlockSparseMatrix<Scalar, Dynamic, ColMajor> bmat(b_rows, b_cols);
|
|
|
|
|
* bmat.setBlockSize(block_size);
|
|
|
|
|
* \endcode
|
|
|
|
|
*
|
|
|
|
|
* 2. The second case is for variable-block sparse matrices.
|
|
|
|
|
* Here each block has its own dimensions. The only restriction is that all the blocks
|
|
|
|
|
* in a row (resp. a column) should have the same number of rows (resp. of columns).
|
|
|
|
|
* It is thus required in this case to describe the layout of the matrix by calling
|
|
|
|
|
* setBlockLayout(rowBlocks, colBlocks).
|
|
|
|
|
*
|
|
|
|
|
* In any of the previous case, the matrix can be filled by calling setFromTriplets().
|
|
|
|
|
* A regular sparse matrix can be converted to a block sparse matrix and vice versa.
|
|
|
|
|
* It is obviously required to describe the block layout beforehand by calling either
|
|
|
|
|
* setBlockSize() for fixed-size blocks or setBlockLayout for variable-size blocks.
|
|
|
|
|
*
|
2021-08-04 22:41:52 +00:00
|
|
|
* \tparam Scalar_ The Scalar type
|
2013-09-20 18:54:17 +02:00
|
|
|
* \tparam _BlockAtCompileTime The block layout option. It takes the following values
|
|
|
|
|
* Dynamic : block size known at runtime
|
|
|
|
|
* a numeric number : fixed-size block known at compile time
|
|
|
|
|
*/
|
2021-08-04 22:41:52 +00:00
|
|
|
template <typename Scalar_, int _BlockAtCompileTime = Dynamic, int Options_ = ColMajor, typename StorageIndex_ = int>
|
|
|
|
|
class BlockSparseMatrix;
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
template <typename BlockSparseMatrixT>
|
|
|
|
|
class BlockSparseMatrixView;
|
|
|
|
|
|
|
|
|
|
namespace internal {
|
2021-08-04 22:41:52 +00:00
|
|
|
template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename Index_>
|
|
|
|
|
struct traits<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, Index_> > {
|
|
|
|
|
typedef Scalar_ Scalar;
|
|
|
|
|
typedef Index_ Index;
|
2013-09-20 18:54:17 +02:00
|
|
|
typedef Sparse StorageKind; // FIXME Where is it used ??
|
|
|
|
|
typedef MatrixXpr XprKind;
|
|
|
|
|
enum {
|
|
|
|
|
RowsAtCompileTime = Dynamic,
|
|
|
|
|
ColsAtCompileTime = Dynamic,
|
|
|
|
|
MaxRowsAtCompileTime = Dynamic,
|
|
|
|
|
MaxColsAtCompileTime = Dynamic,
|
|
|
|
|
BlockSize = _BlockAtCompileTime,
|
2021-08-04 22:41:52 +00:00
|
|
|
Flags = Options_ | NestByRefBit | LvalueBit,
|
2013-09-20 18:54:17 +02:00
|
|
|
CoeffReadCost = NumTraits<Scalar>::ReadCost,
|
|
|
|
|
SupportedAccessPatterns = InnerRandomAccessPattern
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
template <typename BlockSparseMatrixT>
|
|
|
|
|
struct traits<BlockSparseMatrixView<BlockSparseMatrixT> > {
|
|
|
|
|
typedef Ref<
|
|
|
|
|
Matrix<typename BlockSparseMatrixT::Scalar, BlockSparseMatrixT::BlockSize, BlockSparseMatrixT::BlockSize> >
|
|
|
|
|
Scalar;
|
|
|
|
|
typedef Ref<
|
|
|
|
|
Matrix<typename BlockSparseMatrixT::RealScalar, BlockSparseMatrixT::BlockSize, BlockSparseMatrixT::BlockSize> >
|
|
|
|
|
RealScalar;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Function object to sort a triplet list
|
|
|
|
|
template <typename Iterator, bool IsColMajor>
|
|
|
|
|
struct TripletComp {
|
|
|
|
|
typedef typename Iterator::value_type Triplet;
|
|
|
|
|
bool operator()(const Triplet& a, const Triplet& b) {
|
|
|
|
|
if (IsColMajor)
|
|
|
|
|
return ((a.col() == b.col() && a.row() < b.row()) || (a.col() < b.col()));
|
|
|
|
|
else
|
|
|
|
|
return ((a.row() == b.row() && a.col() < b.col()) || (a.row() < b.row()));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
} // end namespace internal
|
|
|
|
|
|
|
|
|
|
/* Proxy to view the block sparse matrix as a regular sparse matrix */
|
|
|
|
|
template <typename BlockSparseMatrixT>
|
|
|
|
|
class BlockSparseMatrixView : public SparseMatrixBase<BlockSparseMatrixT> {
|
|
|
|
|
public:
|
|
|
|
|
typedef Ref<typename BlockSparseMatrixT::BlockScalar> Scalar;
|
|
|
|
|
typedef Ref<typename BlockSparseMatrixT::BlockRealScalar> RealScalar;
|
|
|
|
|
typedef typename BlockSparseMatrixT::Index Index;
|
|
|
|
|
typedef BlockSparseMatrixT Nested;
|
|
|
|
|
enum {
|
|
|
|
|
Flags = BlockSparseMatrixT::Options,
|
|
|
|
|
Options = BlockSparseMatrixT::Options,
|
|
|
|
|
RowsAtCompileTime = BlockSparseMatrixT::RowsAtCompileTime,
|
|
|
|
|
ColsAtCompileTime = BlockSparseMatrixT::ColsAtCompileTime,
|
|
|
|
|
MaxColsAtCompileTime = BlockSparseMatrixT::MaxColsAtCompileTime,
|
|
|
|
|
MaxRowsAtCompileTime = BlockSparseMatrixT::MaxRowsAtCompileTime
|
|
|
|
|
};
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
public:
|
|
|
|
|
BlockSparseMatrixView(const BlockSparseMatrixT& spblockmat) : m_spblockmat(spblockmat) {}
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
Index outerSize() const { return (Flags & RowMajorBit) == 1 ? this->rows() : this->cols(); }
|
|
|
|
|
Index cols() const { return m_spblockmat.blockCols(); }
|
|
|
|
|
Index rows() const { return m_spblockmat.blockRows(); }
|
|
|
|
|
Scalar coeff(Index row, Index col) { return m_spblockmat.coeff(row, col); }
|
|
|
|
|
Scalar coeffRef(Index row, Index col) { return m_spblockmat.coeffRef(row, col); }
|
|
|
|
|
// Wrapper to iterate over all blocks
|
|
|
|
|
class InnerIterator : public BlockSparseMatrixT::BlockInnerIterator {
|
|
|
|
|
public:
|
|
|
|
|
InnerIterator(const BlockSparseMatrixView& mat, Index outer)
|
|
|
|
|
: BlockSparseMatrixT::BlockInnerIterator(mat.m_spblockmat, outer) {}
|
|
|
|
|
};
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
protected:
|
|
|
|
|
const BlockSparseMatrixT& m_spblockmat;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Proxy to view a regular vector as a block vector
|
|
|
|
|
template <typename BlockSparseMatrixT, typename VectorType>
|
|
|
|
|
class BlockVectorView {
|
|
|
|
|
public:
|
|
|
|
|
enum {
|
|
|
|
|
BlockSize = BlockSparseMatrixT::BlockSize,
|
|
|
|
|
ColsAtCompileTime = VectorType::ColsAtCompileTime,
|
|
|
|
|
RowsAtCompileTime = VectorType::RowsAtCompileTime,
|
|
|
|
|
Flags = VectorType::Flags
|
|
|
|
|
};
|
|
|
|
|
typedef Ref<const Matrix<typename BlockSparseMatrixT::Scalar, (RowsAtCompileTime == 1) ? 1 : BlockSize,
|
|
|
|
|
(ColsAtCompileTime == 1) ? 1 : BlockSize> >
|
|
|
|
|
Scalar;
|
|
|
|
|
typedef typename BlockSparseMatrixT::Index Index;
|
|
|
|
|
|
2023-11-29 11:12:48 +00:00
|
|
|
public:
|
2013-09-20 18:54:17 +02:00
|
|
|
BlockVectorView(const BlockSparseMatrixT& spblockmat, const VectorType& vec) : m_spblockmat(spblockmat), m_vec(vec) {}
|
|
|
|
|
inline Index cols() const { return m_vec.cols(); }
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index size() const { return m_spblockmat.blockRows(); }
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Scalar coeff(Index bi) const {
|
|
|
|
|
Index startRow = m_spblockmat.blockRowsIndex(bi);
|
|
|
|
|
Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
|
|
|
|
|
return m_vec.middleRows(startRow, rowSize);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Scalar coeff(Index bi, Index j) const {
|
|
|
|
|
Index startRow = m_spblockmat.blockRowsIndex(bi);
|
|
|
|
|
Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
|
|
|
|
|
return m_vec.block(startRow, j, rowSize, 1);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const BlockSparseMatrixT& m_spblockmat;
|
|
|
|
|
const VectorType& m_vec;
|
2023-11-29 11:12:48 +00:00
|
|
|
};
|
|
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
template <typename VectorType, typename Index>
|
|
|
|
|
class BlockVectorReturn;
|
|
|
|
|
|
|
|
|
|
// Proxy to view a regular vector as a block vector
|
|
|
|
|
template <typename BlockSparseMatrixT, typename VectorType>
|
|
|
|
|
class BlockVectorReturn {
|
|
|
|
|
public:
|
|
|
|
|
enum {
|
|
|
|
|
ColsAtCompileTime = VectorType::ColsAtCompileTime,
|
|
|
|
|
RowsAtCompileTime = VectorType::RowsAtCompileTime,
|
|
|
|
|
Flags = VectorType::Flags
|
|
|
|
|
};
|
|
|
|
|
typedef Ref<Matrix<typename VectorType::Scalar, RowsAtCompileTime, ColsAtCompileTime> > Scalar;
|
|
|
|
|
typedef typename BlockSparseMatrixT::Index Index;
|
|
|
|
|
|
2023-11-29 11:12:48 +00:00
|
|
|
public:
|
2013-09-20 18:54:17 +02:00
|
|
|
BlockVectorReturn(const BlockSparseMatrixT& spblockmat, VectorType& vec) : m_spblockmat(spblockmat), m_vec(vec) {}
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index size() const { return m_spblockmat.blockRows(); }
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Scalar coeffRef(Index bi) {
|
|
|
|
|
Index startRow = m_spblockmat.blockRowsIndex(bi);
|
|
|
|
|
Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
|
|
|
|
|
return m_vec.middleRows(startRow, rowSize);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Scalar coeffRef(Index bi, Index j) {
|
|
|
|
|
Index startRow = m_spblockmat.blockRowsIndex(bi);
|
|
|
|
|
Index rowSize = m_spblockmat.blockRowsIndex(bi + 1) - startRow;
|
|
|
|
|
return m_vec.block(startRow, j, rowSize, 1);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
protected:
|
|
|
|
|
const BlockSparseMatrixT& m_spblockmat;
|
|
|
|
|
VectorType& m_vec;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Block version of the sparse dense product
|
|
|
|
|
template <typename Lhs, typename Rhs>
|
|
|
|
|
class BlockSparseTimeDenseProduct;
|
|
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
|
|
template <typename BlockSparseMatrixT, typename VecType>
|
|
|
|
|
struct traits<BlockSparseTimeDenseProduct<BlockSparseMatrixT, VecType> > {
|
|
|
|
|
typedef Dense StorageKind;
|
|
|
|
|
typedef MatrixXpr XprKind;
|
|
|
|
|
typedef typename BlockSparseMatrixT::Scalar Scalar;
|
|
|
|
|
typedef typename BlockSparseMatrixT::Index Index;
|
|
|
|
|
enum {
|
|
|
|
|
RowsAtCompileTime = Dynamic,
|
|
|
|
|
ColsAtCompileTime = Dynamic,
|
|
|
|
|
MaxRowsAtCompileTime = Dynamic,
|
|
|
|
|
MaxColsAtCompileTime = Dynamic,
|
|
|
|
|
Flags = 0,
|
|
|
|
|
CoeffReadCost = internal::traits<BlockSparseMatrixT>::CoeffReadCost
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
} // end namespace internal
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
template <typename Lhs, typename Rhs>
|
|
|
|
|
class BlockSparseTimeDenseProduct : public ProductBase<BlockSparseTimeDenseProduct<Lhs, Rhs>, Lhs, Rhs> {
|
|
|
|
|
public:
|
|
|
|
|
EIGEN_PRODUCT_PUBLIC_INTERFACE(BlockSparseTimeDenseProduct)
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
BlockSparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs, rhs) {}
|
|
|
|
|
|
|
|
|
|
template <typename Dest>
|
|
|
|
|
void scaleAndAddTo(Dest& dest, const typename Rhs::Scalar& alpha) const {
|
|
|
|
|
BlockVectorReturn<Lhs, Dest> tmpDest(m_lhs, dest);
|
|
|
|
|
internal::sparse_time_dense_product(BlockSparseMatrixView<Lhs>(m_lhs), BlockVectorView<Lhs, Rhs>(m_lhs, m_rhs),
|
|
|
|
|
tmpDest, alpha);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
private:
|
|
|
|
|
BlockSparseTimeDenseProduct& operator=(const BlockSparseTimeDenseProduct&);
|
|
|
|
|
};
|
|
|
|
|
|
2021-08-04 22:41:52 +00:00
|
|
|
template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_>
|
|
|
|
|
class BlockSparseMatrix
|
|
|
|
|
: public SparseMatrixBase<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_> > {
|
2013-09-20 18:54:17 +02:00
|
|
|
public:
|
2021-08-04 22:41:52 +00:00
|
|
|
typedef Scalar_ Scalar;
|
2013-09-20 18:54:17 +02:00
|
|
|
typedef typename NumTraits<Scalar>::Real RealScalar;
|
2021-08-04 22:41:52 +00:00
|
|
|
typedef StorageIndex_ StorageIndex;
|
|
|
|
|
typedef
|
|
|
|
|
typename internal::ref_selector<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_> >::type
|
|
|
|
|
Nested;
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
enum {
|
2021-08-04 22:41:52 +00:00
|
|
|
Options = Options_,
|
2013-09-20 18:54:17 +02:00
|
|
|
Flags = Options,
|
|
|
|
|
BlockSize = _BlockAtCompileTime,
|
|
|
|
|
RowsAtCompileTime = Dynamic,
|
|
|
|
|
ColsAtCompileTime = Dynamic,
|
|
|
|
|
MaxRowsAtCompileTime = Dynamic,
|
|
|
|
|
MaxColsAtCompileTime = Dynamic,
|
|
|
|
|
IsVectorAtCompileTime = 0,
|
|
|
|
|
IsColMajor = Flags & RowMajorBit ? 0 : 1
|
|
|
|
|
};
|
|
|
|
|
typedef Matrix<Scalar, _BlockAtCompileTime, _BlockAtCompileTime, IsColMajor ? ColMajor : RowMajor> BlockScalar;
|
|
|
|
|
typedef Matrix<RealScalar, _BlockAtCompileTime, _BlockAtCompileTime, IsColMajor ? ColMajor : RowMajor>
|
|
|
|
|
BlockRealScalar;
|
2022-03-16 16:43:40 +00:00
|
|
|
typedef std::conditional_t<_BlockAtCompileTime == Dynamic, Scalar, BlockScalar> BlockScalarReturnType;
|
2014-12-04 22:48:53 +01:00
|
|
|
typedef BlockSparseMatrix<Scalar, BlockSize, IsColMajor ? ColMajor : RowMajor, StorageIndex> PlainObject;
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
public:
|
|
|
|
|
// Default constructor
|
|
|
|
|
BlockSparseMatrix()
|
|
|
|
|
: m_innerBSize(0),
|
|
|
|
|
m_outerBSize(0),
|
|
|
|
|
m_innerOffset(0),
|
|
|
|
|
m_outerOffset(0),
|
|
|
|
|
m_nonzerosblocks(0),
|
|
|
|
|
m_values(0),
|
|
|
|
|
m_blockPtr(0),
|
|
|
|
|
m_indices(0),
|
|
|
|
|
m_outerIndex(0),
|
|
|
|
|
m_blockSize(BlockSize) {}
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
/**
|
|
|
|
|
* \brief Construct and resize
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
BlockSparseMatrix(Index brow, Index bcol)
|
|
|
|
|
: m_innerBSize(IsColMajor ? brow : bcol),
|
|
|
|
|
m_outerBSize(IsColMajor ? bcol : brow),
|
|
|
|
|
m_innerOffset(0),
|
|
|
|
|
m_outerOffset(0),
|
|
|
|
|
m_nonzerosblocks(0),
|
2014-12-04 22:48:53 +01:00
|
|
|
m_values(0),
|
2013-09-20 18:54:17 +02:00
|
|
|
m_blockPtr(0),
|
|
|
|
|
m_indices(0),
|
|
|
|
|
m_outerIndex(0),
|
|
|
|
|
m_blockSize(BlockSize) {}
|
2023-11-29 11:12:48 +00:00
|
|
|
|
|
|
|
|
/**
|
2013-09-20 18:54:17 +02:00
|
|
|
* \brief Copy-constructor
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2013-09-20 18:54:17 +02:00
|
|
|
BlockSparseMatrix(const BlockSparseMatrix& other)
|
|
|
|
|
: m_innerBSize(other.m_innerBSize),
|
|
|
|
|
m_outerBSize(other.m_outerBSize),
|
|
|
|
|
m_nonzerosblocks(other.m_nonzerosblocks),
|
|
|
|
|
m_nonzeros(other.m_nonzeros),
|
|
|
|
|
m_blockPtr(0),
|
|
|
|
|
m_blockSize(other.m_blockSize) {
|
|
|
|
|
// should we allow copying between variable-size blocks and fixed-size blocks ??
|
|
|
|
|
eigen_assert(m_blockSize == BlockSize && " CAN NOT COPY BETWEEN FIXED-SIZE AND VARIABLE-SIZE BLOCKS");
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
std::copy(other.m_innerOffset, other.m_innerOffset + m_innerBSize + 1, m_innerOffset);
|
|
|
|
|
std::copy(other.m_outerOffset, other.m_outerOffset + m_outerBSize + 1, m_outerOffset);
|
|
|
|
|
std::copy(other.m_values, other.m_values + m_nonzeros, m_values);
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
if (m_blockSize != Dynamic) std::copy(other.m_blockPtr, other.m_blockPtr + m_nonzerosblocks, m_blockPtr);
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
std::copy(other.m_indices, other.m_indices + m_nonzerosblocks, m_indices);
|
|
|
|
|
std::copy(other.m_outerIndex, other.m_outerIndex + m_outerBSize, m_outerIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend void swap(BlockSparseMatrix& first, BlockSparseMatrix& second) {
|
|
|
|
|
std::swap(first.m_innerBSize, second.m_innerBSize);
|
|
|
|
|
std::swap(first.m_outerBSize, second.m_outerBSize);
|
|
|
|
|
std::swap(first.m_innerOffset, second.m_innerOffset);
|
|
|
|
|
std::swap(first.m_outerOffset, second.m_outerOffset);
|
|
|
|
|
std::swap(first.m_nonzerosblocks, second.m_nonzerosblocks);
|
|
|
|
|
std::swap(first.m_nonzeros, second.m_nonzeros);
|
|
|
|
|
std::swap(first.m_values, second.m_values);
|
|
|
|
|
std::swap(first.m_blockPtr, second.m_blockPtr);
|
|
|
|
|
std::swap(first.m_indices, second.m_indices);
|
|
|
|
|
std::swap(first.m_outerIndex, second.m_outerIndex);
|
|
|
|
|
std::swap(first.m_BlockSize, second.m_blockSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BlockSparseMatrix& operator=(BlockSparseMatrix other) {
|
|
|
|
|
// Copy-and-swap paradigm ... avoid leaked data if thrown
|
|
|
|
|
swap(*this, other);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
|
~BlockSparseMatrix() {
|
|
|
|
|
delete[] m_outerIndex;
|
|
|
|
|
delete[] m_innerOffset;
|
|
|
|
|
delete[] m_outerOffset;
|
|
|
|
|
delete[] m_indices;
|
|
|
|
|
delete[] m_blockPtr;
|
|
|
|
|
delete[] m_values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Constructor from a sparse matrix
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
*/
|
|
|
|
|
template <typename MatrixType>
|
|
|
|
|
inline BlockSparseMatrix(const MatrixType& spmat) : m_blockSize(BlockSize) {
|
|
|
|
|
EIGEN_STATIC_ASSERT((m_blockSize != Dynamic), THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE);
|
|
|
|
|
|
|
|
|
|
*this = spmat;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Assignment from a sparse matrix with the same storage order
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* Convert from a sparse matrix to block sparse matrix.
|
|
|
|
|
* \warning Before calling this function, tt is necessary to call
|
|
|
|
|
* either setBlockLayout() (matrices with variable-size blocks)
|
|
|
|
|
* or setBlockSize() (for fixed-size blocks).
|
|
|
|
|
*/
|
|
|
|
|
template <typename MatrixType>
|
|
|
|
|
inline BlockSparseMatrix& operator=(const MatrixType& spmat) {
|
|
|
|
|
eigen_assert((m_innerBSize != 0 && m_outerBSize != 0) &&
|
|
|
|
|
"Trying to assign to a zero-size matrix, call resize() first");
|
|
|
|
|
eigen_assert(((MatrixType::Options & RowMajorBit) != IsColMajor) && "Wrong storage order");
|
|
|
|
|
typedef SparseMatrix<bool, MatrixType::Options, typename MatrixType::Index> MatrixPatternType;
|
|
|
|
|
MatrixPatternType blockPattern(blockRows(), blockCols());
|
|
|
|
|
m_nonzeros = 0;
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// First, compute the number of nonzero blocks and their locations
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
|
2013-09-20 18:54:17 +02:00
|
|
|
// Browse each outer block and compute the structure
|
|
|
|
|
std::vector<bool> nzblocksFlag(m_innerBSize, false); // Record the existing blocks
|
|
|
|
|
blockPattern.startVec(bj);
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex j = blockOuterIndex(bj); j < blockOuterIndex(bj + 1); ++j) {
|
2013-09-20 18:54:17 +02:00
|
|
|
typename MatrixType::InnerIterator it_spmat(spmat, j);
|
|
|
|
|
for (; it_spmat; ++it_spmat) {
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex bi = innerToBlock(it_spmat.index()); // Index of the current nonzero block
|
2013-09-20 18:54:17 +02:00
|
|
|
if (!nzblocksFlag[bi]) {
|
|
|
|
|
// Save the index of this nonzero block
|
|
|
|
|
nzblocksFlag[bi] = true;
|
|
|
|
|
blockPattern.insertBackByOuterInnerUnordered(bj, bi) = true;
|
|
|
|
|
// Compute the total number of nonzeros (including explicit zeros in blocks)
|
|
|
|
|
m_nonzeros += blockOuterSize(bj) * blockInnerSize(bi);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
} // end current outer block
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
blockPattern.finalize();
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// Allocate the internal arrays
|
|
|
|
|
setBlockStructure(blockPattern);
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex nz = 0; nz < m_nonzeros; ++nz) m_values[nz] = Scalar(0);
|
|
|
|
|
for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
|
2013-09-20 18:54:17 +02:00
|
|
|
// Now copy the values
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex j = blockOuterIndex(bj); j < blockOuterIndex(bj + 1); ++j) {
|
2013-09-20 18:54:17 +02:00
|
|
|
// Browse the outer block column by column (for column-major matrices)
|
|
|
|
|
typename MatrixType::InnerIterator it_spmat(spmat, j);
|
|
|
|
|
for (; it_spmat; ++it_spmat) {
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex idx = 0; // Position of this block in the column block
|
|
|
|
|
StorageIndex bi = innerToBlock(it_spmat.index()); // Index of the current nonzero block
|
2013-09-20 18:54:17 +02:00
|
|
|
// Go to the inner block where this element belongs to
|
|
|
|
|
while (bi > m_indices[m_outerIndex[bj] + idx]) ++idx; // Not expensive for ordered blocks
|
|
|
|
|
StorageIndex idxVal; // Get the right position in the array of values for this element
|
|
|
|
|
if (m_blockSize == Dynamic) {
|
|
|
|
|
// Offset from all blocks before ...
|
|
|
|
|
idxVal = m_blockPtr[m_outerIndex[bj] + idx];
|
|
|
|
|
// ... and offset inside the block
|
|
|
|
|
idxVal += (j - blockOuterIndex(bj)) * blockOuterSize(bj) + it_spmat.index() - m_innerOffset[bi];
|
2023-11-29 11:12:48 +00:00
|
|
|
} else {
|
2013-09-20 18:54:17 +02:00
|
|
|
// All blocks before
|
|
|
|
|
idxVal = (m_outerIndex[bj] + idx) * m_blockSize * m_blockSize;
|
|
|
|
|
// inside the block
|
|
|
|
|
idxVal += (j - blockOuterIndex(bj)) * m_blockSize + (it_spmat.index() % m_blockSize);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
// Insert the value
|
|
|
|
|
m_values[idxVal] = it_spmat.value();
|
|
|
|
|
} // end of this column
|
|
|
|
|
} // end of this block
|
|
|
|
|
} // end of this outer block
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Set the nonzero block pattern of the matrix
|
|
|
|
|
*
|
|
|
|
|
* Given a sparse matrix describing the nonzero block pattern,
|
|
|
|
|
* this function prepares the internal pointers for values.
|
|
|
|
|
* After calling this function, any *nonzero* block (bi, bj) can be set
|
|
|
|
|
* with a simple call to coeffRef(bi,bj).
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
|
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* \warning Before calling this function, tt is necessary to call
|
|
|
|
|
* either setBlockLayout() (matrices with variable-size blocks)
|
|
|
|
|
* or setBlockSize() (for fixed-size blocks).
|
|
|
|
|
*
|
|
|
|
|
* \param blockPattern Sparse matrix of boolean elements describing the block structure
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* \sa setBlockLayout() \sa setBlockSize()
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2013-09-20 18:54:17 +02:00
|
|
|
template <typename MatrixType>
|
|
|
|
|
void setBlockStructure(const MatrixType& blockPattern) {
|
|
|
|
|
resize(blockPattern.rows(), blockPattern.cols());
|
|
|
|
|
reserve(blockPattern.nonZeros());
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// Browse the block pattern and set up the various pointers
|
|
|
|
|
m_outerIndex[0] = 0;
|
|
|
|
|
if (m_blockSize == Dynamic) m_blockPtr[0] = 0;
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex nz = 0; nz < m_nonzeros; ++nz) m_values[nz] = Scalar(0);
|
|
|
|
|
for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
|
|
|
|
|
// Browse each outer block
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// First, copy and save the indices of nonzero blocks
|
|
|
|
|
// FIXME : find a way to avoid this ...
|
|
|
|
|
std::vector<int> nzBlockIdx;
|
|
|
|
|
typename MatrixType::InnerIterator it(blockPattern, bj);
|
|
|
|
|
for (; it; ++it) {
|
|
|
|
|
nzBlockIdx.push_back(it.index());
|
|
|
|
|
}
|
2014-12-04 22:48:53 +01:00
|
|
|
std::sort(nzBlockIdx.begin(), nzBlockIdx.end());
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// Now, fill block indices and (eventually) pointers to blocks
|
|
|
|
|
for (StorageIndex idx = 0; idx < nzBlockIdx.size(); ++idx) {
|
|
|
|
|
StorageIndex offset = m_outerIndex[bj] + idx; // offset in m_indices
|
|
|
|
|
m_indices[offset] = nzBlockIdx[idx];
|
|
|
|
|
if (m_blockSize == Dynamic)
|
|
|
|
|
m_blockPtr[offset] = m_blockPtr[offset - 1] + blockInnerSize(nzBlockIdx[idx]) * blockOuterSize(bj);
|
|
|
|
|
// There is no blockPtr for fixed-size blocks... not needed !???
|
|
|
|
|
}
|
|
|
|
|
// Save the pointer to the next outer block
|
|
|
|
|
m_outerIndex[bj + 1] = m_outerIndex[bj] + nzBlockIdx.size();
|
|
|
|
|
}
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Set the number of rows and columns blocks
|
|
|
|
|
*/
|
2015-02-13 18:57:41 +01:00
|
|
|
inline void resize(Index brow, Index bcol) {
|
2013-09-20 18:54:17 +02:00
|
|
|
m_innerBSize = IsColMajor ? brow : bcol;
|
|
|
|
|
m_outerBSize = IsColMajor ? bcol : brow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief set the block size at runtime for fixed-size block layout
|
|
|
|
|
*
|
|
|
|
|
* Call this only for fixed-size blocks
|
|
|
|
|
*/
|
2015-02-13 18:57:41 +01:00
|
|
|
inline void setBlockSize(Index blockSize) { m_blockSize = blockSize; }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
|
|
|
|
/**
|
2013-09-20 18:54:17 +02:00
|
|
|
* \brief Set the row and column block layouts,
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* This function set the size of each row and column block.
|
|
|
|
|
* So this function should be used only for blocks with variable size.
|
|
|
|
|
* \param rowBlocks : Number of rows per row block
|
|
|
|
|
* \param colBlocks : Number of columns per column block
|
|
|
|
|
* \sa resize(), setBlockSize()
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2013-09-20 18:54:17 +02:00
|
|
|
inline void setBlockLayout(const VectorXi& rowBlocks, const VectorXi& colBlocks) {
|
|
|
|
|
const VectorXi& innerBlocks = IsColMajor ? rowBlocks : colBlocks;
|
|
|
|
|
const VectorXi& outerBlocks = IsColMajor ? colBlocks : rowBlocks;
|
|
|
|
|
eigen_assert(m_innerBSize == innerBlocks.size() && "CHECK THE NUMBER OF ROW OR COLUMN BLOCKS");
|
|
|
|
|
eigen_assert(m_outerBSize == outerBlocks.size() && "CHECK THE NUMBER OF ROW OR COLUMN BLOCKS");
|
|
|
|
|
m_outerBSize = outerBlocks.size();
|
|
|
|
|
// starting index of blocks... cumulative sums
|
2014-12-04 22:48:53 +01:00
|
|
|
m_innerOffset = new StorageIndex[m_innerBSize + 1];
|
|
|
|
|
m_outerOffset = new StorageIndex[m_outerBSize + 1];
|
2013-09-20 18:54:17 +02:00
|
|
|
m_innerOffset[0] = 0;
|
|
|
|
|
m_outerOffset[0] = 0;
|
|
|
|
|
std::partial_sum(&innerBlocks[0], &innerBlocks[m_innerBSize - 1] + 1, &m_innerOffset[1]);
|
|
|
|
|
std::partial_sum(&outerBlocks[0], &outerBlocks[m_outerBSize - 1] + 1, &m_outerOffset[1]);
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// Compute the total number of nonzeros
|
|
|
|
|
m_nonzeros = 0;
|
|
|
|
|
for (StorageIndex bj = 0; bj < m_outerBSize; ++bj)
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex bi = 0; bi < m_innerBSize; ++bi) m_nonzeros += outerBlocks[bj] * innerBlocks[bi];
|
2013-09-20 18:54:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Allocate the internal array of pointers to blocks and their inner indices
|
|
|
|
|
*
|
|
|
|
|
* \note For fixed-size blocks, call setBlockSize() to set the block.
|
|
|
|
|
* And For variable-size blocks, call setBlockLayout() before using this function
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* \param nonzerosblocks Number of nonzero blocks. The total number of nonzeros is
|
|
|
|
|
* is computed in setBlockLayout() for variable-size blocks
|
|
|
|
|
* \sa setBlockSize()
|
|
|
|
|
*/
|
|
|
|
|
inline void reserve(const Index nonzerosblocks) {
|
|
|
|
|
eigen_assert((m_innerBSize != 0 && m_outerBSize != 0) &&
|
|
|
|
|
"TRYING TO RESERVE ZERO-SIZE MATRICES, CALL resize() first");
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// FIXME Should free if already allocated
|
2014-12-04 22:48:53 +01:00
|
|
|
m_outerIndex = new StorageIndex[m_outerBSize + 1];
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
m_nonzerosblocks = nonzerosblocks;
|
|
|
|
|
if (m_blockSize != Dynamic) {
|
|
|
|
|
m_nonzeros = nonzerosblocks * (m_blockSize * m_blockSize);
|
|
|
|
|
m_blockPtr = 0;
|
2023-11-29 11:12:48 +00:00
|
|
|
} else {
|
2013-09-20 18:54:17 +02:00
|
|
|
// m_nonzeros is already computed in setBlockLayout()
|
2014-12-04 22:48:53 +01:00
|
|
|
m_blockPtr = new StorageIndex[m_nonzerosblocks + 1];
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
m_indices = new StorageIndex[m_nonzerosblocks + 1];
|
|
|
|
|
m_values = new Scalar[m_nonzeros];
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
2023-11-29 11:12:48 +00:00
|
|
|
/**
|
2013-09-20 18:54:17 +02:00
|
|
|
* \brief Fill values in a matrix from a triplet list.
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* Each triplet item has a block stored in an Eigen dense matrix.
|
|
|
|
|
* The InputIterator class should provide the functions row(), col() and value()
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* \note For fixed-size blocks, call setBlockSize() before this function.
|
2023-11-29 11:12:48 +00:00
|
|
|
*
|
2013-09-20 18:54:17 +02:00
|
|
|
* FIXME Do not accept duplicates
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2013-09-20 18:54:17 +02:00
|
|
|
template <typename InputIterator>
|
|
|
|
|
void setFromTriplets(const InputIterator& begin, const InputIterator& end) {
|
|
|
|
|
eigen_assert((m_innerBSize != 0 && m_outerBSize != 0) && "ZERO BLOCKS, PLEASE CALL resize() before");
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
/* First, sort the triplet list
|
|
|
|
|
* FIXME This can be unnecessarily expensive since only the inner indices have to be sorted
|
|
|
|
|
* The best approach is like in SparseMatrix::setFromTriplets()
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2013-09-20 18:54:17 +02:00
|
|
|
internal::TripletComp<InputIterator, IsColMajor> tripletcomp;
|
|
|
|
|
std::sort(begin, end, tripletcomp);
|
|
|
|
|
|
|
|
|
|
/* Count the number of rows and column blocks,
|
|
|
|
|
* and the number of nonzero blocks per outer dimension
|
|
|
|
|
*/
|
|
|
|
|
VectorXi rowBlocks(m_innerBSize); // Size of each block row
|
|
|
|
|
VectorXi colBlocks(m_outerBSize); // Size of each block column
|
|
|
|
|
rowBlocks.setZero();
|
|
|
|
|
colBlocks.setZero();
|
|
|
|
|
VectorXi nzblock_outer(m_outerBSize); // Number of nz blocks per outer vector
|
|
|
|
|
VectorXi nz_outer(m_outerBSize); // Number of nz per outer vector...for variable-size blocks
|
2015-02-13 18:57:41 +01:00
|
|
|
nzblock_outer.setZero();
|
2013-09-20 18:54:17 +02:00
|
|
|
nz_outer.setZero();
|
|
|
|
|
for (InputIterator it(begin); it != end; ++it) {
|
|
|
|
|
eigen_assert(it->row() >= 0 && it->row() < this->blockRows() && it->col() >= 0 && it->col() < this->blockCols());
|
|
|
|
|
eigen_assert((it->value().rows() == it->value().cols() && (it->value().rows() == m_blockSize)) ||
|
|
|
|
|
(m_blockSize == Dynamic));
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
if (m_blockSize == Dynamic) {
|
|
|
|
|
eigen_assert((rowBlocks[it->row()] == 0 || rowBlocks[it->row()] == it->value().rows()) &&
|
|
|
|
|
"NON CORRESPONDING SIZES FOR ROW BLOCKS");
|
|
|
|
|
eigen_assert((colBlocks[it->col()] == 0 || colBlocks[it->col()] == it->value().cols()) &&
|
|
|
|
|
"NON CORRESPONDING SIZES FOR COLUMN BLOCKS");
|
|
|
|
|
rowBlocks[it->row()] = it->value().rows();
|
|
|
|
|
colBlocks[it->col()] = it->value().cols();
|
|
|
|
|
}
|
|
|
|
|
nz_outer(IsColMajor ? it->col() : it->row()) += it->value().rows() * it->value().cols();
|
|
|
|
|
nzblock_outer(IsColMajor ? it->col() : it->row())++;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
// Allocate member arrays
|
|
|
|
|
if (m_blockSize == Dynamic) setBlockLayout(rowBlocks, colBlocks);
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex nzblocks = nzblock_outer.sum();
|
2013-09-20 18:54:17 +02:00
|
|
|
reserve(nzblocks);
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// Temporary markers
|
|
|
|
|
VectorXi block_id(m_outerBSize); // To be used as a block marker during insertion
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2014-12-04 22:48:53 +01:00
|
|
|
// Setup outer index pointers and markers
|
2013-09-20 18:54:17 +02:00
|
|
|
m_outerIndex[0] = 0;
|
2014-12-04 22:48:53 +01:00
|
|
|
if (m_blockSize == Dynamic) m_blockPtr[0] = 0;
|
|
|
|
|
for (StorageIndex bj = 0; bj < m_outerBSize; ++bj) {
|
2013-09-20 18:54:17 +02:00
|
|
|
m_outerIndex[bj + 1] = m_outerIndex[bj] + nzblock_outer(bj);
|
2014-12-04 22:48:53 +01:00
|
|
|
block_id(bj) = m_outerIndex[bj];
|
2013-09-20 18:54:17 +02:00
|
|
|
if (m_blockSize == Dynamic) {
|
2014-12-04 22:48:53 +01:00
|
|
|
m_blockPtr[m_outerIndex[bj + 1]] = m_blockPtr[m_outerIndex[bj]] + nz_outer(bj);
|
2013-09-20 18:54:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fill the matrix
|
|
|
|
|
for (InputIterator it(begin); it != end; ++it) {
|
|
|
|
|
StorageIndex outer = IsColMajor ? it->col() : it->row();
|
|
|
|
|
StorageIndex inner = IsColMajor ? it->row() : it->col();
|
|
|
|
|
m_indices[block_id(outer)] = inner;
|
|
|
|
|
StorageIndex block_size = it->value().rows() * it->value().cols();
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex nz_marker = blockPtr(block_id[outer]);
|
2013-09-20 18:54:17 +02:00
|
|
|
memcpy(&(m_values[nz_marker]), it->value().data(), block_size * sizeof(Scalar));
|
|
|
|
|
if (m_blockSize == Dynamic) {
|
|
|
|
|
m_blockPtr[block_id(outer) + 1] = m_blockPtr[block_id(outer)] + block_size;
|
|
|
|
|
}
|
|
|
|
|
block_id(outer)++;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// An alternative when the outer indices are sorted...no need to use an array of markers
|
|
|
|
|
// for(Index bcol = 0; bcol < m_outerBSize; ++bcol)
|
2023-11-29 11:12:48 +00:00
|
|
|
// {
|
2013-09-20 18:54:17 +02:00
|
|
|
// Index id = 0, id_nz = 0, id_nzblock = 0;
|
|
|
|
|
// for(InputIterator it(begin); it!=end; ++it)
|
2023-11-29 11:12:48 +00:00
|
|
|
// {
|
2013-09-20 18:54:17 +02:00
|
|
|
// while (id<bcol) // one pass should do the job unless there are empty columns
|
2023-11-29 11:12:48 +00:00
|
|
|
// {
|
|
|
|
|
// id++;
|
2013-09-20 18:54:17 +02:00
|
|
|
// m_outerIndex[id+1]=m_outerIndex[id];
|
2023-11-29 11:12:48 +00:00
|
|
|
// }
|
2013-09-20 18:54:17 +02:00
|
|
|
// m_outerIndex[id+1] += 1;
|
|
|
|
|
// m_indices[id_nzblock]=brow;
|
|
|
|
|
// Index block_size = it->value().rows()*it->value().cols();
|
|
|
|
|
// m_blockPtr[id_nzblock+1] = m_blockPtr[id_nzblock] + block_size;
|
|
|
|
|
// id_nzblock++;
|
|
|
|
|
// memcpy(&(m_values[id_nz]),it->value().data(), block_size*sizeof(Scalar));
|
|
|
|
|
// id_nz += block_size;
|
2023-11-29 11:12:48 +00:00
|
|
|
// }
|
2013-09-20 18:54:17 +02:00
|
|
|
// while(id < m_outerBSize-1) // Empty columns at the end
|
2023-11-29 11:12:48 +00:00
|
|
|
// {
|
|
|
|
|
// id++;
|
2013-09-20 18:54:17 +02:00
|
|
|
// m_outerIndex[id+1]=m_outerIndex[id];
|
2023-11-29 11:12:48 +00:00
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \returns the number of rows
|
|
|
|
|
*/
|
|
|
|
|
inline Index rows() const {
|
|
|
|
|
// return blockRows();
|
|
|
|
|
return (IsColMajor ? innerSize() : outerSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \returns the number of cols
|
|
|
|
|
*/
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index cols() const {
|
|
|
|
|
// return blockCols();
|
2013-09-20 18:54:17 +02:00
|
|
|
return (IsColMajor ? outerSize() : innerSize());
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index innerSize() const {
|
2013-09-20 18:54:17 +02:00
|
|
|
if (m_blockSize == Dynamic)
|
2015-02-13 18:57:41 +01:00
|
|
|
return m_innerOffset[m_innerBSize];
|
2023-11-29 11:12:48 +00:00
|
|
|
else
|
2015-02-13 18:57:41 +01:00
|
|
|
return (m_innerBSize * m_blockSize);
|
|
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
inline Index outerSize() const {
|
|
|
|
|
if (m_blockSize == Dynamic)
|
|
|
|
|
return m_outerOffset[m_outerBSize];
|
|
|
|
|
else
|
|
|
|
|
return (m_outerBSize * m_blockSize);
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
/** \returns the number of rows grouped by blocks */
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index blockRows() const { return (IsColMajor ? m_innerBSize : m_outerBSize); }
|
2013-09-20 18:54:17 +02:00
|
|
|
/** \returns the number of columns grouped by blocks */
|
|
|
|
|
inline Index blockCols() const { return (IsColMajor ? m_outerBSize : m_innerBSize); }
|
|
|
|
|
|
|
|
|
|
inline Index outerBlocks() const { return m_outerBSize; }
|
|
|
|
|
inline Index innerBlocks() const { return m_innerBSize; }
|
|
|
|
|
|
|
|
|
|
/** \returns the block index where outer belongs to */
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index outerToBlock(Index outer) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
eigen_assert(outer < outerSize() && "OUTER INDEX OUT OF BOUNDS");
|
|
|
|
|
|
|
|
|
|
if (m_blockSize != Dynamic) return (outer / m_blockSize); // Integer division
|
|
|
|
|
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex b_outer = 0;
|
2013-09-20 18:54:17 +02:00
|
|
|
while (m_outerOffset[b_outer] <= outer) ++b_outer;
|
|
|
|
|
return b_outer - 1;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
/** \returns the block index where inner belongs to */
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index innerToBlock(Index inner) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
eigen_assert(inner < innerSize() && "OUTER INDEX OUT OF BOUNDS");
|
|
|
|
|
|
2014-12-04 22:48:53 +01:00
|
|
|
if (m_blockSize != Dynamic) return (inner / m_blockSize); // Integer division
|
2013-09-20 18:54:17 +02:00
|
|
|
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex b_inner = 0;
|
2013-09-20 18:54:17 +02:00
|
|
|
while (m_innerOffset[b_inner] <= inner) ++b_inner;
|
|
|
|
|
return b_inner - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*\returns a reference to the (i,j) block as an Eigen Dense Matrix
|
|
|
|
|
*/
|
|
|
|
|
Ref<BlockScalar> coeffRef(Index brow, Index bcol) {
|
|
|
|
|
eigen_assert(brow < blockRows() && "BLOCK ROW INDEX OUT OF BOUNDS");
|
|
|
|
|
eigen_assert(bcol < blockCols() && "BLOCK nzblocksFlagCOLUMN OUT OF BOUNDS");
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
StorageIndex rsize = IsColMajor ? blockInnerSize(brow) : blockOuterSize(bcol);
|
|
|
|
|
StorageIndex csize = IsColMajor ? blockOuterSize(bcol) : blockInnerSize(brow);
|
|
|
|
|
StorageIndex inner = IsColMajor ? brow : bcol;
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex outer = IsColMajor ? bcol : brow;
|
|
|
|
|
StorageIndex offset = m_outerIndex[outer];
|
2013-09-20 18:54:17 +02:00
|
|
|
while (offset < m_outerIndex[outer + 1] && m_indices[offset] != inner) offset++;
|
|
|
|
|
if (m_indices[offset] == inner) {
|
|
|
|
|
return Map<BlockScalar>(&(m_values[blockPtr(offset)]), rsize, csize);
|
2023-11-29 11:12:48 +00:00
|
|
|
} else {
|
2013-09-20 18:54:17 +02:00
|
|
|
// FIXME the block does not exist, Insert it !!!!!!!!!
|
|
|
|
|
eigen_assert("DYNAMIC INSERTION IS NOT YET SUPPORTED");
|
|
|
|
|
}
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \returns the value of the (i,j) block as an Eigen Dense Matrix
|
|
|
|
|
*/
|
2014-12-04 22:48:53 +01:00
|
|
|
Map<const BlockScalar> coeff(Index brow, Index bcol) const {
|
|
|
|
|
eigen_assert(brow < blockRows() && "BLOCK ROW INDEX OUT OF BOUNDS");
|
|
|
|
|
eigen_assert(bcol < blockCols() && "BLOCK COLUMN OUT OF BOUNDS");
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex rsize = IsColMajor ? blockInnerSize(brow) : blockOuterSize(bcol);
|
2013-09-20 18:54:17 +02:00
|
|
|
StorageIndex csize = IsColMajor ? blockOuterSize(bcol) : blockInnerSize(brow);
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex inner = IsColMajor ? brow : bcol;
|
|
|
|
|
StorageIndex outer = IsColMajor ? bcol : brow;
|
2013-09-20 18:54:17 +02:00
|
|
|
StorageIndex offset = m_outerIndex[outer];
|
|
|
|
|
while (offset < m_outerIndex[outer + 1] && m_indices[offset] != inner) offset++;
|
|
|
|
|
if (m_indices[offset] == inner) {
|
|
|
|
|
return Map<const BlockScalar>(&(m_values[blockPtr(offset)]), rsize, csize);
|
2023-11-29 11:12:48 +00:00
|
|
|
} else
|
2013-09-20 18:54:17 +02:00
|
|
|
// return BlockScalar::Zero(rsize, csize);
|
|
|
|
|
eigen_assert("NOT YET SUPPORTED");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Block Matrix times vector product
|
|
|
|
|
template <typename VecType>
|
2015-02-13 18:57:41 +01:00
|
|
|
BlockSparseTimeDenseProduct<BlockSparseMatrix, VecType> operator*(const VecType& lhs) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
return BlockSparseTimeDenseProduct<BlockSparseMatrix, VecType>(*this, lhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \returns the number of nonzero blocks */
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index nonZerosBlocks() const { return m_nonzerosblocks; }
|
2013-09-20 18:54:17 +02:00
|
|
|
/** \returns the total number of nonzero elements, including eventual explicit zeros in blocks */
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index nonZeros() const { return m_nonzeros; }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
inline BlockScalarReturnType* valuePtr() { return static_cast<BlockScalarReturnType*>(m_values); }
|
|
|
|
|
// inline Scalar *valuePtr(){ return m_values; }
|
2014-12-04 22:48:53 +01:00
|
|
|
inline StorageIndex* innerIndexPtr() { return m_indices; }
|
|
|
|
|
inline const StorageIndex* innerIndexPtr() const { return m_indices; }
|
|
|
|
|
inline StorageIndex* outerIndexPtr() { return m_outerIndex; }
|
|
|
|
|
inline const StorageIndex* outerIndexPtr() const { return m_outerIndex; }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
/** \brief for compatibility purposes with the SparseMatrix class */
|
|
|
|
|
inline bool isCompressed() const { return true; }
|
2023-11-29 11:12:48 +00:00
|
|
|
/**
|
2013-09-20 18:54:17 +02:00
|
|
|
* \returns the starting index of the bi row block
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index blockRowsIndex(Index bi) const { return IsColMajor ? blockInnerIndex(bi) : blockOuterIndex(bi); }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
|
|
|
|
/**
|
2013-09-20 18:54:17 +02:00
|
|
|
* \returns the starting index of the bj col block
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index blockColsIndex(Index bj) const { return IsColMajor ? blockOuterIndex(bj) : blockInnerIndex(bj); }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Index blockOuterIndex(Index bj) const {
|
|
|
|
|
return (m_blockSize == Dynamic) ? m_outerOffset[bj] : (bj * m_blockSize);
|
|
|
|
|
}
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index blockInnerIndex(Index bi) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
return (m_blockSize == Dynamic) ? m_innerOffset[bi] : (bi * m_blockSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Not needed ???
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index blockInnerSize(Index bi) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
return (m_blockSize == Dynamic) ? (m_innerOffset[bi + 1] - m_innerOffset[bi]) : m_blockSize;
|
|
|
|
|
}
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index blockOuterSize(Index bj) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
return (m_blockSize == Dynamic) ? (m_outerOffset[bj + 1] - m_outerOffset[bj]) : m_blockSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Browse the matrix by outer index
|
|
|
|
|
*/
|
|
|
|
|
class InnerIterator; // Browse column by column
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
/**
|
|
|
|
|
* \brief Browse the matrix by block outer index
|
|
|
|
|
*/
|
|
|
|
|
class BlockInnerIterator; // Browse block by block
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
friend std::ostream& operator<<(std::ostream& s, const BlockSparseMatrix& m) {
|
2014-12-04 22:48:53 +01:00
|
|
|
for (StorageIndex j = 0; j < m.outerBlocks(); ++j) {
|
2013-09-20 18:54:17 +02:00
|
|
|
BlockInnerIterator itb(m, j);
|
|
|
|
|
for (; itb; ++itb) {
|
|
|
|
|
s << "(" << itb.row() << ", " << itb.col() << ")\n";
|
|
|
|
|
s << itb.value() << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s << std::endl;
|
|
|
|
|
return s;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
2023-11-29 11:12:48 +00:00
|
|
|
/**
|
2018-10-19 21:10:28 +02:00
|
|
|
* \returns the starting position of the block \p id in the array of values
|
2023-11-29 11:12:48 +00:00
|
|
|
*/
|
2015-02-13 18:57:41 +01:00
|
|
|
Index blockPtr(Index id) const {
|
2013-09-20 18:54:17 +02:00
|
|
|
if (m_blockSize == Dynamic)
|
|
|
|
|
return m_blockPtr[id];
|
2023-11-29 11:12:48 +00:00
|
|
|
else
|
2013-09-20 18:54:17 +02:00
|
|
|
return id * m_blockSize * m_blockSize;
|
2022-03-16 16:43:40 +00:00
|
|
|
// return blockDynIdx(id, std::conditional_t<(BlockSize==Dynamic), internal::true_type, internal::false_type>());
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
// inline Index blockDynIdx(Index id, internal::true_type) const
|
|
|
|
|
// {
|
|
|
|
|
// return m_blockPtr[id];
|
|
|
|
|
// }
|
|
|
|
|
// inline Index blockDynIdx(Index id, internal::false_type) const
|
|
|
|
|
// {
|
|
|
|
|
// return id * BlockSize * BlockSize;
|
|
|
|
|
// }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
// To be implemented
|
|
|
|
|
// Insert a block at a particular location... need to make a room for that
|
|
|
|
|
Map<BlockScalar> insert(Index brow, Index bcol);
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2015-02-13 18:57:41 +01:00
|
|
|
Index m_innerBSize; // Number of block rows
|
|
|
|
|
Index m_outerBSize; // Number of block columns
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex* m_innerOffset; // Starting index of each inner block (size m_innerBSize+1)
|
|
|
|
|
StorageIndex* m_outerOffset; // Starting index of each outer block (size m_outerBSize+1)
|
2015-02-13 18:57:41 +01:00
|
|
|
Index m_nonzerosblocks; // Total nonzeros blocks (lower than m_innerBSize x m_outerBSize)
|
|
|
|
|
Index m_nonzeros; // Total nonzeros elements
|
2013-09-20 18:54:17 +02:00
|
|
|
Scalar* m_values; // Values stored block column after block column (size m_nonzeros)
|
2014-12-04 22:48:53 +01:00
|
|
|
StorageIndex* m_blockPtr; // Pointer to the beginning of each block in m_values, size m_nonzeroblocks ... null for
|
|
|
|
|
// fixed-size blocks
|
|
|
|
|
StorageIndex* m_indices; // Inner block indices, size m_nonzerosblocks ... OK
|
|
|
|
|
StorageIndex* m_outerIndex; // Starting pointer of each block column in m_indices (size m_outerBSize)... OK
|
2015-02-13 18:57:41 +01:00
|
|
|
Index m_blockSize; // Size of a block for fixed-size blocks, otherwise -1
|
2013-09-20 18:54:17 +02:00
|
|
|
};
|
|
|
|
|
|
2021-08-04 22:41:52 +00:00
|
|
|
template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_>
|
|
|
|
|
class BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_>::BlockInnerIterator {
|
2013-09-20 18:54:17 +02:00
|
|
|
public:
|
2021-08-04 22:41:52 +00:00
|
|
|
enum { Flags = Options_ };
|
2013-09-20 18:54:17 +02:00
|
|
|
|
2021-08-04 22:41:52 +00:00
|
|
|
BlockInnerIterator(const BlockSparseMatrix& mat, const Index outer)
|
2015-02-13 18:57:41 +01:00
|
|
|
: m_mat(mat), m_outer(outer), m_id(mat.m_outerIndex[outer]), m_end(mat.m_outerIndex[outer + 1]) {}
|
2013-09-20 18:54:17 +02:00
|
|
|
|
2015-02-13 18:57:41 +01:00
|
|
|
inline BlockInnerIterator& operator++() {
|
2013-09-20 18:54:17 +02:00
|
|
|
m_id++;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline const Map<const BlockScalar> value() const {
|
|
|
|
|
return Map<const BlockScalar>(&(m_mat.m_values[m_mat.blockPtr(m_id)]), rows(), cols());
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Map<BlockScalar> valueRef() {
|
|
|
|
|
return Map<BlockScalar>(&(m_mat.m_values[m_mat.blockPtr(m_id)]), rows(), cols());
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
// Block inner index
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index index() const { return m_mat.m_indices[m_id]; }
|
2013-09-20 18:54:17 +02:00
|
|
|
inline Index outer() const { return m_outer; }
|
|
|
|
|
// block row index
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index row() const { return index(); }
|
2013-09-20 18:54:17 +02:00
|
|
|
// block column index
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index col() const { return outer(); }
|
2013-09-20 18:54:17 +02:00
|
|
|
// FIXME Number of rows in the current block
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index rows() const {
|
2013-09-20 18:54:17 +02:00
|
|
|
return (m_mat.m_blockSize == Dynamic) ? (m_mat.m_innerOffset[index() + 1] - m_mat.m_innerOffset[index()])
|
2015-02-13 18:57:41 +01:00
|
|
|
: m_mat.m_blockSize;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
// Number of columns in the current block ...
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index cols() const {
|
|
|
|
|
return (m_mat.m_blockSize == Dynamic) ? (m_mat.m_outerOffset[m_outer + 1] - m_mat.m_outerOffset[m_outer])
|
|
|
|
|
: m_mat.m_blockSize;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
inline operator bool() const { return (m_id < m_end); }
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex>& m_mat;
|
2015-02-13 18:57:41 +01:00
|
|
|
const Index m_outer;
|
|
|
|
|
Index m_id;
|
|
|
|
|
Index m_end;
|
2013-09-20 18:54:17 +02:00
|
|
|
};
|
|
|
|
|
|
2021-08-04 22:41:52 +00:00
|
|
|
template <typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_>
|
|
|
|
|
class BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_>::InnerIterator {
|
2013-09-20 18:54:17 +02:00
|
|
|
public:
|
|
|
|
|
InnerIterator(const BlockSparseMatrix& mat, Index outer)
|
|
|
|
|
: m_mat(mat),
|
|
|
|
|
m_outerB(mat.outerToBlock(outer)),
|
|
|
|
|
m_outer(outer),
|
|
|
|
|
itb(mat, mat.outerToBlock(outer)),
|
|
|
|
|
m_offset(outer - mat.blockOuterIndex(m_outerB)) {
|
|
|
|
|
if (itb) {
|
|
|
|
|
m_id = m_mat.blockInnerIndex(itb.index());
|
|
|
|
|
m_start = m_id;
|
|
|
|
|
m_end = m_mat.blockInnerIndex(itb.index() + 1);
|
|
|
|
|
}
|
2015-02-13 18:57:41 +01:00
|
|
|
}
|
|
|
|
|
inline InnerIterator& operator++() {
|
2023-11-29 11:12:48 +00:00
|
|
|
m_id++;
|
2015-02-13 18:57:41 +01:00
|
|
|
if (m_id >= m_end) {
|
2023-11-29 11:12:48 +00:00
|
|
|
++itb;
|
|
|
|
|
if (itb) {
|
2015-02-13 18:57:41 +01:00
|
|
|
m_id = m_mat.blockInnerIndex(itb.index());
|
|
|
|
|
m_start = m_id;
|
|
|
|
|
m_end = m_mat.blockInnerIndex(itb.index() + 1);
|
|
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
}
|
|
|
|
|
return *this;
|
2023-11-29 11:12:48 +00:00
|
|
|
}
|
2013-09-20 18:54:17 +02:00
|
|
|
inline const Scalar& value() const { return itb.value().coeff(m_id - m_start, m_offset); }
|
|
|
|
|
inline Scalar& valueRef() { return itb.valueRef().coeff(m_id - m_start, m_offset); }
|
2015-02-13 18:57:41 +01:00
|
|
|
inline Index index() const { return m_id; }
|
|
|
|
|
inline Index outer() const { return m_outer; }
|
|
|
|
|
inline Index col() const { return outer(); }
|
|
|
|
|
inline Index row() const { return index(); }
|
2013-09-20 18:54:17 +02:00
|
|
|
inline operator bool() const { return itb; }
|
2023-11-29 11:12:48 +00:00
|
|
|
|
2013-09-20 18:54:17 +02:00
|
|
|
protected:
|
|
|
|
|
const BlockSparseMatrix& m_mat;
|
2015-02-13 18:57:41 +01:00
|
|
|
const Index m_outer;
|
|
|
|
|
const Index m_outerB;
|
2013-09-20 18:54:17 +02:00
|
|
|
BlockInnerIterator itb; // Iterator through the blocks
|
2015-02-13 18:57:41 +01:00
|
|
|
const Index m_offset; // Position of this column in the block
|
|
|
|
|
Index m_start; // starting inner index of this block
|
|
|
|
|
Index m_id; // current inner index in the block
|
|
|
|
|
Index m_end; // starting inner index of the next block
|
2013-09-20 18:54:17 +02:00
|
|
|
};
|
|
|
|
|
} // end namespace Eigen
|
|
|
|
|
|
|
|
|
|
#endif // EIGEN_SPARSEBLOCKMATRIX_H
|