cart-elc

Source code for CART-ELC
git clone git://git.laack.co/cart-elc.git
Log | Files | Refs | README | LICENSE

SparseBlock.h (24360B)


      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
      5 //
      6 // This Source Code Form is subject to the terms of the Mozilla
      7 // Public License v. 2.0. If a copy of the MPL was not distributed
      8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 
     10 #ifndef EIGEN_SPARSE_BLOCK_H
     11 #define EIGEN_SPARSE_BLOCK_H
     12 
     13 namespace Eigen {
     14 
     15 // Subset of columns or rows
     16 template<typename XprType, int BlockRows, int BlockCols>
     17 class BlockImpl<XprType,BlockRows,BlockCols,true,Sparse>
     18   : public SparseMatrixBase<Block<XprType,BlockRows,BlockCols,true> >
     19 {
     20     typedef typename internal::remove_all<typename XprType::Nested>::type _MatrixTypeNested;
     21     typedef Block<XprType, BlockRows, BlockCols, true> BlockType;
     22 public:
     23     enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
     24 protected:
     25     enum { OuterSize = IsRowMajor ? BlockRows : BlockCols };
     26     typedef SparseMatrixBase<BlockType> Base;
     27     using Base::convert_index;
     28 public:
     29     EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
     30 
     31     inline BlockImpl(XprType& xpr, Index i)
     32       : m_matrix(xpr), m_outerStart(convert_index(i)), m_outerSize(OuterSize)
     33     {}
     34 
     35     inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols)
     36       : m_matrix(xpr), m_outerStart(convert_index(IsRowMajor ? startRow : startCol)), m_outerSize(convert_index(IsRowMajor ? blockRows : blockCols))
     37     {}
     38 
     39     EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
     40     EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
     41 
     42     Index nonZeros() const
     43     {
     44       typedef internal::evaluator<XprType> EvaluatorType;
     45       EvaluatorType matEval(m_matrix);
     46       Index nnz = 0;
     47       Index end = m_outerStart + m_outerSize.value();
     48       for(Index j=m_outerStart; j<end; ++j)
     49         for(typename EvaluatorType::InnerIterator it(matEval, j); it; ++it)
     50           ++nnz;
     51       return nnz;
     52     }
     53 
     54     inline const Scalar coeff(Index row, Index col) const
     55     {
     56       return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 :  m_outerStart));
     57     }
     58 
     59     inline const Scalar coeff(Index index) const
     60     {
     61       return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index :  m_outerStart);
     62     }
     63 
     64     inline const XprType& nestedExpression() const { return m_matrix; }
     65     inline XprType& nestedExpression() { return m_matrix; }
     66     Index startRow() const { return IsRowMajor ? m_outerStart : 0; }
     67     Index startCol() const { return IsRowMajor ? 0 : m_outerStart; }
     68     Index blockRows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
     69     Index blockCols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
     70 
     71   protected:
     72 
     73     typename internal::ref_selector<XprType>::non_const_type m_matrix;
     74     Index m_outerStart;
     75     const internal::variable_if_dynamic<Index, OuterSize> m_outerSize;
     76 
     77   protected:
     78     // Disable assignment with clear error message.
     79     // Note that simply removing operator= yields compilation errors with ICC+MSVC
     80     template<typename T>
     81     BlockImpl& operator=(const T&)
     82     {
     83       EIGEN_STATIC_ASSERT(sizeof(T)==0, THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY);
     84       return *this;
     85     }
     86 };
     87 
     88 
     89 /***************************************************************************
     90 * specialization for SparseMatrix
     91 ***************************************************************************/
     92 
     93 namespace internal {
     94 
     95 template<typename SparseMatrixType, int BlockRows, int BlockCols>
     96 class sparse_matrix_block_impl
     97   : public SparseCompressedBase<Block<SparseMatrixType,BlockRows,BlockCols,true> >
     98 {
     99     typedef typename internal::remove_all<typename SparseMatrixType::Nested>::type _MatrixTypeNested;
    100     typedef Block<SparseMatrixType, BlockRows, BlockCols, true> BlockType;
    101     typedef SparseCompressedBase<Block<SparseMatrixType,BlockRows,BlockCols,true> > Base;
    102     using Base::convert_index;
    103 public:
    104     enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
    105     EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
    106 protected:
    107     typedef typename Base::IndexVector IndexVector;
    108     enum { OuterSize = IsRowMajor ? BlockRows : BlockCols };
    109 public:
    110 
    111     inline sparse_matrix_block_impl(SparseMatrixType& xpr, Index i)
    112       : m_matrix(xpr), m_outerStart(convert_index(i)), m_outerSize(OuterSize)
    113     {}
    114 
    115     inline sparse_matrix_block_impl(SparseMatrixType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols)
    116       : m_matrix(xpr), m_outerStart(convert_index(IsRowMajor ? startRow : startCol)), m_outerSize(convert_index(IsRowMajor ? blockRows : blockCols))
    117     {}
    118 
    119     template<typename OtherDerived>
    120     inline BlockType& operator=(const SparseMatrixBase<OtherDerived>& other)
    121     {
    122       typedef typename internal::remove_all<typename SparseMatrixType::Nested>::type _NestedMatrixType;
    123       _NestedMatrixType& matrix = m_matrix;
    124       // This assignment is slow if this vector set is not empty
    125       // and/or it is not at the end of the nonzeros of the underlying matrix.
    126 
    127       // 1 - eval to a temporary to avoid transposition and/or aliasing issues
    128       Ref<const SparseMatrix<Scalar, IsRowMajor ? RowMajor : ColMajor, StorageIndex> > tmp(other.derived());
    129       eigen_internal_assert(tmp.outerSize()==m_outerSize.value());
    130 
    131       // 2 - let's check whether there is enough allocated memory
    132       Index nnz           = tmp.nonZeros();
    133       Index start         = m_outerStart==0 ? 0 : m_matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block
    134       Index end           = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; // ending position of the current block
    135       Index block_size    = end - start;                                                // available room in the current block
    136       Index tail_size     = m_matrix.outerIndexPtr()[m_matrix.outerSize()] - end;
    137 
    138       Index free_size     = m_matrix.isCompressed()
    139                           ? Index(matrix.data().allocatedSize()) + block_size
    140                           : block_size;
    141 
    142       Index tmp_start = tmp.outerIndexPtr()[0];
    143 
    144       bool update_trailing_pointers = false;
    145       if(nnz>free_size)
    146       {
    147         // realloc manually to reduce copies
    148         typename SparseMatrixType::Storage newdata(m_matrix.data().allocatedSize() - block_size + nnz);
    149 
    150         internal::smart_copy(m_matrix.valuePtr(),       m_matrix.valuePtr() + start,      newdata.valuePtr());
    151         internal::smart_copy(m_matrix.innerIndexPtr(),  m_matrix.innerIndexPtr() + start, newdata.indexPtr());
    152 
    153         internal::smart_copy(tmp.valuePtr() + tmp_start,      tmp.valuePtr() + tmp_start + nnz,       newdata.valuePtr() + start);
    154         internal::smart_copy(tmp.innerIndexPtr() + tmp_start, tmp.innerIndexPtr() + tmp_start + nnz,  newdata.indexPtr() + start);
    155 
    156         internal::smart_copy(matrix.valuePtr()+end,       matrix.valuePtr()+end + tail_size,      newdata.valuePtr()+start+nnz);
    157         internal::smart_copy(matrix.innerIndexPtr()+end,  matrix.innerIndexPtr()+end + tail_size, newdata.indexPtr()+start+nnz);
    158 
    159         newdata.resize(m_matrix.outerIndexPtr()[m_matrix.outerSize()] - block_size + nnz);
    160 
    161         matrix.data().swap(newdata);
    162 
    163         update_trailing_pointers = true;
    164       }
    165       else
    166       {
    167         if(m_matrix.isCompressed() && nnz!=block_size)
    168         {
    169           // no need to realloc, simply copy the tail at its respective position and insert tmp
    170           matrix.data().resize(start + nnz + tail_size);
    171 
    172           internal::smart_memmove(matrix.valuePtr()+end,      matrix.valuePtr() + end+tail_size,      matrix.valuePtr() + start+nnz);
    173           internal::smart_memmove(matrix.innerIndexPtr()+end, matrix.innerIndexPtr() + end+tail_size, matrix.innerIndexPtr() + start+nnz);
    174 
    175           update_trailing_pointers = true;
    176         }
    177 
    178         internal::smart_copy(tmp.valuePtr() + tmp_start,      tmp.valuePtr() + tmp_start + nnz,       matrix.valuePtr() + start);
    179         internal::smart_copy(tmp.innerIndexPtr() + tmp_start, tmp.innerIndexPtr() + tmp_start + nnz,  matrix.innerIndexPtr() + start);
    180       }
    181 
    182       // update outer index pointers and innerNonZeros
    183       if(IsVectorAtCompileTime)
    184       {
    185         if(!m_matrix.isCompressed())
    186           matrix.innerNonZeroPtr()[m_outerStart] = StorageIndex(nnz);
    187         matrix.outerIndexPtr()[m_outerStart] = StorageIndex(start);
    188       }
    189       else
    190       {
    191         StorageIndex p = StorageIndex(start);
    192         for(Index k=0; k<m_outerSize.value(); ++k)
    193         {
    194           StorageIndex nnz_k = internal::convert_index<StorageIndex>(tmp.innerVector(k).nonZeros());
    195           if(!m_matrix.isCompressed())
    196             matrix.innerNonZeroPtr()[m_outerStart+k] = nnz_k;
    197           matrix.outerIndexPtr()[m_outerStart+k] = p;
    198           p += nnz_k;
    199         }
    200       }
    201 
    202       if(update_trailing_pointers)
    203       {
    204         StorageIndex offset = internal::convert_index<StorageIndex>(nnz - block_size);
    205         for(Index k = m_outerStart + m_outerSize.value(); k<=matrix.outerSize(); ++k)
    206         {
    207           matrix.outerIndexPtr()[k] += offset;
    208         }
    209       }
    210 
    211       return derived();
    212     }
    213 
    214     inline BlockType& operator=(const BlockType& other)
    215     {
    216       return operator=<BlockType>(other);
    217     }
    218 
    219     inline const Scalar* valuePtr() const
    220     { return m_matrix.valuePtr(); }
    221     inline Scalar* valuePtr()
    222     { return m_matrix.valuePtr(); }
    223 
    224     inline const StorageIndex* innerIndexPtr() const
    225     { return m_matrix.innerIndexPtr(); }
    226     inline StorageIndex* innerIndexPtr()
    227     { return m_matrix.innerIndexPtr(); }
    228 
    229     inline const StorageIndex* outerIndexPtr() const
    230     { return m_matrix.outerIndexPtr() + m_outerStart; }
    231     inline StorageIndex* outerIndexPtr()
    232     { return m_matrix.outerIndexPtr() + m_outerStart; }
    233 
    234     inline const StorageIndex* innerNonZeroPtr() const
    235     { return isCompressed() ? 0 : (m_matrix.innerNonZeroPtr()+m_outerStart); }
    236     inline StorageIndex* innerNonZeroPtr()
    237     { return isCompressed() ? 0 : (m_matrix.innerNonZeroPtr()+m_outerStart); }
    238 
    239     bool isCompressed() const { return m_matrix.innerNonZeroPtr()==0; }
    240 
    241     inline Scalar& coeffRef(Index row, Index col)
    242     {
    243       return m_matrix.coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 :  m_outerStart));
    244     }
    245 
    246     inline const Scalar coeff(Index row, Index col) const
    247     {
    248       return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 :  m_outerStart));
    249     }
    250 
    251     inline const Scalar coeff(Index index) const
    252     {
    253       return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index :  m_outerStart);
    254     }
    255 
    256     const Scalar& lastCoeff() const
    257     {
    258       EIGEN_STATIC_ASSERT_VECTOR_ONLY(sparse_matrix_block_impl);
    259       eigen_assert(Base::nonZeros()>0);
    260       if(m_matrix.isCompressed())
    261         return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1];
    262       else
    263         return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart]+m_matrix.innerNonZeroPtr()[m_outerStart]-1];
    264     }
    265 
    266     EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
    267     EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
    268 
    269     inline const SparseMatrixType& nestedExpression() const { return m_matrix; }
    270     inline SparseMatrixType& nestedExpression() { return m_matrix; }
    271     Index startRow() const { return IsRowMajor ? m_outerStart : 0; }
    272     Index startCol() const { return IsRowMajor ? 0 : m_outerStart; }
    273     Index blockRows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
    274     Index blockCols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
    275 
    276   protected:
    277 
    278     typename internal::ref_selector<SparseMatrixType>::non_const_type m_matrix;
    279     Index m_outerStart;
    280     const internal::variable_if_dynamic<Index, OuterSize> m_outerSize;
    281 
    282 };
    283 
    284 } // namespace internal
    285 
    286 template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
    287 class BlockImpl<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true,Sparse>
    288   : public internal::sparse_matrix_block_impl<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols>
    289 {
    290 public:
    291   typedef _StorageIndex StorageIndex;
    292   typedef SparseMatrix<_Scalar, _Options, _StorageIndex> SparseMatrixType;
    293   typedef internal::sparse_matrix_block_impl<SparseMatrixType,BlockRows,BlockCols> Base;
    294   inline BlockImpl(SparseMatrixType& xpr, Index i)
    295     : Base(xpr, i)
    296   {}
    297 
    298   inline BlockImpl(SparseMatrixType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols)
    299     : Base(xpr, startRow, startCol, blockRows, blockCols)
    300   {}
    301 
    302   using Base::operator=;
    303 };
    304 
    305 template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
    306 class BlockImpl<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true,Sparse>
    307   : public internal::sparse_matrix_block_impl<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols>
    308 {
    309 public:
    310   typedef _StorageIndex StorageIndex;
    311   typedef const SparseMatrix<_Scalar, _Options, _StorageIndex> SparseMatrixType;
    312   typedef internal::sparse_matrix_block_impl<SparseMatrixType,BlockRows,BlockCols> Base;
    313   inline BlockImpl(SparseMatrixType& xpr, Index i)
    314     : Base(xpr, i)
    315   {}
    316 
    317   inline BlockImpl(SparseMatrixType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols)
    318     : Base(xpr, startRow, startCol, blockRows, blockCols)
    319   {}
    320 
    321   using Base::operator=;
    322 private:
    323   template<typename Derived> BlockImpl(const SparseMatrixBase<Derived>& xpr, Index i);
    324   template<typename Derived> BlockImpl(const SparseMatrixBase<Derived>& xpr);
    325 };
    326 
    327 //----------
    328 
    329 /** Generic implementation of sparse Block expression.
    330   * Real-only.
    331   */
    332 template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
    333 class BlockImpl<XprType,BlockRows,BlockCols,InnerPanel,Sparse>
    334   : public SparseMatrixBase<Block<XprType,BlockRows,BlockCols,InnerPanel> >, internal::no_assignment_operator
    335 {
    336     typedef Block<XprType, BlockRows, BlockCols, InnerPanel> BlockType;
    337     typedef SparseMatrixBase<BlockType> Base;
    338     using Base::convert_index;
    339 public:
    340     enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
    341     EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
    342 
    343     typedef typename internal::remove_all<typename XprType::Nested>::type _MatrixTypeNested;
    344 
    345     /** Column or Row constructor
    346       */
    347     inline BlockImpl(XprType& xpr, Index i)
    348       : m_matrix(xpr),
    349         m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? convert_index(i) : 0),
    350         m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? convert_index(i) : 0),
    351         m_blockRows(BlockRows==1 ? 1 : xpr.rows()),
    352         m_blockCols(BlockCols==1 ? 1 : xpr.cols())
    353     {}
    354 
    355     /** Dynamic-size constructor
    356       */
    357     inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols)
    358       : m_matrix(xpr), m_startRow(convert_index(startRow)), m_startCol(convert_index(startCol)), m_blockRows(convert_index(blockRows)), m_blockCols(convert_index(blockCols))
    359     {}
    360 
    361     inline Index rows() const { return m_blockRows.value(); }
    362     inline Index cols() const { return m_blockCols.value(); }
    363 
    364     inline Scalar& coeffRef(Index row, Index col)
    365     {
    366       return m_matrix.coeffRef(row + m_startRow.value(), col + m_startCol.value());
    367     }
    368 
    369     inline const Scalar coeff(Index row, Index col) const
    370     {
    371       return m_matrix.coeff(row + m_startRow.value(), col + m_startCol.value());
    372     }
    373 
    374     inline Scalar& coeffRef(Index index)
    375     {
    376       return m_matrix.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
    377                                m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
    378     }
    379 
    380     inline const Scalar coeff(Index index) const
    381     {
    382       return m_matrix.coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
    383                             m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
    384     }
    385 
    386     inline const XprType& nestedExpression() const { return m_matrix; }
    387     inline XprType& nestedExpression() { return m_matrix; }
    388     Index startRow() const { return m_startRow.value(); }
    389     Index startCol() const { return m_startCol.value(); }
    390     Index blockRows() const { return m_blockRows.value(); }
    391     Index blockCols() const { return m_blockCols.value(); }
    392 
    393   protected:
    394 //     friend class internal::GenericSparseBlockInnerIteratorImpl<XprType,BlockRows,BlockCols,InnerPanel>;
    395     friend struct internal::unary_evaluator<Block<XprType,BlockRows,BlockCols,InnerPanel>, internal::IteratorBased, Scalar >;
    396 
    397     Index nonZeros() const { return Dynamic; }
    398 
    399     typename internal::ref_selector<XprType>::non_const_type m_matrix;
    400     const internal::variable_if_dynamic<Index, XprType::RowsAtCompileTime == 1 ? 0 : Dynamic> m_startRow;
    401     const internal::variable_if_dynamic<Index, XprType::ColsAtCompileTime == 1 ? 0 : Dynamic> m_startCol;
    402     const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_blockRows;
    403     const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_blockCols;
    404 
    405   protected:
    406     // Disable assignment with clear error message.
    407     // Note that simply removing operator= yields compilation errors with ICC+MSVC
    408     template<typename T>
    409     BlockImpl& operator=(const T&)
    410     {
    411       EIGEN_STATIC_ASSERT(sizeof(T)==0, THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY);
    412       return *this;
    413     }
    414 
    415 };
    416 
    417 namespace internal {
    418 
    419 template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
    420 struct unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBased >
    421  : public evaluator_base<Block<ArgType,BlockRows,BlockCols,InnerPanel> >
    422 {
    423     class InnerVectorInnerIterator;
    424     class OuterVectorInnerIterator;
    425   public:
    426     typedef Block<ArgType,BlockRows,BlockCols,InnerPanel> XprType;
    427     typedef typename XprType::StorageIndex StorageIndex;
    428     typedef typename XprType::Scalar Scalar;
    429 
    430     enum {
    431       IsRowMajor = XprType::IsRowMajor,
    432 
    433       OuterVector =  (BlockCols==1 && ArgType::IsRowMajor)
    434                     | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&".
    435                       // revert to || as soon as not needed anymore.
    436                      (BlockRows==1 && !ArgType::IsRowMajor),
    437 
    438       CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
    439       Flags = XprType::Flags
    440     };
    441 
    442     typedef typename internal::conditional<OuterVector,OuterVectorInnerIterator,InnerVectorInnerIterator>::type InnerIterator;
    443 
    444     explicit unary_evaluator(const XprType& op)
    445       : m_argImpl(op.nestedExpression()), m_block(op)
    446     {}
    447 
    448     inline Index nonZerosEstimate() const {
    449       const Index nnz = m_block.nonZeros();
    450       if(nnz < 0) {
    451         // Scale the non-zero estimate for the underlying expression linearly with block size.
    452         // Return zero if the underlying block is empty.
    453         const Index nested_sz = m_block.nestedExpression().size();        
    454         return nested_sz == 0 ? 0 : m_argImpl.nonZerosEstimate() * m_block.size() / nested_sz;
    455       }
    456       return nnz;
    457     }
    458 
    459   protected:
    460     typedef typename evaluator<ArgType>::InnerIterator EvalIterator;
    461 
    462     evaluator<ArgType> m_argImpl;
    463     const XprType &m_block;
    464 };
    465 
    466 template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
    467 class unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBased>::InnerVectorInnerIterator
    468  : public EvalIterator
    469 {
    470   // NOTE MSVC fails to compile if we don't explicitely "import" IsRowMajor from unary_evaluator
    471   //      because the base class EvalIterator has a private IsRowMajor enum too. (bug #1786)
    472   // NOTE We cannot call it IsRowMajor because it would shadow unary_evaluator::IsRowMajor
    473   enum { XprIsRowMajor = unary_evaluator::IsRowMajor };
    474   const XprType& m_block;
    475   Index m_end;
    476 public:
    477 
    478   EIGEN_STRONG_INLINE InnerVectorInnerIterator(const unary_evaluator& aEval, Index outer)
    479     : EvalIterator(aEval.m_argImpl, outer + (XprIsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol())),
    480       m_block(aEval.m_block),
    481       m_end(XprIsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows())
    482   {
    483     while( (EvalIterator::operator bool()) && (EvalIterator::index() < (XprIsRowMajor ? m_block.startCol() : m_block.startRow())) )
    484       EvalIterator::operator++();
    485   }
    486 
    487   inline StorageIndex index() const { return EvalIterator::index() - convert_index<StorageIndex>(XprIsRowMajor ? m_block.startCol() : m_block.startRow()); }
    488   inline Index outer()  const { return EvalIterator::outer() - (XprIsRowMajor ? m_block.startRow() : m_block.startCol()); }
    489   inline Index row()    const { return EvalIterator::row()   - m_block.startRow(); }
    490   inline Index col()    const { return EvalIterator::col()   - m_block.startCol(); }
    491 
    492   inline operator bool() const { return EvalIterator::operator bool() && EvalIterator::index() < m_end; }
    493 };
    494 
    495 template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
    496 class unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBased>::OuterVectorInnerIterator
    497 {
    498   // NOTE see above
    499   enum { XprIsRowMajor = unary_evaluator::IsRowMajor };
    500   const unary_evaluator& m_eval;
    501   Index m_outerPos;
    502   const Index m_innerIndex;
    503   Index m_end;
    504   EvalIterator m_it;
    505 public:
    506 
    507   EIGEN_STRONG_INLINE OuterVectorInnerIterator(const unary_evaluator& aEval, Index outer)
    508     : m_eval(aEval),
    509       m_outerPos( (XprIsRowMajor ? aEval.m_block.startCol() : aEval.m_block.startRow()) ),
    510       m_innerIndex(XprIsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol()),
    511       m_end(XprIsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()),
    512       m_it(m_eval.m_argImpl, m_outerPos)
    513   {
    514     EIGEN_UNUSED_VARIABLE(outer);
    515     eigen_assert(outer==0);
    516 
    517     while(m_it && m_it.index() < m_innerIndex) ++m_it;
    518     if((!m_it) || (m_it.index()!=m_innerIndex))
    519       ++(*this);
    520   }
    521 
    522   inline StorageIndex index() const { return convert_index<StorageIndex>(m_outerPos - (XprIsRowMajor ? m_eval.m_block.startCol() : m_eval.m_block.startRow())); }
    523   inline Index outer()  const { return 0; }
    524   inline Index row()    const { return XprIsRowMajor ? 0 : index(); }
    525   inline Index col()    const { return XprIsRowMajor ? index() : 0; }
    526 
    527   inline Scalar value() const { return m_it.value(); }
    528   inline Scalar& valueRef() { return m_it.valueRef(); }
    529 
    530   inline OuterVectorInnerIterator& operator++()
    531   {
    532     // search next non-zero entry
    533     while(++m_outerPos<m_end)
    534     {
    535       // Restart iterator at the next inner-vector:
    536       m_it.~EvalIterator();
    537       ::new (&m_it) EvalIterator(m_eval.m_argImpl, m_outerPos);
    538       // search for the key m_innerIndex in the current outer-vector
    539       while(m_it && m_it.index() < m_innerIndex) ++m_it;
    540       if(m_it && m_it.index()==m_innerIndex) break;
    541     }
    542     return *this;
    543   }
    544 
    545   inline operator bool() const { return m_outerPos < m_end; }
    546 };
    547 
    548 template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
    549 struct unary_evaluator<Block<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true>, IteratorBased>
    550   : evaluator<SparseCompressedBase<Block<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> > >
    551 {
    552   typedef Block<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> XprType;
    553   typedef evaluator<SparseCompressedBase<XprType> > Base;
    554   explicit unary_evaluator(const XprType &xpr) : Base(xpr) {}
    555 };
    556 
    557 template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
    558 struct unary_evaluator<Block<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true>, IteratorBased>
    559   : evaluator<SparseCompressedBase<Block<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> > >
    560 {
    561   typedef Block<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> XprType;
    562   typedef evaluator<SparseCompressedBase<XprType> > Base;
    563   explicit unary_evaluator(const XprType &xpr) : Base(xpr) {}
    564 };
    565 
    566 } // end namespace internal
    567 
    568 
    569 } // end namespace Eigen
    570 
    571 #endif // EIGEN_SPARSE_BLOCK_H