Visitor.h
Go to the documentation of this file.
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 #include "./InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
17 namespace internal {
18 
19 template <typename Visitor, typename Derived, int UnrollCount,
20  bool Vectorize = (Derived::PacketAccess && functor_traits<Visitor>::PacketAccess), bool LinearAccess = false,
21  bool ShortCircuitEvaluation = false>
22 struct visitor_impl;
23 
24 template <typename Visitor, bool ShortCircuitEvaluation = false>
25 struct short_circuit_eval_impl {
26  // if short circuit evaluation is not used, do nothing
27  static EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run(const Visitor&) { return false; }
28 };
29 template <typename Visitor>
30 struct short_circuit_eval_impl<Visitor, true> {
31  // if short circuit evaluation is used, check the visitor
32  static EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run(const Visitor& visitor) {
33  return visitor.done();
34  }
35 };
36 
37 // unrolled inner-outer traversal
38 template <typename Visitor, typename Derived, int UnrollCount, bool Vectorize, bool ShortCircuitEvaluation>
39 struct visitor_impl<Visitor, Derived, UnrollCount, Vectorize, false, ShortCircuitEvaluation> {
40  // don't use short circuit evaulation for unrolled version
41  using Scalar = typename Derived::Scalar;
42  using Packet = typename packet_traits<Scalar>::type;
43  static constexpr bool RowMajor = Derived::IsRowMajor;
44  static constexpr int RowsAtCompileTime = Derived::RowsAtCompileTime;
45  static constexpr int ColsAtCompileTime = Derived::ColsAtCompileTime;
46  static constexpr int PacketSize = packet_traits<Scalar>::size;
47 
48  static constexpr bool CanVectorize(int K) {
49  constexpr int InnerSizeAtCompileTime = RowMajor ? ColsAtCompileTime : RowsAtCompileTime;
50  if(InnerSizeAtCompileTime < PacketSize) return false;
51  return Vectorize && (InnerSizeAtCompileTime - (K % InnerSizeAtCompileTime) >= PacketSize);
52  }
53 
54  template <int K = 0,
55  bool Empty = (K == UnrollCount),
56  std::enable_if_t<Empty, bool> = true>
57  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived&, Visitor&) {}
58 
59  template <int K = 0,
60  bool Empty = (K == UnrollCount),
61  bool Initialize = (K == 0),
62  bool DoVectorOp = CanVectorize(K),
63  std::enable_if_t<!Empty && Initialize && !DoVectorOp, bool> = true>
64  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor)
65  {
66  visitor.init(mat.coeff(0, 0), 0, 0);
67  run<1>(mat, visitor);
68  }
69 
70  template <int K = 0,
71  bool Empty = (K == UnrollCount),
72  bool Initialize = (K == 0),
73  bool DoVectorOp = CanVectorize(K),
74  std::enable_if_t<!Empty && !Initialize && !DoVectorOp, bool> = true>
75  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor)
76  {
77  static constexpr int R = RowMajor ? (K / ColsAtCompileTime) : (K % RowsAtCompileTime);
78  static constexpr int C = RowMajor ? (K % ColsAtCompileTime) : (K / RowsAtCompileTime);
79  visitor(mat.coeff(R, C), R, C);
80  run<K + 1>(mat, visitor);
81  }
82 
83  template <int K = 0,
84  bool Empty = (K == UnrollCount),
85  bool Initialize = (K == 0),
86  bool DoVectorOp = CanVectorize(K),
87  std::enable_if_t<!Empty && Initialize && DoVectorOp, bool> = true>
88  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor)
89  {
90  Packet P = mat.template packet<Packet>(0, 0);
91  visitor.initpacket(P, 0, 0);
92  run<PacketSize>(mat, visitor);
93  }
94 
95  template <int K = 0,
96  bool Empty = (K == UnrollCount),
97  bool Initialize = (K == 0),
98  bool DoVectorOp = CanVectorize(K),
99  std::enable_if_t<!Empty && !Initialize && DoVectorOp, bool> = true>
100  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor)
101  {
102  static constexpr int R = RowMajor ? (K / ColsAtCompileTime) : (K % RowsAtCompileTime);
103  static constexpr int C = RowMajor ? (K % ColsAtCompileTime) : (K / RowsAtCompileTime);
104  Packet P = mat.template packet<Packet>(R, C);
105  visitor.packet(P, R, C);
106  run<K + PacketSize>(mat, visitor);
107  }
108 };
109 
110 // unrolled linear traversal
111 template <typename Visitor, typename Derived, int UnrollCount, bool Vectorize, bool ShortCircuitEvaluation>
112 struct visitor_impl<Visitor, Derived, UnrollCount, Vectorize, true, ShortCircuitEvaluation> {
113  // don't use short circuit evaulation for unrolled version
114  using Scalar = typename Derived::Scalar;
115  using Packet = typename packet_traits<Scalar>::type;
116  static constexpr int PacketSize = packet_traits<Scalar>::size;
117 
118  static constexpr bool CanVectorize(int K) {
119  return Vectorize && ((UnrollCount - K) >= PacketSize);
120  }
121 
122  // empty
123  template <int K = 0,
124  bool Empty = (K == UnrollCount),
125  std::enable_if_t<Empty, bool> = true>
126  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived&, Visitor&) {}
127 
128  // scalar initialization
129  template <int K = 0,
130  bool Empty = (K == UnrollCount),
131  bool Initialize = (K == 0),
132  bool DoVectorOp = CanVectorize(K),
133  std::enable_if_t<!Empty && Initialize && !DoVectorOp, bool> = true>
134  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
135  visitor.init(mat.coeff(0), 0);
136  run<1>(mat, visitor);
137  }
138 
139  // scalar iteration
140  template <int K = 0,
141  bool Empty = (K == UnrollCount),
142  bool Initialize = (K == 0),
143  bool DoVectorOp = CanVectorize(K),
144  std::enable_if_t<!Empty && !Initialize && !DoVectorOp, bool> = true>
145  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
146  visitor(mat.coeff(K), K);
147  run<K + 1>(mat, visitor);
148  }
149 
150  // vector initialization
151  template <int K = 0,
152  bool Empty = (K == UnrollCount),
153  bool Initialize = (K == 0),
154  bool DoVectorOp = CanVectorize(K),
155  std::enable_if_t<!Empty && Initialize && DoVectorOp, bool> = true>
156  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
157  Packet P = mat.template packet<Packet>(0);
158  visitor.initpacket(P, 0);
159  run<PacketSize>(mat, visitor);
160  }
161 
162  // vector iteration
163  template <int K = 0,
164  bool Empty = (K == UnrollCount),
165  bool Initialize = (K == 0),
166  bool DoVectorOp = CanVectorize(K),
167  std::enable_if_t<!Empty && !Initialize && DoVectorOp, bool> = true>
168  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
169  Packet P = mat.template packet<Packet>(K);
170  visitor.packet(P, K);
171  run<K + PacketSize>(mat, visitor);
172  }
173 };
174 
175 // dynamic scalar outer-inner traversal
176 template <typename Visitor, typename Derived, bool ShortCircuitEvaluation>
177 struct visitor_impl<Visitor, Derived, Dynamic, /*Vectorize=*/false, /*LinearAccess=*/false, ShortCircuitEvaluation> {
178  using short_circuit = short_circuit_eval_impl<Visitor, ShortCircuitEvaluation>;
179  static constexpr bool RowMajor = Derived::IsRowMajor;
180 
181  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
182  const Index innerSize = RowMajor ? mat.cols() : mat.rows();
183  const Index outerSize = RowMajor ? mat.rows() : mat.cols();
184  if (innerSize == 0 || outerSize == 0) return;
185  {
186  visitor.init(mat.coeff(0, 0), 0, 0);
187  if (short_circuit::run(visitor)) return;
188  for (Index i = 1; i < innerSize; ++i) {
189  Index r = RowMajor ? 0 : i;
190  Index c = RowMajor ? i : 0;
191  visitor(mat.coeff(r, c), r, c);
192  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
193  }
194  }
195  for (Index j = 1; j < outerSize; j++) {
196  for (Index i = 0; i < innerSize; ++i) {
197  Index r = RowMajor ? j : i;
198  Index c = RowMajor ? i : j;
199  visitor(mat.coeff(r, c), r, c);
200  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
201  }
202  }
203  }
204 };
205 
206 // dynamic vectorized outer-inner traversal
207 template <typename Visitor, typename Derived, bool ShortCircuitEvaluation>
208 struct visitor_impl<Visitor, Derived, Dynamic, /*Vectorize=*/true, /*LinearAccess=*/false, ShortCircuitEvaluation> {
209  using Scalar = typename Derived::Scalar;
210  using Packet = typename packet_traits<Scalar>::type;
211  static constexpr int PacketSize = packet_traits<Scalar>::size;
212  using short_circuit = short_circuit_eval_impl<Visitor, ShortCircuitEvaluation>;
213  static constexpr bool RowMajor = Derived::IsRowMajor;
214 
215  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
216  const Index innerSize = RowMajor ? mat.cols() : mat.rows();
217  const Index outerSize = RowMajor ? mat.rows() : mat.cols();
218  if (innerSize == 0 || outerSize == 0) return;
219  {
220  Index i = 0;
221  if (innerSize < PacketSize) {
222  visitor.init(mat.coeff(0, 0), 0, 0);
223  i = 1;
224  } else {
225  Packet p = mat.template packet<Packet>(0, 0);
226  visitor.initpacket(p, 0, 0);
227  i = PacketSize;
228  }
229  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
230  for (; i + PacketSize - 1 < innerSize; i += PacketSize) {
231  Index r = RowMajor ? 0 : i;
232  Index c = RowMajor ? i : 0;
233  Packet p = mat.template packet<Packet>(r, c);
234  visitor.packet(p, r, c);
235  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
236  }
237  for (; i < innerSize; ++i) {
238  Index r = RowMajor ? 0 : i;
239  Index c = RowMajor ? i : 0;
240  visitor(mat.coeff(r, c), r, c);
241  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
242  }
243  }
244  for (Index j = 1; j < outerSize; j++) {
245  Index i = 0;
246  for (; i + PacketSize - 1 < innerSize; i += PacketSize) {
247  Index r = RowMajor ? j : i;
248  Index c = RowMajor ? i : j;
249  Packet p = mat.template packet<Packet>(r, c);
250  visitor.packet(p, r, c);
251  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
252  }
253  for (; i < innerSize; ++i) {
254  Index r = RowMajor ? j : i;
255  Index c = RowMajor ? i : j;
256  visitor(mat.coeff(r, c), r, c);
257  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
258  }
259  }
260  }
261 };
262 
263 // dynamic scalar linear traversal
264 template <typename Visitor, typename Derived, bool ShortCircuitEvaluation>
265 struct visitor_impl<Visitor, Derived, Dynamic, /*Vectorize=*/false, /*LinearAccess=*/true, ShortCircuitEvaluation> {
266  using short_circuit = short_circuit_eval_impl<Visitor, ShortCircuitEvaluation>;
267 
268  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
269  const Index size = mat.size();
270  if (size == 0) return;
271  visitor.init(mat.coeff(0), 0);
272  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
273  for (Index k = 1; k < size; k++) {
274  visitor(mat.coeff(k), k);
275  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
276  }
277  }
278 };
279 
280 // dynamic vectorized linear traversal
281 template <typename Visitor, typename Derived, bool ShortCircuitEvaluation>
282 struct visitor_impl<Visitor, Derived, Dynamic, /*Vectorize=*/true, /*LinearAccess=*/true, ShortCircuitEvaluation> {
283  using Scalar = typename Derived::Scalar;
284  using Packet = typename packet_traits<Scalar>::type;
285  static constexpr int PacketSize = packet_traits<Scalar>::size;
286  using short_circuit = short_circuit_eval_impl<Visitor, ShortCircuitEvaluation>;
287 
288  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& mat, Visitor& visitor) {
289  const Index size = mat.size();
290  if (size == 0) return;
291  Index k = 0;
292  if (size < PacketSize) {
293  visitor.init(mat.coeff(0), 0);
294  k = 1;
295  } else {
296  Packet p = mat.template packet<Packet>(k);
297  visitor.initpacket(p, k);
298  k = PacketSize;
299  }
300  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
301  for (; k + PacketSize - 1 < size; k += PacketSize) {
302  Packet p = mat.template packet<Packet>(k);
303  visitor.packet(p, k);
304  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
305  }
306  for (; k < size; k++) {
307  visitor(mat.coeff(k), k);
308  if EIGEN_PREDICT_FALSE(short_circuit::run(visitor)) return;
309  }
310  }
311 };
312 
313 // evaluator adaptor
314 template<typename XprType>
315 class visitor_evaluator
316 {
317 public:
318  typedef evaluator<XprType> Evaluator;
319  typedef typename XprType::Scalar Scalar;
320  using Packet = typename packet_traits<Scalar>::type;
321  typedef std::remove_const_t<typename XprType::CoeffReturnType> CoeffReturnType;
322 
323  static constexpr bool PacketAccess = static_cast<bool>(Evaluator::Flags & PacketAccessBit);
324  static constexpr bool LinearAccess = static_cast<bool>(Evaluator::Flags & LinearAccessBit);
325  static constexpr bool IsRowMajor = static_cast<bool>(XprType::IsRowMajor);
326  static constexpr int RowsAtCompileTime = XprType::RowsAtCompileTime;
327  static constexpr int ColsAtCompileTime = XprType::ColsAtCompileTime;
328  static constexpr int XprAlignment = Evaluator::Alignment;
329  static constexpr int CoeffReadCost = Evaluator::CoeffReadCost;
330 
332  explicit visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) { }
333 
334  EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_xpr.rows(); }
335  EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_xpr.cols(); }
336  EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_xpr.size(); }
337  // outer-inner access
338  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_evaluator.coeff(row, col); }
339  template <typename Packet, int Alignment = Unaligned>
340  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(Index row, Index col) const {
341  return m_evaluator.template packet<Alignment, Packet>(row, col);
342  }
343  // linear access
344  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_evaluator.coeff(index); }
345  template <typename Packet, int Alignment = XprAlignment>
346  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(Index index) const {
347  return m_evaluator.template packet<Alignment, Packet>(index);
348  }
349 
350 protected:
351  Evaluator m_evaluator;
352  const XprType &m_xpr;
353 };
354 
355 template <typename Derived, typename Visitor, bool ShortCircuitEvaulation>
356 struct visit_impl {
357  using Evaluator = visitor_evaluator<Derived>;
358  using Scalar = typename DenseBase<Derived>::Scalar;
359 
360  static constexpr bool IsRowMajor = DenseBase<Derived>::IsRowMajor;
361  static constexpr int SizeAtCompileTime = DenseBase<Derived>::SizeAtCompileTime;
362  static constexpr int RowsAtCompileTime = DenseBase<Derived>::RowsAtCompileTime;
363  static constexpr int ColsAtCompileTime = DenseBase<Derived>::ColsAtCompileTime;
364  static constexpr int InnerSizeAtCompileTime = IsRowMajor ? ColsAtCompileTime : RowsAtCompileTime;
365  static constexpr int OuterSizeAtCompileTime = IsRowMajor ? RowsAtCompileTime : ColsAtCompileTime;
366 
367  static constexpr bool LinearAccess = Evaluator::LinearAccess && static_cast<bool>(functor_traits<Visitor>::LinearAccess);
368  static constexpr bool Vectorize = Evaluator::PacketAccess && static_cast<bool>(functor_traits<Visitor>::PacketAccess);
369 
370  static constexpr int PacketSize = packet_traits<Scalar>::size;
371  static constexpr int VectorOps = Vectorize ? (LinearAccess ? (SizeAtCompileTime / PacketSize) : (OuterSizeAtCompileTime * (InnerSizeAtCompileTime / PacketSize))) : 0;
372  static constexpr int ScalarOps = SizeAtCompileTime - (VectorOps * PacketSize);
373  // treat vector op and scalar op as same cost for unroll logic
374  static constexpr int TotalOps = VectorOps + ScalarOps;
375 
376  static constexpr int UnrollCost = int(Evaluator::CoeffReadCost) + int(functor_traits<Visitor>::Cost);
377  static constexpr bool Unroll = (SizeAtCompileTime != Dynamic) && ((TotalOps * UnrollCost) <= EIGEN_UNROLLING_LIMIT);
378  static constexpr int UnrollCount = Unroll ? int(SizeAtCompileTime) : Dynamic;
379 
380 
381  using impl = visitor_impl<Visitor, Evaluator, UnrollCount, Vectorize, LinearAccess, ShortCircuitEvaulation>;
382 
383  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const DenseBase<Derived>& mat, Visitor& visitor) {
384  Evaluator evaluator(mat.derived());
385  impl::run(evaluator, visitor);
386  }
387 };
388 
389 } // end namespace internal
390 
410 template<typename Derived>
411 template<typename Visitor>
413 void DenseBase<Derived>::visit(Visitor& visitor) const
414 {
415  using impl = internal::visit_impl<Derived, Visitor, /*ShortCircuitEvaulation*/false>;
416  impl::run(derived(), visitor);
417 }
418 
419 namespace internal {
420 
424 template <typename Derived>
425 struct coeff_visitor
426 {
427  // default initialization to avoid countless invalid maybe-uninitialized warnings by gcc
429  coeff_visitor() : row(-1), col(-1), res(0) {}
430  typedef typename Derived::Scalar Scalar;
431  Index row, col;
432  Scalar res;
434  inline void init(const Scalar& value, Index i, Index j)
435  {
436  res = value;
437  row = i;
438  col = j;
439  }
440 };
441 
442 
443 template <typename Scalar, int NaNPropagation, bool is_min = true>
444 struct minmax_compare {
445  typedef typename packet_traits<Scalar>::type Packet;
446  static EIGEN_DEVICE_FUNC inline bool compare(Scalar a, Scalar b) { return a < b; }
447  static EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& p) { return predux_min<NaNPropagation>(p); }
448 };
449 
450 template <typename Scalar, int NaNPropagation>
451 struct minmax_compare<Scalar, NaNPropagation, false> {
452  typedef typename packet_traits<Scalar>::type Packet;
453  static EIGEN_DEVICE_FUNC inline bool compare(Scalar a, Scalar b) { return a > b; }
454  static EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& p) { return predux_max<NaNPropagation>(p); }
455 };
456 
457 // Default implementation used by non-floating types, where we do not
458 // need special logic for NaN handling.
459 template <typename Derived, bool is_min, int NaNPropagation,
461 struct minmax_coeff_visitor : coeff_visitor<Derived> {
462  using Scalar = typename Derived::Scalar;
463  using Packet = typename packet_traits<Scalar>::type;
464  using Comparator = minmax_compare<Scalar, NaNPropagation, is_min>;
465  static constexpr Index PacketSize = packet_traits<Scalar>::size;
466 
467  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index i, Index j) {
468  if (Comparator::compare(value, this->res)) {
469  this->res = value;
470  this->row = i;
471  this->col = j;
472  }
473  }
474  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index i, Index j) {
476  if (Comparator::compare(value, this->res)) {
477  const Packet range = preverse(plset<Packet>(Scalar(1)));
478  Packet mask = pcmp_eq(pset1<Packet>(value), p);
479  Index max_idx = PacketSize - static_cast<Index>(predux_max(pand(range, mask)));
480  this->res = value;
481  this->row = Derived::IsRowMajor ? i : i + max_idx;
482  this->col = Derived::IsRowMajor ? j + max_idx : j;
483  }
484  }
485  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index i, Index j) {
486  Scalar value = Comparator::predux(p);
487  const Packet range = preverse(plset<Packet>(Scalar(1)));
488  Packet mask = pcmp_eq(pset1<Packet>(value), p);
489  Index max_idx = PacketSize - static_cast<Index>(predux_max(pand(range, mask)));
490  this->res = value;
491  this->row = Derived::IsRowMajor ? i : i + max_idx;
492  this->col = Derived::IsRowMajor ? j + max_idx : j;
493  }
494 };
495 
496 // Suppress NaN. The only case in which we return NaN is if the matrix is all NaN,
497 // in which case, row=0, col=0 is returned for the location.
498 template <typename Derived, bool is_min>
499 struct minmax_coeff_visitor<Derived, is_min, PropagateNumbers, false> : coeff_visitor<Derived> {
500  typedef typename Derived::Scalar Scalar;
501  using Packet = typename packet_traits<Scalar>::type;
502  using Comparator = minmax_compare<Scalar, PropagateNumbers, is_min>;
503 
504  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index i, Index j) {
505  if ((!(numext::isnan)(value) && (numext::isnan)(this->res)) || Comparator::compare(value, this->res)) {
506  this->res = value;
507  this->row = i;
508  this->col = j;
509  }
510  }
511  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index i, Index j) {
512  const Index PacketSize = packet_traits<Scalar>::size;
513  Scalar value = Comparator::predux(p);
514  if ((!(numext::isnan)(value) && (numext::isnan)(this->res)) || Comparator::compare(value, this->res)) {
515  const Packet range = preverse(plset<Packet>(Scalar(1)));
516  /* mask will be zero for NaNs, so they will be ignored. */
517  Packet mask = pcmp_eq(pset1<Packet>(value), p);
518  Index max_idx = PacketSize - static_cast<Index>(predux_max(pand(range, mask)));
519  this->res = value;
520  this->row = Derived::IsRowMajor ? i : i + max_idx;
521  this->col = Derived::IsRowMajor ? j + max_idx : j;
522  }
523  }
524  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index i, Index j) {
525  const Index PacketSize = packet_traits<Scalar>::size;
526  Scalar value = Comparator::predux(p);
527  if ((numext::isnan)(value)) {
528  this->res = value;
529  this->row = 0;
530  this->col = 0;
531  return;
532  }
533  const Packet range = preverse(plset<Packet>(Scalar(1)));
534  /* mask will be zero for NaNs, so they will be ignored. */
535  Packet mask = pcmp_eq(pset1<Packet>(value), p);
536  Index max_idx = PacketSize - static_cast<Index>(predux_max(pand(range, mask)));
537  this->res = value;
538  this->row = Derived::IsRowMajor ? i : i + max_idx;
539  this->col = Derived::IsRowMajor ? j + max_idx : j;
540  }
541 };
542 
543 // Propagate NaNs. If the matrix contains NaN, the location of the first NaN
544 // will be returned in row and col.
545 template <typename Derived, bool is_min, int NaNPropagation>
546  struct minmax_coeff_visitor<Derived, is_min, NaNPropagation, false> : coeff_visitor<Derived> {
547  typedef typename Derived::Scalar Scalar;
548  using Packet = typename packet_traits<Scalar>::type;
549  using Comparator = minmax_compare<Scalar, PropagateNaN, is_min>;
550 
551  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index i, Index j) {
552  const bool value_is_nan = (numext::isnan)(value);
553  if ((value_is_nan && !(numext::isnan)(this->res)) || Comparator::compare(value, this->res)) {
554  this->res = value;
555  this->row = i;
556  this->col = j;
557  }
558  }
559  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index i, Index j) {
560  const Index PacketSize = packet_traits<Scalar>::size;
561  Scalar value = Comparator::predux(p);
562  const bool value_is_nan = (numext::isnan)(value);
563  if ((value_is_nan && !(numext::isnan)(this->res)) || Comparator::compare(value, this->res)) {
564  const Packet range = preverse(plset<Packet>(Scalar(1)));
565  // If the value is NaN, pick the first position of a NaN, otherwise pick the first extremal value.
566  Packet mask = value_is_nan ? pnot(pcmp_eq(p, p)) : pcmp_eq(pset1<Packet>(value), p);
567  Index max_idx = PacketSize - static_cast<Index>(predux_max(pand(range, mask)));
568  this->res = value;
569  this->row = Derived::IsRowMajor ? i : i + max_idx;
570  this->col = Derived::IsRowMajor ? j + max_idx : j;
571  }
572  }
573  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index i, Index j) {
574  const Index PacketSize = packet_traits<Scalar>::size;
575  Scalar value = Comparator::predux(p);
576  const bool value_is_nan = (numext::isnan)(value);
577  const Packet range = preverse(plset<Packet>(Scalar(1)));
578  // If the value is NaN, pick the first position of a NaN, otherwise pick the first extremal value.
579  Packet mask = value_is_nan ? pnot(pcmp_eq(p, p)) : pcmp_eq(pset1<Packet>(value), p);
580  Index max_idx = PacketSize - static_cast<Index>(predux_max(pand(range, mask)));
581  this->res = value;
582  this->row = Derived::IsRowMajor ? i : i + max_idx;
583  this->col = Derived::IsRowMajor ? j + max_idx : j;
584  }
585 };
586 
587 template<typename Derived, bool is_min, int NaNPropagation>
588 struct functor_traits<minmax_coeff_visitor<Derived, is_min, NaNPropagation> > {
589  using Scalar = typename Derived::Scalar;
590  enum {
592  LinearAccess = false,
593  PacketAccess = packet_traits<Scalar>::HasCmp
594  };
595 };
596 
597 template <typename Scalar>
598 struct all_visitor {
599  using result_type = bool;
600  using Packet = typename packet_traits<Scalar>::type;
601  EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index, Index) { res = (value != Scalar(0)); }
602  EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index) { res = (value != Scalar(0)); }
603  EIGEN_DEVICE_FUNC inline bool all_predux(const Packet& p) const { return !predux_any(pcmp_eq(p, pzero(p))); }
604  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index, Index) { res = all_predux(p); }
605  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index) { res = all_predux(p); }
606  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index, Index) { res = res && (value != Scalar(0)); }
607  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index) { res = res && (value != Scalar(0)); }
608  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index, Index) { res = res && all_predux(p); }
609  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index) { res = res && all_predux(p); }
610  EIGEN_DEVICE_FUNC inline bool done() const { return !res; }
611  bool res = true;
612 };
613 template <typename Scalar>
614 struct functor_traits<all_visitor<Scalar>> {
615  enum { Cost = NumTraits<Scalar>::ReadCost, LinearAccess = true, PacketAccess = packet_traits<Scalar>::HasCmp };
616 };
617 
618 template <typename Scalar>
619 struct any_visitor {
620  using result_type = bool;
621  using Packet = typename packet_traits<Scalar>::type;
622  EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index, Index) { res = (value != Scalar(0)); }
623  EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index) { res = (value != Scalar(0)); }
624  EIGEN_DEVICE_FUNC inline bool any_predux(const Packet& p) const {
625  return predux_any(pandnot(ptrue(p), pcmp_eq(p, pzero(p))));
626  }
627  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index, Index) { res = any_predux(p); }
628  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index) { res = any_predux(p); }
629  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index, Index) { res = res || (value != Scalar(0)); }
630  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index) { res = res || (value != Scalar(0)); }
631  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index, Index) { res = res || any_predux(p); }
632  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index) { res = res || any_predux(p); }
633  EIGEN_DEVICE_FUNC inline bool done() const { return res; }
634  bool res = false;
635 };
636 template <typename Scalar>
637 struct functor_traits<any_visitor<Scalar>> {
638  enum { Cost = NumTraits<Scalar>::ReadCost, LinearAccess = true, PacketAccess = packet_traits<Scalar>::HasCmp };
639 };
640 
641 template <typename Scalar>
642 struct count_visitor {
643  using result_type = Index;
644  using Packet = typename packet_traits<Scalar>::type;
645  EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index, Index) { res = value != Scalar(0) ? 1 : 0; }
646  EIGEN_DEVICE_FUNC inline void init(const Scalar& value, Index) { res = value != Scalar(0) ? 1 : 0; }
647  EIGEN_DEVICE_FUNC inline Index count_redux(const Packet& p) const {
648  const Packet cst_one = pset1<Packet>(Scalar(1));
649  Packet true_vals = pandnot(cst_one, pcmp_eq(p, pzero(p)));
650  Scalar num_true = predux(true_vals);
651  return static_cast<Index>(num_true);
652  }
653  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index, Index) { res = count_redux(p); }
654  EIGEN_DEVICE_FUNC inline void initpacket(const Packet& p, Index) { res = count_redux(p); }
655  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index, Index) {
656  if (value != Scalar(0)) res++;
657  }
658  EIGEN_DEVICE_FUNC inline void operator()(const Scalar& value, Index) {
659  if (value != Scalar(0)) res++;
660  }
661  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index, Index) { res += count_redux(p); }
662  EIGEN_DEVICE_FUNC inline void packet(const Packet& p, Index) { res += count_redux(p); }
663  Index res = 0;
664 };
665 
666 template <typename Scalar>
667 struct functor_traits<count_visitor<Scalar>> {
668  enum {
670  LinearAccess = true,
671  // predux is problematic for bool
672  PacketAccess = packet_traits<Scalar>::HasCmp && packet_traits<Scalar>::HasAdd && !is_same<Scalar, bool>::value
673  };
674 };
675 
676 } // end namespace internal
677 
689 template<typename Derived>
690 template<int NaNPropagation, typename IndexType>
692 typename internal::traits<Derived>::Scalar
693 DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const
694 {
695  eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix");
696 
697  internal::minmax_coeff_visitor<Derived, true, NaNPropagation> minVisitor;
698  this->visit(minVisitor);
699  *rowId = minVisitor.row;
700  if (colId) *colId = minVisitor.col;
701  return minVisitor.res;
702 }
703 
714 template<typename Derived>
715 template<int NaNPropagation, typename IndexType>
717 typename internal::traits<Derived>::Scalar
718 DenseBase<Derived>::minCoeff(IndexType* index) const
719 {
720  eigen_assert(this->rows() > 0 && this->cols() > 0 && "you are using an empty matrix");
722 
723  internal::minmax_coeff_visitor<Derived, true, NaNPropagation> minVisitor;
724  this->visit(minVisitor);
725  *index = IndexType((RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row);
726  return minVisitor.res;
727 }
728 
740 template<typename Derived>
741 template<int NaNPropagation, typename IndexType>
743 typename internal::traits<Derived>::Scalar
744 DenseBase<Derived>::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const
745 {
746  eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix");
747 
748  internal::minmax_coeff_visitor<Derived, false, NaNPropagation> maxVisitor;
749  this->visit(maxVisitor);
750  *rowPtr = maxVisitor.row;
751  if (colPtr) *colPtr = maxVisitor.col;
752  return maxVisitor.res;
753 }
754 
765 template<typename Derived>
766 template<int NaNPropagation, typename IndexType>
768 typename internal::traits<Derived>::Scalar
769 DenseBase<Derived>::maxCoeff(IndexType* index) const
770 {
771  eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix");
772 
774  internal::minmax_coeff_visitor<Derived, false, NaNPropagation> maxVisitor;
775  this->visit(maxVisitor);
776  *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row;
777  return maxVisitor.res;
778 }
779 
787 template <typename Derived>
789  using Visitor = internal::all_visitor<Scalar>;
790  using impl = internal::visit_impl<Derived, Visitor, /*ShortCircuitEvaulation*/true>;
791  Visitor visitor;
792  impl::run(derived(), visitor);
793  return visitor.res;
794 }
795 
800 template <typename Derived>
802  using Visitor = internal::any_visitor<Scalar>;
803  using impl = internal::visit_impl<Derived, Visitor, /*ShortCircuitEvaulation*/true>;
804  Visitor visitor;
805  impl::run(derived(), visitor);
806  return visitor.res;
807 }
808 
813 template<typename Derived>
816 {
817  using Visitor = internal::count_visitor<Scalar>;
818  using impl = internal::visit_impl<Derived, Visitor, /*ShortCircuitEvaulation*/false>;
819  Visitor visitor;
820  impl::run(derived(), visitor);
821  return visitor.res;
822 
823 }
824 
825 template <typename Derived>
827  return derived().cwiseTypedNotEqual(derived()).any();
828 }
829 
834 template <typename Derived>
836  return derived().array().isFinite().all();
837 }
838 
839 } // end namespace Eigen
840 
841 #endif // EIGEN_VISITOR_H
Array< int, 3, 1 > b
RowXpr row(Index i)
This is the const version of row(). *‍/.
ColXpr col(Index i)
This is the const version of col().
Array33i c
Projective3d P(Matrix4d::Random())
IndexedView_or_Block operator()(const RowIndices &rowIndices, const ColIndices &colIndices)
#define EIGEN_NOEXCEPT
Definition: Macros.h:1260
#define EIGEN_CONSTEXPR
Definition: Macros.h:747
#define EIGEN_PREDICT_FALSE(x)
Definition: Macros.h:1177
#define EIGEN_DEVICE_FUNC
Definition: Macros.h:883
#define eigen_assert(x)
Definition: Macros.h:902
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
#define EIGEN_UNROLLING_LIMIT
Definition: Settings.h:24
#define EIGEN_STATIC_ASSERT_VECTOR_ONLY(TYPE)
Definition: StaticAssert.h:36
float * p
internal::traits< Derived >::Scalar minCoeff() const
Definition: Redux.h:518
void visit(Visitor &func) const
Definition: Visitor.h:413
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
internal::traits< Derived >::Scalar maxCoeff() const
Definition: Redux.h:533
bool hasNaN() const
Definition: Visitor.h:826
Index count() const
Definition: Visitor.h:815
bool any() const
Definition: Visitor.h:801
bool all() const
Definition: Visitor.h:788
bool allFinite() const
Definition: Visitor.h:835
@ PropagateNumbers
Definition: Constants.h:347
@ RowMajor
Definition: Constants.h:323
const unsigned int PacketAccessBit
Definition: Constants.h:96
const unsigned int LinearAccessBit
Definition: Constants.h:132
Packet8f pzero(const Packet8f &)
unpacket_traits< Packet >::type predux(const Packet &a)
Packet8h ptrue(const Packet8h &a)
Packet8h pandnot(const Packet8h &a, const Packet8h &b)
Packet2cf pcmp_eq(const Packet2cf &a, const Packet2cf &b)
Packet8h pand(const Packet8h &a, const Packet8h &b)
Packet pnot(const Packet &a)
Packet pset1(const typename unpacket_traits< Packet >::type &a)
unpacket_traits< Packet >::type predux_max(const Packet &a)
Packet2cf preverse(const Packet2cf &a)
bool predux_any(const Packet4f &x)
EIGEN_ALWAYS_INLINE bool() isnan(const Eigen::bfloat16 &h)
Definition: BFloat16.h:778
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const int Dynamic
Definition: Constants.h:24
Eigen::Index Index
The interface type of indices.
Definition: EigenBase.h:41
std::ptrdiff_t j