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 EIGEN_DEVICE_FUNC
26 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
33template<typename Visitor, typename Derived>
34struct 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
43template<typename Visitor, typename Derived>
44struct 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
59template<typename XprType>
60class visitor_evaluator
61{
62public:
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
81protected:
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 */
104template<typename Derived>
105template<typename Visitor>
106EIGEN_DEVICE_FUNC
107void 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
119namespace internal {
120
121/** \internal
122 * \brief Base class to implement min and max visitors
123 */
124template <typename Derived>
125struct 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 */
144template <typename Derived>
145struct 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
160template<typename Scalar>
161struct 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 */
172template <typename Derived>
173struct 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
188template<typename Scalar>
189struct 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 */
203template<typename Derived>
204template<typename IndexType>
205EIGEN_DEVICE_FUNC
206typename internal::traits<Derived>::Scalar
207DenseBase<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 */
221template<typename Derived>
222template<typename IndexType>
223EIGEN_DEVICE_FUNC
224typename internal::traits<Derived>::Scalar
225DenseBase<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 */
240template<typename Derived>
241template<typename IndexType>
242EIGEN_DEVICE_FUNC
243typename internal::traits<Derived>::Scalar
244DenseBase<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 */
258template<typename Derived>
259template<typename IndexType>
260EIGEN_DEVICE_FUNC
261typename internal::traits<Derived>::Scalar
262DenseBase<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