xref: /aosp_15_r20/external/eigen/Eigen/src/Core/Visitor.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <[email protected]>
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 // 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