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