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 | // This specialization enables visitors on empty matrices at compile-time |
44 | template<typename Visitor, typename Derived> |
45 | struct visitor_impl<Visitor, Derived, 0> { |
46 | EIGEN_DEVICE_FUNC |
47 | static inline void run(const Derived &/*mat*/, Visitor& /*visitor*/) |
48 | {} |
49 | }; |
50 | |
51 | template<typename Visitor, typename Derived> |
52 | struct visitor_impl<Visitor, Derived, Dynamic> |
53 | { |
54 | EIGEN_DEVICE_FUNC |
55 | static inline void run(const Derived& mat, Visitor& visitor) |
56 | { |
57 | visitor.init(mat.coeff(0,0), 0, 0); |
58 | for(Index i = 1; i < mat.rows(); ++i) |
59 | visitor(mat.coeff(i, 0), i, 0); |
60 | for(Index j = 1; j < mat.cols(); ++j) |
61 | for(Index i = 0; i < mat.rows(); ++i) |
62 | visitor(mat.coeff(i, j), i, j); |
63 | } |
64 | }; |
65 | |
66 | // evaluator adaptor |
67 | template<typename XprType> |
68 | class visitor_evaluator |
69 | { |
70 | public: |
71 | EIGEN_DEVICE_FUNC |
72 | explicit visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} |
73 | |
74 | typedef typename XprType::Scalar Scalar; |
75 | typedef typename XprType::CoeffReturnType CoeffReturnType; |
76 | |
77 | enum { |
78 | RowsAtCompileTime = XprType::RowsAtCompileTime, |
79 | CoeffReadCost = internal::evaluator<XprType>::CoeffReadCost |
80 | }; |
81 | |
82 | EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_xpr.rows(); } |
83 | EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_xpr.cols(); } |
84 | EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_xpr.size(); } |
85 | |
86 | EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const |
87 | { return m_evaluator.coeff(row, col); } |
88 | |
89 | protected: |
90 | internal::evaluator<XprType> m_evaluator; |
91 | const XprType &m_xpr; |
92 | }; |
93 | } // end namespace internal |
94 | |
95 | /** Applies the visitor \a visitor to the whole coefficients of the matrix or vector. |
96 | * |
97 | * The template parameter \a Visitor is the type of the visitor and provides the following interface: |
98 | * \code |
99 | * struct MyVisitor { |
100 | * // called for the first coefficient |
101 | * void init(const Scalar& value, Index i, Index j); |
102 | * // called for all other coefficients |
103 | * void operator() (const Scalar& value, Index i, Index j); |
104 | * }; |
105 | * \endcode |
106 | * |
107 | * \note compared to one or two \em for \em loops, visitors offer automatic |
108 | * unrolling for small fixed size matrix. |
109 | * |
110 | * \note if the matrix is empty, then the visitor is left unchanged. |
111 | * |
112 | * \sa minCoeff(Index*,Index*), maxCoeff(Index*,Index*), DenseBase::redux() |
113 | */ |
114 | template<typename Derived> |
115 | template<typename Visitor> |
116 | EIGEN_DEVICE_FUNC |
117 | void DenseBase<Derived>::visit(Visitor& visitor) const |
118 | { |
119 | if(size()==0) |
120 | return; |
121 | |
122 | typedef typename internal::visitor_evaluator<Derived> ThisEvaluator; |
123 | ThisEvaluator thisEval(derived()); |
124 | |
125 | enum { |
126 | unroll = SizeAtCompileTime != Dynamic |
127 | && SizeAtCompileTime * int(ThisEvaluator::CoeffReadCost) + (SizeAtCompileTime-1) * int(internal::functor_traits<Visitor>::Cost) <= EIGEN_UNROLLING_LIMIT |
128 | }; |
129 | return internal::visitor_impl<Visitor, ThisEvaluator, unroll ? int(SizeAtCompileTime) : Dynamic>::run(thisEval, visitor); |
130 | } |
131 | |
132 | namespace internal { |
133 | |
134 | /** \internal |
135 | * \brief Base class to implement min and max visitors |
136 | */ |
137 | template <typename Derived> |
138 | struct coeff_visitor |
139 | { |
140 | // default initialization to avoid countless invalid maybe-uninitialized warnings by gcc |
141 | EIGEN_DEVICE_FUNC |
142 | coeff_visitor() : row(-1), col(-1), res(0) {} |
143 | typedef typename Derived::Scalar Scalar; |
144 | Index row, col; |
145 | Scalar res; |
146 | EIGEN_DEVICE_FUNC |
147 | inline void init(const Scalar& value, Index i, Index j) |
148 | { |
149 | res = value; |
150 | row = i; |
151 | col = j; |
152 | } |
153 | }; |
154 | |
155 | /** \internal |
156 | * \brief Visitor computing the min coefficient with its value and coordinates |
157 | * |
158 | * \sa DenseBase::minCoeff(Index*, Index*) |
159 | */ |
160 | template <typename Derived, int NaNPropagation> |
161 | struct min_coeff_visitor : coeff_visitor<Derived> |
162 | { |
163 | typedef typename Derived::Scalar Scalar; |
164 | EIGEN_DEVICE_FUNC |
165 | void operator() (const Scalar& value, Index i, Index j) |
166 | { |
167 | if(value < this->res) |
168 | { |
169 | this->res = value; |
170 | this->row = i; |
171 | this->col = j; |
172 | } |
173 | } |
174 | }; |
175 | |
176 | template <typename Derived> |
177 | struct min_coeff_visitor<Derived, PropagateNumbers> : coeff_visitor<Derived> |
178 | { |
179 | typedef typename Derived::Scalar Scalar; |
180 | EIGEN_DEVICE_FUNC |
181 | void operator() (const Scalar& value, Index i, Index j) |
182 | { |
183 | if((numext::isnan)(this->res) || (!(numext::isnan)(value) && value < this->res)) |
184 | { |
185 | this->res = value; |
186 | this->row = i; |
187 | this->col = j; |
188 | } |
189 | } |
190 | }; |
191 | |
192 | template <typename Derived> |
193 | struct min_coeff_visitor<Derived, PropagateNaN> : coeff_visitor<Derived> |
194 | { |
195 | typedef typename Derived::Scalar Scalar; |
196 | EIGEN_DEVICE_FUNC |
197 | void operator() (const Scalar& value, Index i, Index j) |
198 | { |
199 | if((numext::isnan)(value) || value < this->res) |
200 | { |
201 | this->res = value; |
202 | this->row = i; |
203 | this->col = j; |
204 | } |
205 | } |
206 | }; |
207 | |
208 | template<typename Scalar, int NaNPropagation> |
209 | struct functor_traits<min_coeff_visitor<Scalar, NaNPropagation> > { |
210 | enum { |
211 | Cost = NumTraits<Scalar>::AddCost |
212 | }; |
213 | }; |
214 | |
215 | /** \internal |
216 | * \brief Visitor computing the max coefficient with its value and coordinates |
217 | * |
218 | * \sa DenseBase::maxCoeff(Index*, Index*) |
219 | */ |
220 | template <typename Derived, int NaNPropagation> |
221 | struct max_coeff_visitor : coeff_visitor<Derived> |
222 | { |
223 | typedef typename Derived::Scalar Scalar; |
224 | EIGEN_DEVICE_FUNC |
225 | void operator() (const Scalar& value, Index i, Index j) |
226 | { |
227 | if(value > this->res) |
228 | { |
229 | this->res = value; |
230 | this->row = i; |
231 | this->col = j; |
232 | } |
233 | } |
234 | }; |
235 | |
236 | template <typename Derived> |
237 | struct max_coeff_visitor<Derived, PropagateNumbers> : coeff_visitor<Derived> |
238 | { |
239 | typedef typename Derived::Scalar Scalar; |
240 | EIGEN_DEVICE_FUNC |
241 | void operator() (const Scalar& value, Index i, Index j) |
242 | { |
243 | if((numext::isnan)(this->res) || (!(numext::isnan)(value) && value > this->res)) |
244 | { |
245 | this->res = value; |
246 | this->row = i; |
247 | this->col = j; |
248 | } |
249 | } |
250 | }; |
251 | |
252 | template <typename Derived> |
253 | struct max_coeff_visitor<Derived, PropagateNaN> : coeff_visitor<Derived> |
254 | { |
255 | typedef typename Derived::Scalar Scalar; |
256 | EIGEN_DEVICE_FUNC |
257 | void operator() (const Scalar& value, Index i, Index j) |
258 | { |
259 | if((numext::isnan)(value) || value > this->res) |
260 | { |
261 | this->res = value; |
262 | this->row = i; |
263 | this->col = j; |
264 | } |
265 | } |
266 | }; |
267 | |
268 | template<typename Scalar, int NaNPropagation> |
269 | struct functor_traits<max_coeff_visitor<Scalar, NaNPropagation> > { |
270 | enum { |
271 | Cost = NumTraits<Scalar>::AddCost |
272 | }; |
273 | }; |
274 | |
275 | } // end namespace internal |
276 | |
277 | /** \fn DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const |
278 | * \returns the minimum of all coefficients of *this and puts in *row and *col its location. |
279 | * |
280 | * In case \c *this contains NaN, NaNPropagation determines the behavior: |
281 | * NaNPropagation == PropagateFast : undefined |
282 | * NaNPropagation == PropagateNaN : result is NaN |
283 | * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN |
284 | * \warning the matrix must be not empty, otherwise an assertion is triggered. |
285 | * |
286 | * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visit(), DenseBase::minCoeff() |
287 | */ |
288 | template<typename Derived> |
289 | template<int NaNPropagation, typename IndexType> |
290 | EIGEN_DEVICE_FUNC |
291 | typename internal::traits<Derived>::Scalar |
292 | DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const |
293 | { |
294 | eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix" ); |
295 | |
296 | internal::min_coeff_visitor<Derived, NaNPropagation> minVisitor; |
297 | this->visit(minVisitor); |
298 | *rowId = minVisitor.row; |
299 | if (colId) *colId = minVisitor.col; |
300 | return minVisitor.res; |
301 | } |
302 | |
303 | /** \returns the minimum of all coefficients of *this and puts in *index its location. |
304 | * |
305 | * In case \c *this contains NaN, NaNPropagation determines the behavior: |
306 | * NaNPropagation == PropagateFast : undefined |
307 | * NaNPropagation == PropagateNaN : result is NaN |
308 | * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN |
309 | * \warning the matrix must be not empty, otherwise an assertion is triggered. |
310 | * |
311 | * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::minCoeff() |
312 | */ |
313 | template<typename Derived> |
314 | template<int NaNPropagation, typename IndexType> |
315 | EIGEN_DEVICE_FUNC |
316 | typename internal::traits<Derived>::Scalar |
317 | DenseBase<Derived>::minCoeff(IndexType* index) const |
318 | { |
319 | eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix" ); |
320 | |
321 | EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) |
322 | internal::min_coeff_visitor<Derived, NaNPropagation> minVisitor; |
323 | this->visit(minVisitor); |
324 | *index = IndexType((RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row); |
325 | return minVisitor.res; |
326 | } |
327 | |
328 | /** \fn DenseBase<Derived>::maxCoeff(IndexType* rowId, IndexType* colId) const |
329 | * \returns the maximum of all coefficients of *this and puts in *row and *col its location. |
330 | * |
331 | * In case \c *this contains NaN, NaNPropagation determines the behavior: |
332 | * NaNPropagation == PropagateFast : undefined |
333 | * NaNPropagation == PropagateNaN : result is NaN |
334 | * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN |
335 | * \warning the matrix must be not empty, otherwise an assertion is triggered. |
336 | * |
337 | * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::maxCoeff() |
338 | */ |
339 | template<typename Derived> |
340 | template<int NaNPropagation, typename IndexType> |
341 | EIGEN_DEVICE_FUNC |
342 | typename internal::traits<Derived>::Scalar |
343 | DenseBase<Derived>::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const |
344 | { |
345 | eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix" ); |
346 | |
347 | internal::max_coeff_visitor<Derived, NaNPropagation> maxVisitor; |
348 | this->visit(maxVisitor); |
349 | *rowPtr = maxVisitor.row; |
350 | if (colPtr) *colPtr = maxVisitor.col; |
351 | return maxVisitor.res; |
352 | } |
353 | |
354 | /** \returns the maximum of all coefficients of *this and puts in *index its location. |
355 | * |
356 | * In case \c *this contains NaN, NaNPropagation determines the behavior: |
357 | * NaNPropagation == PropagateFast : undefined |
358 | * NaNPropagation == PropagateNaN : result is NaN |
359 | * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN |
360 | * \warning the matrix must be not empty, otherwise an assertion is triggered. |
361 | * |
362 | * \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff() |
363 | */ |
364 | template<typename Derived> |
365 | template<int NaNPropagation, typename IndexType> |
366 | EIGEN_DEVICE_FUNC |
367 | typename internal::traits<Derived>::Scalar |
368 | DenseBase<Derived>::maxCoeff(IndexType* index) const |
369 | { |
370 | eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix" ); |
371 | |
372 | EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) |
373 | internal::max_coeff_visitor<Derived, NaNPropagation> maxVisitor; |
374 | this->visit(maxVisitor); |
375 | *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row; |
376 | return maxVisitor.res; |
377 | } |
378 | |
379 | } // end namespace Eigen |
380 | |
381 | #endif // EIGEN_VISITOR_H |
382 | |