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
13namespace Eigen {
14
15// Subset of columns or rows
16template<typename XprType, int BlockRows, int BlockCols>
17class 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;
22public:
23    enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
24protected:
25    enum { OuterSize = IsRowMajor ? BlockRows : BlockCols };
26    typedef SparseMatrixBase<BlockType> Base;
27    using Base::convert_index;
28public:
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
93namespace internal {
94
95template<typename SparseMatrixType, int BlockRows, int BlockCols>
96class 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;
103public:
104    enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
105    EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
106protected:
107    typedef typename Base::IndexVector IndexVector;
108    enum { OuterSize = IsRowMajor ? BlockRows : BlockCols };
109public:
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
286template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
287class BlockImpl<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols,true,Sparse>
288  : public internal::sparse_matrix_block_impl<SparseMatrix<_Scalar, _Options, _StorageIndex>,BlockRows,BlockCols>
289{
290public:
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
305template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
306class 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{
309public:
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=;
322private:
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  */
332template<typename Derived>
333typename 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  */
339template<typename Derived>
340const 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  */
346template<typename Derived>
347typename SparseMatrixBase<Derived>::InnerVectorsReturnType
348SparseMatrixBase<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  */
359template<typename Derived>
360const typename SparseMatrixBase<Derived>::ConstInnerVectorsReturnType
361SparseMatrixBase<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  */
372template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
373class 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;
379public:
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
457namespace internal {
458
459template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
460struct 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
502template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
503class 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;
509public:
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
528template<typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
529class 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;
537public:
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
580template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
581struct 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
589template<typename _Scalar, int _Options, typename _StorageIndex, int BlockRows, int BlockCols>
590struct 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