| // 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 | 
 |  | 
 | #include "./InternalHeaderCheck.h" | 
 |  | 
 | 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. | 
 |   * | 
 |   * \tparam Scalar_ The Scalar type | 
 |   * \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 | 
 |   */ | 
 | template<typename Scalar_, int _BlockAtCompileTime=Dynamic, int Options_=ColMajor, typename StorageIndex_=int> class BlockSparseMatrix; | 
 |  | 
 | template<typename BlockSparseMatrixT> class BlockSparseMatrixView; | 
 |  | 
 | namespace internal { | 
 | template<typename Scalar_, int _BlockAtCompileTime, int Options_, typename Index_> | 
 | struct traits<BlockSparseMatrix<Scalar_,_BlockAtCompileTime,Options_, Index_> > | 
 | { | 
 |   typedef Scalar_ Scalar; | 
 |   typedef Index_ Index; | 
 |   typedef Sparse StorageKind; // FIXME Where is it used ?? | 
 |   typedef MatrixXpr XprKind; | 
 |   enum { | 
 |     RowsAtCompileTime = Dynamic, | 
 |     ColsAtCompileTime = Dynamic, | 
 |     MaxRowsAtCompileTime = Dynamic, | 
 |     MaxColsAtCompileTime = Dynamic, | 
 |     BlockSize = _BlockAtCompileTime, | 
 |     Flags = Options_ | NestByRefBit | LvalueBit, | 
 |     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 | 
 |     }; | 
 |   public: | 
 |     BlockSparseMatrixView(const BlockSparseMatrixT& spblockmat) | 
 |      : m_spblockmat(spblockmat) | 
 |     {} | 
 |  | 
 |     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) | 
 |       {} | 
 |  | 
 |     }; | 
 |  | 
 |   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; | 
 |   public: | 
 |     BlockVectorView(const BlockSparseMatrixT& spblockmat, const VectorType& vec) | 
 |     : m_spblockmat(spblockmat),m_vec(vec) | 
 |     { } | 
 |     inline Index cols() const | 
 |     { | 
 |       return m_vec.cols(); | 
 |     } | 
 |     inline Index size() const | 
 |     { | 
 |       return m_spblockmat.blockRows(); | 
 |     } | 
 |     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); | 
 |     } | 
 |     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); | 
 |     } | 
 |   protected: | 
 |     const BlockSparseMatrixT& m_spblockmat; | 
 |     const VectorType& m_vec; | 
 | }; | 
 |  | 
 | 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; | 
 |   public: | 
 |     BlockVectorReturn(const BlockSparseMatrixT& spblockmat, VectorType& vec) | 
 |     : m_spblockmat(spblockmat),m_vec(vec) | 
 |     { } | 
 |     inline Index size() const | 
 |     { | 
 |       return m_spblockmat.blockRows(); | 
 |     } | 
 |     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); | 
 |     } | 
 |     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); | 
 |     } | 
 |  | 
 |   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 | 
 |  | 
 | template<typename Lhs, typename Rhs> | 
 | class BlockSparseTimeDenseProduct | 
 |   : public ProductBase<BlockSparseTimeDenseProduct<Lhs,Rhs>, Lhs, Rhs> | 
 | { | 
 |   public: | 
 |     EIGEN_PRODUCT_PUBLIC_INTERFACE(BlockSparseTimeDenseProduct) | 
 |  | 
 |     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); | 
 |     } | 
 |  | 
 |   private: | 
 |     BlockSparseTimeDenseProduct& operator=(const BlockSparseTimeDenseProduct&); | 
 | }; | 
 |  | 
 | template<typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_> | 
 | class BlockSparseMatrix : public SparseMatrixBase<BlockSparseMatrix<Scalar_,_BlockAtCompileTime, Options_,StorageIndex_> > | 
 | { | 
 |   public: | 
 |     typedef Scalar_ Scalar; | 
 |     typedef typename NumTraits<Scalar>::Real RealScalar; | 
 |     typedef StorageIndex_ StorageIndex; | 
 |     typedef typename internal::ref_selector<BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_> >::type Nested; | 
 |  | 
 |     enum { | 
 |       Options = Options_, | 
 |       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; | 
 |     typedef typename internal::conditional<_BlockAtCompileTime==Dynamic, Scalar, BlockScalar>::type BlockScalarReturnType; | 
 |     typedef BlockSparseMatrix<Scalar, BlockSize, IsColMajor ? ColMajor : RowMajor, StorageIndex> PlainObject; | 
 |   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) | 
 |     { } | 
 |  | 
 |  | 
 |     /** | 
 |      * \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), | 
 |         m_values(0),m_blockPtr(0),m_indices(0), | 
 |         m_outerIndex(0),m_blockSize(BlockSize) | 
 |     { } | 
 |  | 
 |     /** | 
 |      * \brief Copy-constructor | 
 |      */ | 
 |     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"); | 
 |  | 
 |       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); | 
 |  | 
 |       if(m_blockSize != Dynamic) | 
 |         std::copy(other.m_blockPtr, other.m_blockPtr+m_nonzerosblocks, m_blockPtr); | 
 |  | 
 |       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 | 
 |       * | 
 |       */ | 
 |     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; | 
 |     } | 
 |  | 
 |     /** | 
 |       * \brief Assignment from a sparse matrix with the same storage order | 
 |       * | 
 |       * 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; | 
 |  | 
 |       // First, compute the number of nonzero blocks and their locations | 
 |       for(StorageIndex bj = 0; bj < m_outerBSize; ++bj) | 
 |       { | 
 |         // Browse each outer block and compute the structure | 
 |         std::vector<bool> nzblocksFlag(m_innerBSize,false);  // Record the existing blocks | 
 |         blockPattern.startVec(bj); | 
 |         for(StorageIndex j = blockOuterIndex(bj); j < blockOuterIndex(bj+1); ++j) | 
 |         { | 
 |           typename MatrixType::InnerIterator it_spmat(spmat, j); | 
 |           for(; it_spmat; ++it_spmat) | 
 |           { | 
 |             StorageIndex bi = innerToBlock(it_spmat.index()); // Index of the current nonzero block | 
 |             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); | 
 |             } | 
 |           } | 
 |         } // end current outer block | 
 |       } | 
 |       blockPattern.finalize(); | 
 |  | 
 |       // Allocate the internal arrays | 
 |       setBlockStructure(blockPattern); | 
 |  | 
 |       for(StorageIndex nz = 0; nz < m_nonzeros; ++nz) m_values[nz] = Scalar(0); | 
 |       for(StorageIndex bj = 0; bj < m_outerBSize; ++bj) | 
 |       { | 
 |         // Now copy the values | 
 |         for(StorageIndex j = blockOuterIndex(bj); j < blockOuterIndex(bj+1); ++j) | 
 |         { | 
 |           // Browse the outer block column by column (for column-major matrices) | 
 |           typename MatrixType::InnerIterator it_spmat(spmat, j); | 
 |           for(; it_spmat; ++it_spmat) | 
 |           { | 
 |             StorageIndex idx = 0; // Position of this block in the column block | 
 |             StorageIndex bi = innerToBlock(it_spmat.index()); // Index of the current nonzero block | 
 |             // 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]; | 
 |             } | 
 |             else | 
 |             { | 
 |               // 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); | 
 |             } | 
 |             // 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). | 
 |       * | 
 |       * | 
 |       * \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 | 
 |       * | 
 |       * \sa setBlockLayout() \sa setBlockSize() | 
 |       */ | 
 |     template<typename MatrixType> | 
 |     void setBlockStructure(const MatrixType& blockPattern) | 
 |     { | 
 |       resize(blockPattern.rows(), blockPattern.cols()); | 
 |       reserve(blockPattern.nonZeros()); | 
 |  | 
 |       // Browse the block pattern and set up the various pointers | 
 |       m_outerIndex[0] = 0; | 
 |       if(m_blockSize == Dynamic) m_blockPtr[0] = 0; | 
 |       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 | 
 |  | 
 |         //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()); | 
 |         } | 
 |         std::sort(nzBlockIdx.begin(), nzBlockIdx.end()); | 
 |  | 
 |         // 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(); | 
 |       } | 
 |     } | 
 |  | 
 |     /** | 
 |       * \brief Set the number of rows and columns blocks | 
 |       */ | 
 |     inline void resize(Index brow, Index bcol) | 
 |     { | 
 |       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 | 
 |       */ | 
 |     inline void setBlockSize(Index blockSize) | 
 |     { | 
 |       m_blockSize = blockSize; | 
 |     } | 
 |  | 
 |     /** | 
 |       * \brief Set the row and column block layouts, | 
 |       * | 
 |       * 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() | 
 |       */ | 
 |     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 | 
 |       m_innerOffset = new StorageIndex[m_innerBSize+1]; | 
 |       m_outerOffset = new StorageIndex[m_outerBSize+1]; | 
 |       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]); | 
 |  | 
 |       // Compute the total number of nonzeros | 
 |       m_nonzeros = 0; | 
 |       for(StorageIndex bj = 0; bj < m_outerBSize; ++bj) | 
 |         for(StorageIndex bi = 0; bi < m_innerBSize; ++bi) | 
 |           m_nonzeros += outerBlocks[bj] * innerBlocks[bi]; | 
 |  | 
 |     } | 
 |  | 
 |     /** | 
 |       * \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 | 
 |       * | 
 |       * \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"); | 
 |  | 
 |       //FIXME Should free if already allocated | 
 |       m_outerIndex = new StorageIndex[m_outerBSize+1]; | 
 |  | 
 |       m_nonzerosblocks = nonzerosblocks; | 
 |       if(m_blockSize != Dynamic) | 
 |       { | 
 |         m_nonzeros = nonzerosblocks * (m_blockSize * m_blockSize); | 
 |         m_blockPtr = 0; | 
 |       } | 
 |       else | 
 |       { | 
 |         // m_nonzeros  is already computed in setBlockLayout() | 
 |         m_blockPtr = new StorageIndex[m_nonzerosblocks+1]; | 
 |       } | 
 |       m_indices = new StorageIndex[m_nonzerosblocks+1]; | 
 |       m_values = new Scalar[m_nonzeros]; | 
 |     } | 
 |  | 
 |  | 
 |     /** | 
 |       * \brief Fill values in a matrix  from a triplet list. | 
 |       * | 
 |       * Each triplet item has a block stored in an Eigen dense matrix. | 
 |       * The InputIterator class should provide the functions row(), col() and value() | 
 |       * | 
 |       * \note For fixed-size blocks, call setBlockSize() before this function. | 
 |       * | 
 |       * FIXME Do not accept duplicates | 
 |       */ | 
 |     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"); | 
 |  | 
 |       /* 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() | 
 |         */ | 
 |       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 | 
 |       nzblock_outer.setZero(); | 
 |       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)); | 
 |  | 
 |         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())++; | 
 |       } | 
 |       // Allocate member arrays | 
 |       if(m_blockSize == Dynamic) setBlockLayout(rowBlocks, colBlocks); | 
 |       StorageIndex nzblocks = nzblock_outer.sum(); | 
 |       reserve(nzblocks); | 
 |  | 
 |        // Temporary markers | 
 |       VectorXi block_id(m_outerBSize); // To be used as a block marker during insertion | 
 |  | 
 |       // Setup outer index pointers and markers | 
 |       m_outerIndex[0] = 0; | 
 |       if (m_blockSize == Dynamic)  m_blockPtr[0] =  0; | 
 |       for(StorageIndex bj = 0; bj < m_outerBSize; ++bj) | 
 |       { | 
 |         m_outerIndex[bj+1] = m_outerIndex[bj] + nzblock_outer(bj); | 
 |         block_id(bj) = m_outerIndex[bj]; | 
 |         if(m_blockSize==Dynamic) | 
 |         { | 
 |           m_blockPtr[m_outerIndex[bj+1]] = m_blockPtr[m_outerIndex[bj]] + nz_outer(bj); | 
 |         } | 
 |       } | 
 |  | 
 |       // 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(); | 
 |         StorageIndex nz_marker = blockPtr(block_id[outer]); | 
 |         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)++; | 
 |       } | 
 |  | 
 |       // An alternative when the outer indices are sorted...no need to use an array of markers | 
 | //      for(Index bcol = 0; bcol < m_outerBSize; ++bcol) | 
 | //      { | 
 | //      Index id = 0, id_nz = 0, id_nzblock = 0; | 
 | //      for(InputIterator it(begin); it!=end; ++it) | 
 | //      { | 
 | //        while (id<bcol) // one pass should do the job unless there are empty columns | 
 | //        { | 
 | //          id++; | 
 | //          m_outerIndex[id+1]=m_outerIndex[id]; | 
 | //        } | 
 | //        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; | 
 | //      } | 
 | //      while(id < m_outerBSize-1) // Empty columns at the end | 
 | //      { | 
 | //        id++; | 
 | //        m_outerIndex[id+1]=m_outerIndex[id]; | 
 | //      } | 
 | //      } | 
 |     } | 
 |  | 
 |  | 
 |     /** | 
 |       * \returns the number of rows | 
 |       */ | 
 |     inline Index rows() const | 
 |     { | 
 | //      return blockRows(); | 
 |       return (IsColMajor ? innerSize() : outerSize()); | 
 |     } | 
 |  | 
 |     /** | 
 |       * \returns the number of cols | 
 |       */ | 
 |     inline Index cols() const | 
 |     { | 
 | //      return blockCols(); | 
 |       return (IsColMajor ? outerSize() : innerSize()); | 
 |     } | 
 |  | 
 |     inline Index innerSize() const | 
 |     { | 
 |       if(m_blockSize == Dynamic) return m_innerOffset[m_innerBSize]; | 
 |       else return  (m_innerBSize * m_blockSize) ; | 
 |     } | 
 |  | 
 |     inline Index outerSize() const | 
 |     { | 
 |       if(m_blockSize == Dynamic) return m_outerOffset[m_outerBSize]; | 
 |       else return  (m_outerBSize * m_blockSize) ; | 
 |     } | 
 |     /** \returns the number of rows grouped by blocks */ | 
 |     inline Index blockRows() const | 
 |     { | 
 |       return (IsColMajor ? m_innerBSize : m_outerBSize); | 
 |     } | 
 |     /** \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 */ | 
 |     inline Index outerToBlock(Index outer) const | 
 |     { | 
 |       eigen_assert(outer < outerSize() && "OUTER INDEX OUT OF BOUNDS"); | 
 |  | 
 |       if(m_blockSize != Dynamic) | 
 |         return (outer / m_blockSize); // Integer division | 
 |  | 
 |       StorageIndex b_outer = 0; | 
 |       while(m_outerOffset[b_outer] <= outer) ++b_outer; | 
 |       return b_outer - 1; | 
 |     } | 
 |     /** \returns  the block index where inner belongs to */ | 
 |     inline Index innerToBlock(Index inner) const | 
 |     { | 
 |       eigen_assert(inner < innerSize() && "OUTER INDEX OUT OF BOUNDS"); | 
 |  | 
 |       if(m_blockSize != Dynamic) | 
 |         return (inner / m_blockSize); // Integer division | 
 |  | 
 |       StorageIndex b_inner = 0; | 
 |       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"); | 
 |  | 
 |       StorageIndex rsize = IsColMajor ? blockInnerSize(brow): blockOuterSize(bcol); | 
 |       StorageIndex csize = IsColMajor ? blockOuterSize(bcol) : blockInnerSize(brow); | 
 |       StorageIndex inner = IsColMajor ? brow : bcol; | 
 |       StorageIndex outer = IsColMajor ? bcol : brow; | 
 |       StorageIndex offset = m_outerIndex[outer]; | 
 |       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); | 
 |       } | 
 |       else | 
 |       { | 
 |         //FIXME the block does not exist, Insert it !!!!!!!!! | 
 |         eigen_assert("DYNAMIC INSERTION IS NOT YET SUPPORTED"); | 
 |       } | 
 |     } | 
 |  | 
 |     /** | 
 |       * \returns the value of the (i,j) block as an Eigen Dense Matrix | 
 |       */ | 
 |     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"); | 
 |  | 
 |       StorageIndex rsize = IsColMajor ? blockInnerSize(brow): blockOuterSize(bcol); | 
 |       StorageIndex csize = IsColMajor ? blockOuterSize(bcol) : blockInnerSize(brow); | 
 |       StorageIndex inner = IsColMajor ? brow : bcol; | 
 |       StorageIndex outer = IsColMajor ? bcol : brow; | 
 |       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); | 
 |       } | 
 |       else | 
 | //        return BlockScalar::Zero(rsize, csize); | 
 |         eigen_assert("NOT YET SUPPORTED"); | 
 |     } | 
 |  | 
 |     // Block Matrix times vector product | 
 |     template<typename VecType> | 
 |     BlockSparseTimeDenseProduct<BlockSparseMatrix, VecType> operator*(const VecType& lhs) const | 
 |     { | 
 |       return BlockSparseTimeDenseProduct<BlockSparseMatrix, VecType>(*this, lhs); | 
 |     } | 
 |  | 
 |     /** \returns the number of nonzero blocks */ | 
 |     inline Index nonZerosBlocks() const { return m_nonzerosblocks; } | 
 |     /** \returns the total number of nonzero elements, including eventual explicit zeros in blocks */ | 
 |     inline Index nonZeros() const { return m_nonzeros; } | 
 |  | 
 |     inline BlockScalarReturnType *valuePtr() {return static_cast<BlockScalarReturnType *>(m_values);} | 
 | //    inline Scalar *valuePtr(){ return m_values; } | 
 |     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; } | 
 |  | 
 |     /** \brief for compatibility purposes with the SparseMatrix class */ | 
 |     inline bool isCompressed() const {return true;} | 
 |     /** | 
 |       * \returns the starting index of the bi row block | 
 |       */ | 
 |     inline Index blockRowsIndex(Index bi) const | 
 |     { | 
 |       return IsColMajor ? blockInnerIndex(bi) : blockOuterIndex(bi); | 
 |     } | 
 |  | 
 |     /** | 
 |       * \returns the starting index of the bj col block | 
 |       */ | 
 |     inline Index blockColsIndex(Index bj) const | 
 |     { | 
 |       return IsColMajor ? blockOuterIndex(bj) : blockInnerIndex(bj); | 
 |     } | 
 |  | 
 |     inline Index blockOuterIndex(Index bj) const | 
 |     { | 
 |       return (m_blockSize == Dynamic) ? m_outerOffset[bj] : (bj * m_blockSize); | 
 |     } | 
 |     inline Index blockInnerIndex(Index bi) const | 
 |     { | 
 |       return (m_blockSize == Dynamic) ? m_innerOffset[bi] : (bi * m_blockSize); | 
 |     } | 
 |  | 
 |     // Not needed ??? | 
 |     inline Index blockInnerSize(Index bi) const | 
 |     { | 
 |       return (m_blockSize == Dynamic) ? (m_innerOffset[bi+1] - m_innerOffset[bi]) : m_blockSize; | 
 |     } | 
 |     inline Index blockOuterSize(Index bj) const | 
 |     { | 
 |       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 | 
 |  | 
 |     /** | 
 |       * \brief Browse the matrix by block outer index | 
 |       */ | 
 |     class BlockInnerIterator; // Browse block by block | 
 |  | 
 |     friend std::ostream & operator << (std::ostream & s, const BlockSparseMatrix& m) | 
 |     { | 
 |       for (StorageIndex j = 0; j < m.outerBlocks(); ++j) | 
 |       { | 
 |         BlockInnerIterator itb(m, j); | 
 |         for(; itb; ++itb) | 
 |         { | 
 |           s << "("<<itb.row() << ", " << itb.col() << ")\n"; | 
 |           s << itb.value() <<"\n"; | 
 |         } | 
 |       } | 
 |       s << std::endl; | 
 |       return s; | 
 |     } | 
 |  | 
 |     /** | 
 |       * \returns the starting position of the block \p id in the array of values | 
 |       */ | 
 |     Index blockPtr(Index id) const | 
 |     { | 
 |       if(m_blockSize == Dynamic) return m_blockPtr[id]; | 
 |       else return id * m_blockSize * m_blockSize; | 
 |       //return blockDynIdx(id, typename internal::conditional<(BlockSize==Dynamic), internal::true_type, internal::false_type>::type()); | 
 |     } | 
 |  | 
 |  | 
 |   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; | 
 | //    } | 
 |  | 
 |     // To be implemented | 
 |     // Insert a block at a particular location... need to make a room for that | 
 |     Map<BlockScalar> insert(Index brow, Index bcol); | 
 |  | 
 |     Index m_innerBSize; // Number of block rows | 
 |     Index m_outerBSize; // Number of block columns | 
 |     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) | 
 |     Index m_nonzerosblocks; // Total nonzeros blocks (lower than  m_innerBSize x m_outerBSize) | 
 |     Index m_nonzeros; // Total nonzeros elements | 
 |     Scalar *m_values; //Values stored block column after block column (size m_nonzeros) | 
 |     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 | 
 |     Index m_blockSize; // Size of a block for fixed-size blocks, otherwise -1 | 
 | }; | 
 |  | 
 | template<typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_> | 
 | class BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_>::BlockInnerIterator | 
 | { | 
 |   public: | 
 |  | 
 |     enum{ | 
 |       Flags = Options_ | 
 |     }; | 
 |  | 
 |     BlockInnerIterator(const BlockSparseMatrix& mat, const Index outer) | 
 |     : m_mat(mat),m_outer(outer), | 
 |       m_id(mat.m_outerIndex[outer]), | 
 |       m_end(mat.m_outerIndex[outer+1]) | 
 |     { | 
 |     } | 
 |  | 
 |     inline BlockInnerIterator& operator++() {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()); | 
 |     } | 
 |     inline Map<BlockScalar> valueRef() | 
 |     { | 
 |       return Map<BlockScalar>(&(m_mat.m_values[m_mat.blockPtr(m_id)]), | 
 |           rows(),cols()); | 
 |     } | 
 |     // Block inner index | 
 |     inline Index index() const {return m_mat.m_indices[m_id]; } | 
 |     inline Index outer() const { return m_outer; } | 
 |     // block row index | 
 |     inline Index row() const  {return index(); } | 
 |     // block column index | 
 |     inline Index col() const {return outer(); } | 
 |     // FIXME Number of rows in the current block | 
 |     inline Index rows() const { return (m_mat.m_blockSize==Dynamic) ? (m_mat.m_innerOffset[index()+1] - m_mat.m_innerOffset[index()]) : m_mat.m_blockSize; } | 
 |     // Number of columns in the current block ... | 
 |     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;} | 
 |     inline operator bool() const { return (m_id < m_end); } | 
 |  | 
 |   protected: | 
 |     const BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex>& m_mat; | 
 |     const Index m_outer; | 
 |     Index m_id; | 
 |     Index m_end; | 
 | }; | 
 |  | 
 | template<typename Scalar_, int _BlockAtCompileTime, int Options_, typename StorageIndex_> | 
 | class BlockSparseMatrix<Scalar_, _BlockAtCompileTime, Options_, StorageIndex_>::InnerIterator | 
 | { | 
 |   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); | 
 |         } | 
 |      } | 
 |     inline InnerIterator& operator++() | 
 |     { | 
 |       m_id++; | 
 |       if (m_id >= m_end) | 
 |       { | 
 |         ++itb; | 
 |         if (itb) | 
 |         { | 
 |           m_id = m_mat.blockInnerIndex(itb.index()); | 
 |           m_start = m_id; | 
 |           m_end = m_mat.blockInnerIndex(itb.index()+1); | 
 |         } | 
 |       } | 
 |       return *this; | 
 |     } | 
 |     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); | 
 |     } | 
 |     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();} | 
 |     inline operator bool() const | 
 |     { | 
 |       return itb; | 
 |     } | 
 |   protected: | 
 |     const BlockSparseMatrix& m_mat; | 
 |     const Index m_outer; | 
 |     const Index m_outerB; | 
 |     BlockInnerIterator itb; // Iterator through the blocks | 
 |     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 | 
 |  | 
 | }; | 
 | } // end namespace Eigen | 
 |  | 
 | #endif // EIGEN_SPARSEBLOCKMATRIX_H |