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 |
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 | |
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 | |