Visitor.h 7.88 KB
Newer Older
LM's avatar
LM committed
1 2 3 4 5
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
Don Gagne's avatar
Don Gagne committed
6 7 8
// 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/.
LM's avatar
LM committed
9 10 11 12

#ifndef EIGEN_VISITOR_H
#define EIGEN_VISITOR_H

Don Gagne's avatar
Don Gagne committed
13 14
namespace Eigen { 

LM's avatar
LM committed
15 16 17 18 19 20 21 22 23 24
namespace internal {

template<typename Visitor, typename Derived, int UnrollCount>
struct visitor_impl
{
  enum {
    col = (UnrollCount-1) / Derived::RowsAtCompileTime,
    row = (UnrollCount-1) % Derived::RowsAtCompileTime
  };

25
  EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
26
  static inline void run(const Derived &mat, Visitor& visitor)
LM's avatar
LM committed
27 28 29 30 31 32 33 34 35
  {
    visitor_impl<Visitor, Derived, UnrollCount-1>::run(mat, visitor);
    visitor(mat.coeff(row, col), row, col);
  }
};

template<typename Visitor, typename Derived>
struct visitor_impl<Visitor, Derived, 1>
{
36
  EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
37
  static inline void run(const Derived &mat, Visitor& visitor)
LM's avatar
LM committed
38 39 40 41 42 43 44 45
  {
    return visitor.init(mat.coeff(0, 0), 0, 0);
  }
};

template<typename Visitor, typename Derived>
struct visitor_impl<Visitor, Derived, Dynamic>
{
46
  EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
47
  static inline void run(const Derived& mat, Visitor& visitor)
LM's avatar
LM committed
48 49 50 51 52 53 54 55 56 57
  {
    visitor.init(mat.coeff(0,0), 0, 0);
    for(Index i = 1; i < mat.rows(); ++i)
      visitor(mat.coeff(i, 0), i, 0);
    for(Index j = 1; j < mat.cols(); ++j)
      for(Index i = 0; i < mat.rows(); ++i)
        visitor(mat.coeff(i, j), i, j);
  }
};

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
// evaluator adaptor
template<typename XprType>
class visitor_evaluator
{
public:
  EIGEN_DEVICE_FUNC
  explicit visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {}
  
  typedef typename XprType::Scalar Scalar;
  typedef typename XprType::CoeffReturnType CoeffReturnType;
  
  enum {
    RowsAtCompileTime = XprType::RowsAtCompileTime,
    CoeffReadCost = internal::evaluator<XprType>::CoeffReadCost
  };
  
  EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); }
  EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); }
  EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); }

  EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const
  { return m_evaluator.coeff(row, col); }
  
protected:
  internal::evaluator<XprType> m_evaluator;
  const XprType &m_xpr;
};
LM's avatar
LM committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
} // end namespace internal

/** Applies the visitor \a visitor to the whole coefficients of the matrix or vector.
  *
  * The template parameter \a Visitor is the type of the visitor and provides the following interface:
  * \code
  * struct MyVisitor {
  *   // called for the first coefficient
  *   void init(const Scalar& value, Index i, Index j);
  *   // called for all other coefficients
  *   void operator() (const Scalar& value, Index i, Index j);
  * };
  * \endcode
  *
  * \note compared to one or two \em for \em loops, visitors offer automatic
  * unrolling for small fixed size matrix.
  *
  * \sa minCoeff(Index*,Index*), maxCoeff(Index*,Index*), DenseBase::redux()
  */
template<typename Derived>
template<typename Visitor>
106
EIGEN_DEVICE_FUNC
LM's avatar
LM committed
107 108
void DenseBase<Derived>::visit(Visitor& visitor) const
{
109 110 111 112 113 114 115 116
  typedef typename internal::visitor_evaluator<Derived> ThisEvaluator;
  ThisEvaluator thisEval(derived());
  
  enum {
    unroll =  SizeAtCompileTime != Dynamic
           && SizeAtCompileTime * ThisEvaluator::CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits<Visitor>::Cost <= EIGEN_UNROLLING_LIMIT
  };
  return internal::visitor_impl<Visitor, ThisEvaluator, unroll ? int(SizeAtCompileTime) : Dynamic>::run(thisEval, visitor);
LM's avatar
LM committed
117 118 119 120 121 122 123 124 125 126 127 128 129
}

