Home | History | Annotate | Download | only in SparseCore
      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 (at) 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())
    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 /** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
    330   * is col-major (resp. row-major).
    331   */
    332 template<typename Derived>
    333 typename SparseMatrixBase<Derived>::InnerVectorReturnType SparseMatrixBase<Derived>::innerVector(Index outer)
    334 { return InnerVectorReturnType(derived(), outer); }
    335 
    336 /** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
    337   * is col-major (resp. row-major). Read-only.
    338   */
    339 template<typename Derived>
    340 const typename SparseMatrixBase<Derived>::ConstInnerVectorReturnType SparseMatrixBase<Derived>::innerVector(Index outer) const
    341 { return ConstInnerVectorReturnType(derived(), outer); }
    342 
    343 /** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
    344   * is col-major (resp. row-major).
    345   */
    346 template<typename Derived>
    347 typename SparseMatrixBase<Derived>::InnerVectorsReturnType
    348 SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize)
    349 {
    350   return Block<Derived,Dynamic,Dynamic,true>(derived(),
    351                                              IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart,
    352                                              IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize);
    353 
    354 }
    355 
    356 /** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
    357   * is col-major (resp. row-major). Read-only.
    358   */
    359 template<typename Derived>
    360 const typename SparseMatrixBase<Derived>::ConstInnerVectorsReturnType
    361 SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) const
    362 {
    363   return Block<const Derived,Dynamic,Dynamic,true>(derived(),
    364                                                   IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart,
    365                                                   IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize);
    366 
    367 }
    368 
    369 /** Generic implementation of sparse Block expression.
    370   * Real-only.
    371   */
    372 template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
    373 class BlockImpl<XprType,BlockRows,BlockCols,InnerPanel,Sparse>
    374   : public SparseMatrixBase<Block<XprType,BlockRows,BlockCols,InnerPanel> >, internal::no_assignment_operator
    375 {
    376     typedef Block<XprType, BlockRows, BlockCols, InnerPanel> BlockType;
    377     typedef SparseMatrixBase<BlockType> Base;
    378     using Base::convert_index;
    379 public:
    380     enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
    381     EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
    382 
    383     typedef typename internal::remove_all<typename XprType::Nested>::type _MatrixTypeNested;
    384 
    385     /** Column or Row constructor
    386       */
    387     inline BlockImpl(XprType& xpr, Index i)
    388       : m_matrix(xpr),
    389         m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? convert_index(i) : 0),
    390         m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? convert_index(i) : 0),
    391         m_blockRows(BlockRows==1 ? 1 : xpr.rows()),
    392         m_blockCols(BlockCols==1 ? 1 : xpr.cols())
    393     {}
    394 
    395     /** Dynamic-size constructor
    396       */
    397     inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols)
    398       : m_matrix(xpr), m_startRow(convert_index(startRow)), m_startCol(convert_index(startCol)), m_blockRows(convert_index(blockRows)), m_blockCols(convert_index(blockCols))
    399     {}
    400 
    401     inline Index rows() const { return m_blockRows.value(); }
    402     inline Index cols() const { return m_blockCols.value(); }
    403 
    404     inline Scalar& coeffRef(Index row, Index col)
    405     {
    406       return m_matrix.coeffRef(row + m_startRow.value(), col + m_startCol.value());
    407     }
    408 
    409     inline const Scalar coeff(Index row, Index col) const
    410     {
    411       return m_matrix.coeff(row + m_startRow.value(), col + m_startCol.value());
    412     }
    413 
    414     inline Scalar& coeffRef(Index index)
    415     {
    416       return m_matrix.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
    417                                m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
    418     }
    419 
    420     inline const Scalar coeff(Index index) const
    421     {
    422       return m_matrix.coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
    423                             m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
    424     }
    425 
    426     inline const XprType& nestedExpression() const { return m_matrix; }
    427     inline XprType& nestedExpression() { return m_matrix; }
    428     Index startRow() const { return m_startRow.value(); }
    429     Index startCol() const { return m_startCol.value(); }
    430     Index blockRows() const { return m_blockRows.value(); }
    431     Index blockCols() const { return m_blockCols.value(); }
    432 
    433   protected:
    434 //     friend class internal::GenericSparseBlockInnerIteratorImpl<XprType,BlockRows,BlockCols,InnerPanel>;
    435     friend struct internal::unary_evaluator<Block<XprType,BlockRows,BlockCols,InnerPanel>, internal::IteratorBased, Scalar >;
    436 
    437     Index nonZeros() const { return Dynamic; }
    438 
    439     typename internal::ref_selector<XprType>::non_const_type m_matrix;
    440     const internal::variable_if_dynamic<Index, XprType::RowsAtCompileTime == 1 ? 0 : Dynamic> m_startRow;
    441     const internal::variable_if_dynamic<Index, XprType::ColsAtCompileTime == 1 ? 0 : Dynamic> m_startCol;
    442     const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_blockRows;
    443     const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_blockCols;
    444 
    445   protected:
    446     // Disable assignment with clear error message.
    447     // Note that simply removing operator= yields compilation errors with ICC+MSVC
    448     template<typename T>
    449     BlockImpl& operator=(const T&)
    450     {
    451       EIGEN_STATIC_ASSERT(sizeof(T)==0, THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY);
    452       return *this;
    453     }
    454 
    455 };
    456 
    457 namespace internal {
    458 
    459 template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
    460 struct unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBased >
    461  : public evaluator_base<Block<ArgType,BlockRows,BlockCols,InnerPanel> >
    462 {
    463     class InnerVectorInnerIterator;
    464     class OuterVectorInnerIterator;
    465   public:
    466     typedef Block<ArgType,BlockRows,BlockCols,InnerPanel> XprType;
    467     typedef typename XprType::StorageIndex StorageIndex;
    468     typedef typename XprType::Scalar Scalar;
    469 
    470     enum {
    471       IsRowMajor = XprType::IsRowMajor,
    472 
    473       OuterVector =  (BlockCols==1 && ArgType::IsRowMajor)
    474                     | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&".
    475                       // revert to || as soon as not needed anymore.
    476                      (BlockRows==1 && !ArgType::IsRowMajor),
    477 
    478       CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
    479       Flags = XprType::Flags
    480     };
    481 
    482     typedef typename internal::conditional<OuterVector,OuterVectorInnerIterator,InnerVectorInnerIterator>::type InnerIterator;
    483 
    484     explicit unary_evaluator(const XprType& op)
    485       : m_argImpl(op.nestedExpression()), m_block(op)
    486     {}
    487 
    488     inline Index nonZerosEstimate() const {
    489       Index nnz = m_block.nonZeros();
    490       if(nnz<0)
    491         return m_argImpl.nonZerosEstimate() * m_block.size() / m_block.nestedExpression().size();
    492       return nnz;
    493     }
    494 
    495   protected:
    496     typedef typename evaluator<ArgType>::InnerIterator EvalIterator;
    497 
    498     evaluator<ArgType> m_argImpl;
    499     const XprType &m_block;
    500 };
    501 
    502 template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
    503 class unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBased>::InnerVectorInnerIterator
    504  : public EvalIterator
    505 {
    506   enum { IsRowMajor = unary_evaluator::IsRowMajor };
    507   const XprType& m_block;
    508   Index m_end;
    509 public:
    510 
    511   EIGEN_STRONG_INLINE InnerVectorInnerIterator(const unary_evaluator& aEval, Index outer)
    512     : EvalIterator(aEval.m_argImpl, outer + (IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol())),
    513       m_block(aEval.m_block),
    514       m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows())
    515   {
    516     while( (EvalIterator::operator bool()) && (EvalIterator::index() < (IsRowMajor ? m_block.startCol() : m_block.startRow())) )
    517       EvalIterator::operator++();
    518   }
    519 
    520   inline StorageIndex index() const { return EvalIterator::index() - convert_index<StorageIndex>(IsRowMajor ? m_block.startCol() : m_block.startRow()); }
    521   inline Index outer()  const { return EvalIterator::outer() - (IsRowMajor ? m_block.startRow() : m_block.startCol()); }
    522   inline Index row()    const { return EvalIterator::row()   - m_block.startRow(); }
    523   inline Index col()    const { return EvalIterator::col()   - m_block.startCol(); }
    524 
    525   inline operator bool() const { return EvalIterator::operator bool() && EvalIterator::index() < m_end; }
    526 };
    527 
    528 template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
    529 class unary_evaluator<Block<ArgType,BlockRows,BlockCols,InnerPanel>, IteratorBased>::OuterVectorInnerIterator
    530 {
    531   enum { IsRowMajor = unary_evaluator::IsRowMajor };
    532   const unary_evaluator& m_eval;
    533   Index m_outerPos;
    534   const Index m_innerIndex;
    535   Index m_end;
    536   EvalIterator m_it;
    537 public:
    538 
    539   EIGEN_STRONG_INLINE OuterVectorInnerIterator(const unary_evaluator& aEval, Index outer)
    540     : m_eval(aEval),
    541       m_outerPos( (IsRowMajor ? aEval.m_block.startCol() : aEval.m_block.startRow()) ),
    542       m_innerIndex(IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol()),
    543       m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()),
    544       m_it(m_eval.m_argImpl, m_outerPos)
    545   {
    546     EIGEN_UNUSED_VARIABLE(outer);
    547     eigen_assert(outer==0);
    548 
    549     while(m_it && m_it.index() < m_innerIndex) ++m_it;
    550     if((!m_it) || (m_it.index()!=m_innerIndex))
    551       ++(*this);
    552   }
    553 
    554   inline StorageIndex index() const { return convert_index<StorageIndex>(m_outerPos - (IsRowMajor ? m_eval.m_block.startCol() : m_eval.m_block.startRow())); }
    555   inline Index outer()  const { return 0; }
    556   inline Index row()    const { return IsRowMajor ? 0 : index(); }
    557   inline Index col()    const { return IsRowMajor ? index() : 0; }
    558 
    559   inline Scalar value() const { return m_it.value(); }
    560   inline Scalar& valueRef() { return m_it.valueRef(); }
    561 
    562   inline OuterVectorInnerIterator& operator++()
    563   {
    564     // search next non-zero entry
    565     while(++m_outerPos<m_end)
    566     {
    567       // Restart iterator at the next inner-vector:
    568       m_it.~EvalIterator();
    569       ::new (&m_it) EvalIterator(m_eval.m_argImpl, m_outerPos);
    570       // search for the key m_innerIndex in the current outer-vector
    571       while(m_it && m_it.index() < m_innerIndex) ++m_it;
    572       if(m_it && m_it.index()==m_innerIndex) break;
    573     }
    574     return *this;
    575   }
    576 
    577   inline operator bool() const { return m_outerPos < m_end; }
    578 };
    579 
    580 template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
    581 struct unary_evaluator<Block<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true>, IteratorBased>
    582   : evaluator<SparseCompressedBase<Block<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> > >
    583 {
    584   typedef Block<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> XprType;
    585   typedef evaluator<SparseCompressedBase<XprType> > Base;
    586   explicit unary_evaluator(const XprType &xpr) : Base(xpr) {}
    587 };
    588 
    589 template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
    590 struct unary_evaluator<Block<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true>, IteratorBased>
    591   : evaluator<SparseCompressedBase<Block<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> > >
    592 {
    593   typedef Block<const SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true> XprType;
    594   typedef evaluator<SparseCompressedBase<XprType> > Base;
    595   explicit unary_evaluator(const XprType &xpr) : Base(xpr) {}
    596 };
    597 
    598 } // end namespace internal
    599 
    600 
    601 } // end namespace Eigen
    602 
    603 #endif // EIGEN_SPARSE_BLOCK_H
    604