1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008 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_VISITOR_H
11#define EIGEN_VISITOR_H
12
13namespace Eigen {
14
15namespace internal {
16
17template<typename Visitor, typename Derived, int UnrollCount>
18struct visitor_impl
19{
20  enum {
21    col = (UnrollCount-1) / Derived::RowsAtCompileTime,
22    row = (UnrollCount-1) % Derived::RowsAtCompileTime
23  };
24
25  static inline void run(const Derived &mat, Visitor& visitor)
26  {
27    visitor_impl<Visitor, Derived, UnrollCount-1>::run(mat, visitor);
28    visitor(mat.coeff(row, col), row, col);
29  }
30};
31
32template<typename Visitor, typename Derived>
33struct visitor_impl<Visitor, Derived, 1>
34{
35  static inline void run(const Derived &mat, Visitor& visitor)
36  {
37    return visitor.init(mat.coeff(0, 0), 0, 0);
38  }
39};
40
41template<typename Visitor, typename Derived>
42struct visitor_impl<Visitor, Derived, Dynamic>
43{
44  typedef typename Derived::Index Index;
45  static inline void run(const Derived& mat, Visitor& visitor)
46  {
47    visitor.init(mat.coeff(0,0), 0, 0);
48    for(Index i = 1; i < mat.rows(); ++i)
49      visitor(mat.coeff(i, 0), i, 0);
50    for(Index j = 1; j < mat.cols(); ++j)
51      for(Index i = 0; i < mat.rows(); ++i)
52        visitor(mat.coeff(i, j), i, j);
53  }
54};
55
56} // end namespace internal
57
58/** Applies the visitor \a visitor to the whole coefficients of the matrix or vector.
59  *
60  * The template parameter \a Visitor is the type of the visitor and provides the following interface:
61  * \code
62  * struct MyVisitor {
63  *   // called for the first coefficient
64  *   void init(const Scalar& value, Index i, Index j);
65  *   // called for all other coefficients
66  *   void operator() (const Scalar& value, Index i, Index j);
67  * };
68  * \endcode
69  *
70  * \note compared to one or two \em for \em loops, visitors offer automatic
71  * unrolling for small fixed size matrix.
72  *
73  * \sa minCoeff(Index*,Index*), maxCoeff(Index*,Index*), DenseBase::redux()
74  */
75template<typename Derived>
76template<typename Visitor>
77void DenseBase<Derived>::visit(Visitor& visitor) const
78{
79  enum { unroll = SizeAtCompileTime != Dynamic
80                   && CoeffReadCost != Dynamic
81                   && (SizeAtCompileTime == 1 || internal::functor_traits<Visitor>::Cost != Dynamic)
82                   && SizeAtCompileTime * CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits<Visitor>::Cost
83                      <= EIGEN_UNROLLING_LIMIT };
84  return internal::visitor_impl<Visitor, Derived,
85      unroll ? int(SizeAtCompileTime) : Dynamic
86    >::run(derived(), visitor);
87}
88
89namespace internal {
90
91/** \internal
92  * \brief Base class to implement min and max visitors
93  */
94template <typename Derived>
95struct coeff_visitor
96{
97  typedef typename Derived::Index Index;
98  typedef typename Derived::Scalar Scalar;
99  Index row, col;
100  Scalar res;
101  inline void init(const Scalar& value, Index i, Index j)
102  {
103    res = value;
104    row = i;
105    col = j;
106  }
107};
108
109/** \internal
110  * \brief Visitor computing the min coefficient with its value and coordinates
111  *
112  * \sa DenseBase::minCoeff(Index*, Index*)
113  */
114template <typename Derived>
115struct min_coeff_visitor : coeff_visitor<Derived>
116{
117  typedef typename Derived::Index Index;
118  typedef typename Derived::Scalar Scalar;
119  void operator() (const Scalar& value, Index i, Index j)
120  {
121    if(value < this->res)
122    {
123      this->res = value;
124      this->row = i;
125      this->col = j;
126    }
127  }
128};
129
130template<typename Scalar>
131struct functor_traits<min_coeff_visitor<Scalar> > {
132  enum {
133    Cost = NumTraits<Scalar>::AddCost
134  };
135};
136
137/** \internal
138  * \brief Visitor computing the max coefficient with its value and coordinates
139  *
140  * \sa DenseBase::maxCoeff(Index*, Index*)
141  */
142template <typename Derived>
143struct max_coeff_visitor : coeff_visitor<Derived>
144{
145  typedef typename Derived::Index Index;
146  typedef typename Derived::Scalar Scalar;
147  void operator() (const Scalar& value, Index i, Index j)
148  {
149    if(value > this->res)
150    {
151      this->res = value;
152      this->row = i;
153      this->col = j;
154    }
155  }
156};
157
158template<typename Scalar>
159struct functor_traits<max_coeff_visitor<Scalar> > {
160  enum {
161    Cost = NumTraits<Scalar>::AddCost
162  };
163};
164
165} // end namespace internal
166
167/** \returns the minimum of all coefficients of *this and puts in *row and *col its location.
168  * \warning the result is undefined if \c *this contains NaN.
169  *
170  * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visitor(), DenseBase::minCoeff()
171  */
172template<typename Derived>
173template<typename IndexType>
174typename internal::traits<Derived>::Scalar
175DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const
176{
177  internal::min_coeff_visitor<Derived> minVisitor;
178  this->visit(minVisitor);
179  *rowId = minVisitor.row;
180  if (colId) *colId = minVisitor.col;
181  return minVisitor.res;
182}
183
184/** \returns the minimum of all coefficients of *this and puts in *index its location.
185  * \warning the result is undefined if \c *this contains NaN.
186  *
187  * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::minCoeff()
188  */
189template<typename Derived>
190template<typename IndexType>
191typename internal::traits<Derived>::Scalar
192DenseBase<Derived>::minCoeff(IndexType* index) const
193{
194  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
195  internal::min_coeff_visitor<Derived> minVisitor;
196  this->visit(minVisitor);
197  *index = (RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row;
198  return minVisitor.res;
199}
200
201/** \returns the maximum of all coefficients of *this and puts in *row and *col its location.
202  * \warning the result is undefined if \c *this contains NaN.
203  *
204  * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff()
205  */
206template<typename Derived>
207template<typename IndexType>
208typename internal::traits<Derived>::Scalar
209DenseBase<Derived>::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const
210{
211  internal::max_coeff_visitor<Derived> maxVisitor;
212  this->visit(maxVisitor);
213  *rowPtr = maxVisitor.row;
214  if (colPtr) *colPtr = maxVisitor.col;
215  return maxVisitor.res;
216}
217
218/** \returns the maximum of all coefficients of *this and puts in *index its location.
219  * \warning the result is undefined if \c *this contains NaN.
220  *
221  * \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff()
222  */
223template<typename Derived>
224template<typename IndexType>
225typename internal::traits<Derived>::Scalar
226DenseBase<Derived>::maxCoeff(IndexType* index) const
227{
228  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
229  internal::max_coeff_visitor<Derived> maxVisitor;
230  this->visit(maxVisitor);
231  *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row;
232  return maxVisitor.res;
233}
234
235} // end namespace Eigen
236
237#endif // EIGEN_VISITOR_H
238