namespace internal {

/** \internal
  * \brief Base class to implement min and max visitors
  */
template <typename Derived>
struct coeff_visitor
{
  typedef typename Derived::Scalar Scalar;
  Index row, col;
  Scalar res;
130
  EIGEN_DEVICE_FUNC
LM's avatar
LM committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  inline void init(const Scalar& value, Index i, Index j)
  {
    res = value;
    row = i;
    col = j;
  }
};

/** \internal
  * \brief Visitor computing the min coefficient with its value and coordinates
  *
  * \sa DenseBase::minCoeff(Index*, Index*)
  */
template <typename Derived>
struct min_coeff_visitor : coeff_visitor<Derived>
{
  typedef typename Derived::Scalar Scalar;
148
  EIGEN_DEVICE_FUNC
LM's avatar
LM committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
  void operator() (const Scalar& value, Index i, Index j)
  {
    if(value < this->res)
    {
      this->res = value;
      this->row = i;
      this->col = j;
    }
  }
};

template<typename Scalar>
struct functor_traits<min_coeff_visitor<Scalar> > {
  enum {
    Cost = NumTraits<Scalar>::AddCost
  };
};

/** \internal
  * \brief Visitor computing the max coefficient with its value and coordinates
  *
  * \sa DenseBase::maxCoeff(Index*, Index*)
  */
template <typename Derived>
struct max_coeff_visitor : coeff_visitor<Derived>
{
175 176
  typedef typename Derived::Scalar Scalar; 
  EIGEN_DEVICE_FUNC
LM's avatar
LM committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  void operator() (const Scalar& value, Index i, Index j)
  {
    if(value > this->res)
    {
      this->res = value;
      this->row = i;
      this->col = j;
    }
  }
};

template<typename Scalar>
struct functor_traits<max_coeff_visitor<Scalar> > {
  enum {
    Cost = NumTraits<Scalar>::AddCost
  };
};

} // end namespace internal

197 198
/** \fn DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const
  * \returns the minimum of all coefficients of *this and puts in *row and *col its location.
Don Gagne's avatar
Don Gagne committed
199
  * \warning the result is undefined if \c *this contains NaN.
LM's avatar
LM committed
200
  *
201
  * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visit(), DenseBase::minCoeff()
LM's avatar
LM committed
202 203 204
  */
template<typename Derived>
template<typename IndexType>
205
EIGEN_DEVICE_FUNC
LM's avatar
LM committed
206
typename internal::traits<Derived>::Scalar
Don Gagne's avatar
Don Gagne committed
207
DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const
LM's avatar
LM committed
208 209 210
{
  internal::min_coeff_visitor<Derived> minVisitor;
  this->visit(minVisitor);
Don Gagne's avatar
Don Gagne committed
211 212
  *rowId = minVisitor.row;
  if (colId) *colId = minVisitor.col;
LM's avatar
LM committed
213 214 215
  return minVisitor.res;
}

Don Gagne's avatar
Don Gagne committed
216 217
/** \returns the minimum of all coefficients of *this and puts in *index its location.
  * \warning the result is undefined if \c *this contains NaN. 
LM's avatar
LM committed
218
  *
219
  * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::minCoeff()
LM's avatar
LM committed
220 221 222
  */
template<typename Derived>
template<typename IndexType>
223
EIGEN_DEVICE_FUNC
LM's avatar
LM committed
224 225 226 227 228 229
typename internal::traits<Derived>::Scalar
DenseBase<Derived>::minCoeff(IndexType* index) const
{
  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
  internal::min_coeff_visitor<Derived> minVisitor;
  this->visit(minVisitor);
230
  *index = IndexType((RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row);
LM's avatar
LM committed
231 232 233
  return minVisitor.res;
}

234 235
/** \fn DenseBase<Derived>::maxCoeff(IndexType* rowId, IndexType* colId) const
  * \returns the maximum of all coefficients of *this and puts in *row and *col its location.
Don Gagne's avatar
Don Gagne committed
236
  * \warning the result is undefined if \c *this contains NaN. 
LM's avatar
LM committed
237
  *
238
  * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::maxCoeff()
LM's avatar
LM committed
239 240 241
  */
template<typename Derived>
template<typename IndexType>
242
EIGEN_DEVICE_FUNC
LM's avatar
LM committed
243
typename internal::traits<Derived>::Scalar
Don Gagne's avatar
Don Gagne committed
244
DenseBase<Derived>::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const
LM's avatar
LM committed
245 246 247
{
  internal::max_coeff_visitor<Derived> maxVisitor;
  this->visit(maxVisitor);
Don Gagne's avatar
Don Gagne committed
248 249
  *rowPtr = maxVisitor.row;
  if (colPtr) *colPtr = maxVisitor.col;
LM's avatar
LM committed
250 251 252
  return maxVisitor.res;
}

Don Gagne's avatar
Don Gagne committed
253 254
/** \returns the maximum of all coefficients of *this and puts in *index its location.
  * \warning the result is undefined if \c *this contains NaN.
LM's avatar
LM committed
255 256 257 258 259
  *
  * \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff()
  */
template<typename Derived>
template<typename IndexType>
260
EIGEN_DEVICE_FUNC
LM's avatar
LM committed
261 262 263 264 265 266 267 268 269 270
typename internal::traits<Derived>::Scalar
DenseBase<Derived>::maxCoeff(IndexType* index) const
{
  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
  internal::max_coeff_visitor<Derived> maxVisitor;
  this->visit(maxVisitor);
  *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row;
  return maxVisitor.res;
}

Don Gagne's avatar
Don Gagne committed
271 272
} // end namespace Eigen

LM's avatar
LM committed
273
#endif // EIGEN_VISITOR_H