aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Rasmus Munk Larsen <rmlarsen@google.com>2020-10-13 21:48:31 +0000
committerGravatar Rasmus Munk Larsen <rmlarsen@google.com>2020-10-13 21:48:31 +0000
commitc6953f799b01d36f4236b64f351cc1446e0abe17 (patch)
tree9abcded97c6effc010d08787c5b43ef7bb043b54
parent807e51528d220c0efed870f0505dea81a5776085 (diff)
Add packet generic ops `predux_fmin`, `predux_fmin_nan`, `predux_fmax`, and `predux_fmax_nan` that implement reductions with `PropagateNaN`, and `PropagateNumbers` semantics. Add (slow) generic implementations for most reductions.
-rw-r--r--Eigen/src/Core/GenericPacketMath.h380
-rw-r--r--Eigen/src/Core/functors/BinaryFunctors.h42
-rw-r--r--test/packetmath.cpp62
-rw-r--r--unsupported/Eigen/CXX11/src/Tensor/TensorBase.h22
-rw-r--r--unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h41
-rw-r--r--unsupported/test/cxx11_tensor_expr.cpp94
6 files changed, 371 insertions, 270 deletions
diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h
index 32cedd0b1..a734d99b7 100644
--- a/Eigen/src/Core/GenericPacketMath.h
+++ b/Eigen/src/Core/GenericPacketMath.h
@@ -215,74 +215,29 @@ pmul(const bool& a, const bool& b) { return a && b; }
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
pdiv(const Packet& a, const Packet& b) { return a/b; }
-/** \internal \returns the min of \a a and \a b (coeff-wise).
- If \a a or \b b is NaN, the return value is implementation defined. */
+/** \internal \returns one bits */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pmin(const Packet& a, const Packet& b) { return numext::mini(a, b); }
+ptrue(const Packet& /*a*/) { Packet b; memset((void*)&b, 0xff, sizeof(b)); return b;}
-/** \internal \returns the max of \a a and \a b (coeff-wise)
- If \a a or \b b is NaN, the return value is implementation defined. */
+/** \internal \returns zero bits */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pmax(const Packet& a, const Packet& b) { return numext::maxi(a, b); }
+pzero(const Packet& /*a*/) { Packet b; memset((void*)&b, 0, sizeof(b)); return b;}
-/** \internal \returns the absolute value of \a a */
+/** \internal \returns a <= b as a bit mask */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pabs(const Packet& a) { using std::abs; return abs(a); }
-template<> EIGEN_DEVICE_FUNC inline unsigned int
-pabs(const unsigned int& a) { return a; }
-template<> EIGEN_DEVICE_FUNC inline unsigned long
-pabs(const unsigned long& a) { return a; }
-template<> EIGEN_DEVICE_FUNC inline unsigned long long
-pabs(const unsigned long long& a) { return a; }
+pcmp_le(const Packet& a, const Packet& b) { return a<=b ? ptrue(a) : pzero(a); }
-/** \internal \returns the phase angle of \a a */
+/** \internal \returns a < b as a bit mask */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-parg(const Packet& a) { using numext::arg; return arg(a); }
-
-
-/** \internal \returns \a a logically shifted by N bits to the right */
-template<int N> EIGEN_DEVICE_FUNC inline int
-parithmetic_shift_right(const int& a) { return a >> N; }
-template<int N> EIGEN_DEVICE_FUNC inline long int
-parithmetic_shift_right(const long int& a) { return a >> N; }
-
-/** \internal \returns \a a arithmetically shifted by N bits to the right */
-template<int N> EIGEN_DEVICE_FUNC inline int
-plogical_shift_right(const int& a) { return static_cast<int>(static_cast<unsigned int>(a) >> N); }
-template<int N> EIGEN_DEVICE_FUNC inline long int
-plogical_shift_right(const long int& a) { return static_cast<long>(static_cast<unsigned long>(a) >> N); }
-
-/** \internal \returns \a a shifted by N bits to the left */
-template<int N> EIGEN_DEVICE_FUNC inline int
-plogical_shift_left(const int& a) { return a << N; }
-template<int N> EIGEN_DEVICE_FUNC inline long int
-plogical_shift_left(const long int& a) { return a << N; }
-
-/** \internal \returns the significant and exponent of the underlying floating point numbers
- * See https://en.cppreference.com/w/cpp/numeric/math/frexp
- */
-template <typename Packet>
-EIGEN_DEVICE_FUNC inline Packet pfrexp(const Packet& a, Packet& exponent) {
- int exp;
- EIGEN_USING_STD(frexp);
- Packet result = frexp(a, &exp);
- exponent = static_cast<Packet>(exp);
- return result;
-}
+pcmp_lt(const Packet& a, const Packet& b) { return a<b ? ptrue(a) : pzero(a); }
-/** \internal \returns a * 2^exponent
- * See https://en.cppreference.com/w/cpp/numeric/math/ldexp
- */
+/** \internal \returns a == b as a bit mask */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pldexp(const Packet &a, const Packet &exponent) {
- EIGEN_USING_STD(ldexp)
- return ldexp(a, static_cast<int>(exponent));
-}
+pcmp_eq(const Packet& a, const Packet& b) { return a==b ? ptrue(a) : pzero(a); }
-/** \internal \returns zero bits */
+/** \internal \returns a < b or a==NaN or b==NaN as a bit mask */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pzero(const Packet& /*a*/) { Packet b; memset((void*)&b, 0, sizeof(b)); return b;}
-
+pcmp_lt_or_nan(const Packet& a, const Packet& b) { return a>=b ? pzero(a) : ptrue(a); }
template<> EIGEN_DEVICE_FUNC inline float pzero<float>(const float& a) {
EIGEN_UNUSED_VARIABLE(a)
return 0.f;
@@ -293,10 +248,6 @@ template<> EIGEN_DEVICE_FUNC inline double pzero<double>(const double& a) {
return 0.;
}
-/** \internal \returns one bits */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-ptrue(const Packet& /*a*/) { Packet b; memset((void*)&b, 0xff, sizeof(b)); return b;}
-
template <typename RealScalar>
EIGEN_DEVICE_FUNC inline std::complex<RealScalar> ptrue(const std::complex<RealScalar>& /*a*/) {
RealScalar b;
@@ -341,22 +292,6 @@ pxor(const Packet& a, const Packet& b) {
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
pandnot(const Packet& a, const Packet& b) { return pand(a, pxor(ptrue(b), b)); }
-/** \internal \returns a <= b as a bit mask */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pcmp_le(const Packet& a, const Packet& b) { return a<=b ? ptrue(a) : pzero(a); }
-
-/** \internal \returns a < b as a bit mask */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pcmp_lt(const Packet& a, const Packet& b) { return a<b ? ptrue(a) : pzero(a); }
-
-/** \internal \returns a == b as a bit mask */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pcmp_eq(const Packet& a, const Packet& b) { return a==b ? ptrue(a) : pzero(a); }
-
-/** \internal \returns a < b or a==NaN or b==NaN as a bit mask */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pcmp_lt_or_nan(const Packet& a, const Packet& b) { return a>=b ? pzero(a) : ptrue(a); }
-
/** \internal \returns \a or \b for each field in packet according to \mask */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
pselect(const Packet& mask, const Packet& a, const Packet& b) {
@@ -378,6 +313,119 @@ template<> EIGEN_DEVICE_FUNC inline bool pselect<bool>(
return cond ? a : b;
}
+/** \internal \returns the min or of \a a and \a b (coeff-wise)
+ If either \a a or \a b are NaN, the result is implementation defined. */
+template<int NaNPropagation>
+struct pminmax_impl {
+ template <typename Packet, typename Op>
+ static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a, const Packet& b, Op op) {
+ return op(a,b);
+ }
+};
+
+/** \internal \returns the min or max of \a a and \a b (coeff-wise)
+ If either \a a or \a b are NaN, NaN is returned. */
+template<>
+struct pminmax_impl<PropagateNaN> {
+ template <typename Packet, typename Op>
+ static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a, const Packet& b, Op op) {
+ Packet not_nan_mask_a = pcmp_eq(a, a);
+ Packet not_nan_mask_b = pcmp_eq(b, b);
+ return pselect(not_nan_mask_a,
+ pselect(not_nan_mask_b, op(a, b), b),
+ a);
+ }
+};
+
+/** \internal \returns the min or max of \a a and \a b (coeff-wise)
+ If both \a a and \a b are NaN, NaN is returned.
+ Equivalent to std::fmin(a, b). */
+template<>
+struct pminmax_impl<PropagateNumbers> {
+ template <typename Packet, typename Op>
+ static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a, const Packet& b, Op op) {
+ Packet not_nan_mask_a = pcmp_eq(a, a);
+ Packet not_nan_mask_b = pcmp_eq(b, b);
+ return pselect(not_nan_mask_a,
+ pselect(not_nan_mask_b, op(a, b), a),
+ b);
+ }
+};
+
+/** \internal \returns the min of \a a and \a b (coeff-wise).
+ If \a a or \b b is NaN, the return value is implementation defined. */
+template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
+pmin(const Packet& a, const Packet& b) { return numext::mini(a,b); }
+
+/** \internal \returns the min of \a a and \a b (coeff-wise).
+ NaNPropagation determines the NaN propagation semantics. */
+template<int NaNPropagation, typename Packet> EIGEN_DEVICE_FUNC inline Packet
+pmin(const Packet& a, const Packet& b) { return pminmax_impl<NaNPropagation>::run(a,b, pmin<Packet>); }
+
+/** \internal \returns the max of \a a and \a b (coeff-wise)
+ If \a a or \b b is NaN, the return value is implementation defined. */
+template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
+pmax(const Packet& a, const Packet& b) { return numext::maxi(a, b); }
+
+/** \internal \returns the max of \a a and \a b (coeff-wise).
+ NaNPropagation determines the NaN propagation semantics. */
+template<int NaNPropagation, typename Packet> EIGEN_DEVICE_FUNC inline Packet
+pmax(const Packet& a, const Packet& b) { return pminmax_impl<NaNPropagation>::run(a,b, pmax<Packet>); }
+
+/** \internal \returns the absolute value of \a a */
+template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
+pabs(const Packet& a) { return numext::abs(a); }
+template<> EIGEN_DEVICE_FUNC inline unsigned int
+pabs(const unsigned int& a) { return a; }
+template<> EIGEN_DEVICE_FUNC inline unsigned long
+pabs(const unsigned long& a) { return a; }
+template<> EIGEN_DEVICE_FUNC inline unsigned long long
+pabs(const unsigned long long& a) { return a; }
+
+/** \internal \returns the phase angle of \a a */
+template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
+parg(const Packet& a) { using numext::arg; return arg(a); }
+
+
+/** \internal \returns \a a logically shifted by N bits to the right */
+template<int N> EIGEN_DEVICE_FUNC inline int
+parithmetic_shift_right(const int& a) { return a >> N; }
+template<int N> EIGEN_DEVICE_FUNC inline long int
+parithmetic_shift_right(const long int& a) { return a >> N; }
+
+/** \internal \returns \a a arithmetically shifted by N bits to the right */
+template<int N> EIGEN_DEVICE_FUNC inline int
+plogical_shift_right(const int& a) { return static_cast<int>(static_cast<unsigned int>(a) >> N); }
+template<int N> EIGEN_DEVICE_FUNC inline long int
+plogical_shift_right(const long int& a) { return static_cast<long>(static_cast<unsigned long>(a) >> N); }
+
+/** \internal \returns \a a shifted by N bits to the left */
+template<int N> EIGEN_DEVICE_FUNC inline int
+plogical_shift_left(const int& a) { return a << N; }
+template<int N> EIGEN_DEVICE_FUNC inline long int
+plogical_shift_left(const long int& a) { return a << N; }
+
+/** \internal \returns the significant and exponent of the underlying floating point numbers
+ * See https://en.cppreference.com/w/cpp/numeric/math/frexp
+ */
+template <typename Packet>
+EIGEN_DEVICE_FUNC inline Packet pfrexp(const Packet& a, Packet& exponent) {
+ int exp;
+ EIGEN_USING_STD(frexp);
+ Packet result = frexp(a, &exp);
+ exponent = static_cast<Packet>(exp);
+ return result;
+}
+
+/** \internal \returns a * 2^exponent
+ * See https://en.cppreference.com/w/cpp/numeric/math/ldexp
+ */
+template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
+pldexp(const Packet &a, const Packet &exponent) {
+ EIGEN_USING_STD(ldexp)
+ return ldexp(a, static_cast<int>(exponent));
+}
+
/** \internal \returns the min of \a a and \a b (coeff-wise) */
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
pabsdiff(const Packet& a, const Packet& b) { return pselect(pcmp_lt(a, b), psub(b, a), psub(a, b)); }
@@ -507,57 +555,6 @@ template<typename Scalar> EIGEN_DEVICE_FUNC inline void prefetch(const Scalar* a
#endif
}
-/** \internal \returns the first element of a packet */
-template<typename Packet> EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type pfirst(const Packet& a)
-{ return a; }
-
-/** \internal \returns the sum of the elements of \a a*/
-template<typename Packet> EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type predux(const Packet& a)
-{ return a; }
-
-/** \internal \returns the sum of the elements of upper and lower half of \a a if \a a is larger than 4.
- * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7}
- * For packet-size smaller or equal to 4, this boils down to a noop.
- */
-template<typename Packet> EIGEN_DEVICE_FUNC inline
-typename conditional<(unpacket_traits<Packet>::size%8)==0,typename unpacket_traits<Packet>::half,Packet>::type
-predux_half_dowto4(const Packet& a)
-{ return a; }
-
-/** \internal \returns the product of the elements of \a a */
-template<typename Packet> EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type predux_mul(const Packet& a)
-{ return a; }
-
-/** \internal \returns the min of the elements of \a a */
-template<typename Packet> EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type predux_min(const Packet& a)
-{ return a; }
-
-/** \internal \returns the max of the elements of \a a */
-template<typename Packet> EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type predux_max(const Packet& a)
-{ return a; }
-
-/** \internal \returns true if all coeffs of \a a means "true"
- * It is supposed to be called on values returned by pcmp_*.
- */
-// not needed yet
-// template<typename Packet> EIGEN_DEVICE_FUNC inline bool predux_all(const Packet& a)
-// { return bool(a); }
-
-/** \internal \returns true if any coeffs of \a a means "true"
- * It is supposed to be called on values returned by pcmp_*.
- */
-template<typename Packet> EIGEN_DEVICE_FUNC inline bool predux_any(const Packet& a)
-{
- // Dirty but generic implementation where "true" is assumed to be non 0 and all the sames.
- // It is expected that "true" is either:
- // - Scalar(1)
- // - bits full of ones (NaN for floats),
- // - or first bit equals to 1 (1 for ints, smallest denormal for floats).
- // For all these cases, taking the sum is just fine, and this boils down to a no-op for scalars.
- typedef typename unpacket_traits<Packet>::type Scalar;
- return numext::not_equal_strict(predux(a), Scalar(0));
-}
-
/** \internal \returns the reversed elements of \a a*/
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet preverse(const Packet& a)
{ return a; }
@@ -656,53 +653,104 @@ Packet print(const Packet& a) { using numext::rint; return rint(a); }
template<typename Packet> EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS
Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); }
+/** \internal \returns the first element of a packet */
+template<typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+pfirst(const Packet& a)
+{ return a; }
-/** \internal \returns the max of \a a and \a b (coeff-wise)
- If both \a a and \a b are NaN, NaN is returned.
- Equivalent to std::fmax(a, b). */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pfmax(const Packet& a, const Packet& b) {
- Packet not_nan_mask_a = pcmp_eq(a, a);
- Packet not_nan_mask_b = pcmp_eq(b, b);
- return pselect(not_nan_mask_a,
- pselect(not_nan_mask_b, pmax(a, b), a),
- b);
+/** \internal \returns the sum of the elements of upper and lower half of \a a if \a a is larger than 4.
+ * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7}
+ * For packet-size smaller or equal to 4, this boils down to a noop.
+ */
+template<typename Packet>
+EIGEN_DEVICE_FUNC inline typename conditional<(unpacket_traits<Packet>::size%8)==0,typename unpacket_traits<Packet>::half,Packet>::type
+predux_half_dowto4(const Packet& a)
+{ return a; }
+
+// Slow generic implementation of Packet reduction.
+template <typename Packet, typename Op>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux_helper(const Packet& a, Op op) {
+ typedef typename unpacket_traits<Packet>::type Scalar;
+ const size_t n = unpacket_traits<Packet>::size;
+ Scalar elements[n];
+ pstoreu<Scalar>(elements, a);
+ for(size_t k = n / 2; k > 0; k /= 2) {
+ for(size_t i = 0; i < k; ++i) {
+ elements[i] = op(elements[i], elements[i + k]);
+ }
+ }
+ return elements[0];
}
-/** \internal \returns the min of \a a and \a b (coeff-wise)
- If both \a a and \a b are NaN, NaN is returned.
- Equivalent to std::fmin(a, b). */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pfmin(const Packet& a, const Packet& b) {
- Packet not_nan_mask_a = pcmp_eq(a, a);
- Packet not_nan_mask_b = pcmp_eq(b, b);
- return pselect(not_nan_mask_a,
- pselect(not_nan_mask_b, pmin(a, b), a),
- b);
+/** \internal \returns the sum of the elements of \a a*/
+template<typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux(const Packet& a)
+{
+ return predux_helper(a, padd<typename unpacket_traits<Packet>::type>);
}
-/** \internal \returns the max of \a a and \a b (coeff-wise)
- If either \a a or \a b are NaN, NaN is returned. */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pfmax_nan(const Packet& a, const Packet& b) {
- Packet not_nan_mask_a = pcmp_eq(a, a);
- Packet not_nan_mask_b = pcmp_eq(b, b);
- return pselect(not_nan_mask_a,
- pselect(not_nan_mask_b, pmax(a, b), b),
- a);
+/** \internal \returns the product of the elements of \a a */
+template<typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux_mul(const Packet& a)
+{
+ return predux_helper(a, pmul<typename unpacket_traits<Packet>::type>);
}
-/** \internal \returns the min of \a a and \a b (coeff-wise)
- If either \a a or \a b are NaN, NaN is returned. */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
-pfmin_nan(const Packet& a, const Packet& b) {
- Packet not_nan_mask_a = pcmp_eq(a, a);
- Packet not_nan_mask_b = pcmp_eq(b, b);
- return pselect(not_nan_mask_a,
- pselect(not_nan_mask_b, pmin(a, b), b),
- a);
+/** \internal \returns the min of the elements of \a a */
+template<typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux_min(const Packet& a)
+{
+ return predux_helper(a, pmin<PropagateFast, typename unpacket_traits<Packet>::type>);
}
+template<int NaNPropagation, typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux_min(const Packet& a)
+{
+ return predux_helper(a, pmin<NaNPropagation, typename unpacket_traits<Packet>::type>);
+}
+
+/** \internal \returns the max of the elements of \a a */
+template<typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux_max(const Packet& a)
+{
+ return predux_helper(a, pmax<PropagateFast, typename unpacket_traits<Packet>::type>);
+}
+
+template<int NaNPropagation, typename Packet>
+EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
+predux_max(const Packet& a)
+{
+ return predux_helper(a, pmax<NaNPropagation, typename unpacket_traits<Packet>::type>);
+}
+
+/** \internal \returns true if all coeffs of \a a means "true"
+ * It is supposed to be called on values returned by pcmp_*.
+ */
+// not needed yet
+// template<typename Packet> EIGEN_DEVICE_FUNC inline bool predux_all(const Packet& a)
+// { return bool(a); }
+
+/** \internal \returns true if any coeffs of \a a means "true"
+ * It is supposed to be called on values returned by pcmp_*.
+ */
+template<typename Packet> EIGEN_DEVICE_FUNC inline bool predux_any(const Packet& a)
+{
+ // Dirty but generic implementation where "true" is assumed to be non 0 and all the sames.
+ // It is expected that "true" is either:
+ // - Scalar(1)
+ // - bits full of ones (NaN for floats),
+ // - or first bit equals to 1 (1 for ints, smallest denormal for floats).
+ // For all these cases, taking the sum is just fine, and this boils down to a no-op for scalars.
+ typedef typename unpacket_traits<Packet>::type Scalar;
+ return numext::not_equal_strict(predux(a), Scalar(0));
+}
/***************************************************************************
* The following functions might not have to be overwritten for vectorized types
diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h
index 55650bb8d..f3509c4b9 100644
--- a/Eigen/src/Core/functors/BinaryFunctors.h
+++ b/Eigen/src/Core/functors/BinaryFunctors.h
@@ -140,29 +140,18 @@ struct scalar_min_op : binary_op_base<LhsScalar,RhsScalar>
typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_min_op>::ReturnType result_type;
EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const {
- if (NaNPropagation == PropagateFast) {
- return numext::mini(a, b);
- } else if (NaNPropagation == PropagateNumbers) {
- return internal::pfmin(a,b);
- } else if (NaNPropagation == PropagateNaN) {
- return internal::pfmin_nan(a,b);
- }
+ return internal::pmin<NaNPropagation>(a, b);
}
template<typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
{
- if (NaNPropagation == PropagateFast) {
- return internal::pmin(a,b);
- } else if (NaNPropagation == PropagateNumbers) {
- return internal::pfmin(a,b);
- } else if (NaNPropagation == PropagateNaN) {
- return internal::pfmin_nan(a,b);
- }
+ return internal::pmin<NaNPropagation>(a,b);
}
- // TODO(rmlarsen): Handle all NaN propagation semantics reductions.
template<typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
- { return internal::predux_min(a); }
+ {
+ return internal::predux_min<NaNPropagation>(a);
+ }
};
template<typename LhsScalar,typename RhsScalar, int NaNPropagation>
@@ -184,29 +173,18 @@ struct scalar_max_op : binary_op_base<LhsScalar,RhsScalar>
typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar,scalar_max_op>::ReturnType result_type;
EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const {
- if (NaNPropagation == PropagateFast) {
- return numext::maxi(a, b);
- } else if (NaNPropagation == PropagateNumbers) {
- return internal::pfmax(a,b);
- } else if (NaNPropagation == PropagateNaN) {
- return internal::pfmax_nan(a,b);
- }
+ return internal::pmax<NaNPropagation>(a,b);
}
template<typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
{
- if (NaNPropagation == PropagateFast) {
- return internal::pmax(a,b);
- } else if (NaNPropagation == PropagateNumbers) {
- return internal::pfmax(a,b);
- } else if (NaNPropagation == PropagateNaN) {
- return internal::pfmax_nan(a,b);
- }
+ return internal::pmax<NaNPropagation>(a,b);
}
- // TODO(rmlarsen): Handle all NaN propagation semantics reductions.
template<typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
- { return internal::predux_max(a); }
+ {
+ return internal::predux_max<NaNPropagation>(a);
+ }
};
template<typename LhsScalar,typename RhsScalar, int NaNPropagation>
diff --git a/test/packetmath.cpp b/test/packetmath.cpp
index 53c41c967..c6a1648ba 100644
--- a/test/packetmath.cpp
+++ b/test/packetmath.cpp
@@ -801,10 +801,6 @@ void packetmath_notcomplex() {
Array<Scalar, Dynamic, 1>::Map(data1, PacketSize * 4).setRandom();
- ref[0] = data1[0];
- for (int i = 0; i < PacketSize; ++i) ref[0] = (std::min)(ref[0], data1[i]);
- VERIFY(internal::isApprox(ref[0], internal::predux_min(internal::pload<Packet>(data1))) && "internal::predux_min");
-
VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasMin);
VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasMax);
@@ -817,13 +813,16 @@ void packetmath_notcomplex() {
using ::fmin;
using ::fmax;
#endif
- CHECK_CWISE2_IF(PacketTraits::HasMin, fmin, internal::pfmin);
- CHECK_CWISE2_IF(PacketTraits::HasMax, fmax, internal::pfmax);
+ CHECK_CWISE2_IF(PacketTraits::HasMin, fmin, (internal::pmin<PropagateNumbers>));
+ CHECK_CWISE2_IF(PacketTraits::HasMax, fmax, internal::pmax<PropagateNumbers>);
CHECK_CWISE1(numext::abs, internal::pabs);
CHECK_CWISE2_IF(PacketTraits::HasAbsDiff, REF_ABS_DIFF, internal::pabsdiff);
ref[0] = data1[0];
- for (int i = 0; i < PacketSize; ++i) ref[0] = (std::max)(ref[0], data1[i]);
+ for (int i = 0; i < PacketSize; ++i) ref[0] = internal::pmin(ref[0], data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_min(internal::pload<Packet>(data1))) && "internal::predux_min");
+ ref[0] = data1[0];
+ for (int i = 0; i < PacketSize; ++i) ref[0] = internal::pmax(ref[0], data1[i]);
VERIFY(internal::isApprox(ref[0], internal::predux_max(internal::pload<Packet>(data1))) && "internal::predux_max");
for (int i = 0; i < PacketSize; ++i) ref[i] = data1[0] + Scalar(i);
@@ -852,16 +851,47 @@ void packetmath_notcomplex() {
}
}
- for (int i = 0; i < PacketSize; ++i) {
- data1[i] = internal::random<bool>() ? std::numeric_limits<Scalar>::quiet_NaN() : Scalar(0);
- data1[i + PacketSize] = internal::random<bool>() ? std::numeric_limits<Scalar>::quiet_NaN() : Scalar(0);
+
+ // Test NaN propagation.
+ if (!NumTraits<Scalar>::IsInteger) {
+ // Test reductions with no NaNs.
+ ref[0] = data1[0];
+ for (int i = 0; i < PacketSize; ++i) ref[0] = internal::pmin<PropagateNumbers>(ref[0], data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_min<PropagateNumbers>(internal::pload<Packet>(data1))) && "internal::predux_min<PropagateNumbers>");
+ ref[0] = data1[0];
+ for (int i = 0; i < PacketSize; ++i) ref[0] = internal::pmin<PropagateNaN>(ref[0], data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_min<PropagateNaN>(internal::pload<Packet>(data1))) && "internal::predux_min<PropagateNaN>");
+ ref[0] = data1[0];
+ for (int i = 0; i < PacketSize; ++i) ref[0] = internal::pmax<PropagateNumbers>(ref[0], data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_max<PropagateNumbers>(internal::pload<Packet>(data1))) && "internal::predux_max<PropagateNumbers>");
+ ref[0] = data1[0];
+ for (int i = 0; i < PacketSize; ++i) ref[0] = internal::pmax<PropagateNaN>(ref[0], data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_max<PropagateNaN>(internal::pload<Packet>(data1))) && "internal::predux_max<PropagateNumbers>");
+ // A single NaN.
+ const size_t index = std::numeric_limits<size_t>::quiet_NaN() % PacketSize;
+ data1[index] = std::numeric_limits<Scalar>::quiet_NaN();
+ VERIFY(PacketSize==1 || !(numext::isnan)(internal::predux_min<PropagateNumbers>(internal::pload<Packet>(data1))));
+ VERIFY((numext::isnan)(internal::predux_min<PropagateNaN>(internal::pload<Packet>(data1))));
+ VERIFY(PacketSize==1 || !(numext::isnan)(internal::predux_max<PropagateNumbers>(internal::pload<Packet>(data1))));
+ VERIFY((numext::isnan)(internal::predux_max<PropagateNaN>(internal::pload<Packet>(data1))));
+ // All NaNs.
+ for (int i = 0; i < 4 * PacketSize; ++i) data1[i] = std::numeric_limits<Scalar>::quiet_NaN();
+ VERIFY((numext::isnan)(internal::predux_min<PropagateNumbers>(internal::pload<Packet>(data1))));
+ VERIFY((numext::isnan)(internal::predux_min<PropagateNaN>(internal::pload<Packet>(data1))));
+ VERIFY((numext::isnan)(internal::predux_max<PropagateNumbers>(internal::pload<Packet>(data1))));
+ VERIFY((numext::isnan)(internal::predux_max<PropagateNaN>(internal::pload<Packet>(data1))));
+
+ // Test NaN propagation for coefficient-wise min and max.
+ for (int i = 0; i < PacketSize; ++i) {
+ data1[i] = internal::random<bool>() ? std::numeric_limits<Scalar>::quiet_NaN() : Scalar(0);
+ data1[i + PacketSize] = internal::random<bool>() ? std::numeric_limits<Scalar>::quiet_NaN() : Scalar(0);
+ }
+ // Note: NaN propagation is implementation defined for pmin/pmax, so we do not test it here.
+ CHECK_CWISE2_IF(PacketTraits::HasMin, fmin, (internal::pmin<PropagateNumbers>));
+ CHECK_CWISE2_IF(PacketTraits::HasMax, fmax, internal::pmax<PropagateNumbers>);
+ CHECK_CWISE2_IF(PacketTraits::HasMin, propagate_nan_min, (internal::pmin<PropagateNaN>));
+ CHECK_CWISE2_IF(PacketTraits::HasMax, propagate_nan_max, internal::pmax<PropagateNaN>);
}
- // Test NaN propagation for pfmin and pfmax. It should be equivalent to std::fmin.
- // Note: NaN propagation is implementation defined for pmin/pmax, so we do not test it here.
- CHECK_CWISE2_IF(PacketTraits::HasMin, fmin, internal::pfmin);
- CHECK_CWISE2_IF(PacketTraits::HasMax, fmax, internal::pfmax);
- CHECK_CWISE2_IF(PacketTraits::HasMin, propagate_nan_min, internal::pfmin_nan);
- CHECK_CWISE2_IF(PacketTraits::HasMax, propagate_nan_max, internal::pfmax_nan);
}
template <>
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h b/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h
index ef332dd19..3a70d8517 100644
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h
+++ b/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h
@@ -682,28 +682,30 @@ class TensorBase<Derived, ReadOnlyAccessors>
return TensorReductionOp<internal::ProdReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::ProdReducer<CoeffReturnType>());
}
- template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
- const TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const Dims, const Derived>
+ template <typename Dims,int NanPropagation=PropagateFast> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
+ const TensorReductionOp<internal::MaxReducer<CoeffReturnType,NanPropagation>, const Dims, const Derived>
maximum(const Dims& dims) const {
- return TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::MaxReducer<CoeffReturnType>());
+ return TensorReductionOp<internal::MaxReducer<CoeffReturnType,NanPropagation>, const Dims, const Derived>(derived(), dims, internal::MaxReducer<CoeffReturnType,NanPropagation>());
}
- const TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
+ template <int NanPropagation=PropagateFast>
+ const TensorReductionOp<internal::MaxReducer<CoeffReturnType,NanPropagation>, const DimensionList<Index, NumDimensions>, const Derived>
maximum() const {
DimensionList<Index, NumDimensions> in_dims;
- return TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MaxReducer<CoeffReturnType>());
+ return TensorReductionOp<internal::MaxReducer<CoeffReturnType,NanPropagation>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MaxReducer<CoeffReturnType,NanPropagation>());
}
- template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
- const TensorReductionOp<internal::MinReducer<CoeffReturnType>, const Dims, const Derived>
+ template <typename Dims,int NanPropagation=PropagateFast> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
+ const TensorReductionOp<internal::MinReducer<CoeffReturnType,NanPropagation>, const Dims, const Derived>
minimum(const Dims& dims) const {
- return TensorReductionOp<internal::MinReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::MinReducer<CoeffReturnType>());
+ return TensorReductionOp<internal::MinReducer<CoeffReturnType,NanPropagation>, const Dims, const Derived>(derived(), dims, internal::MinReducer<CoeffReturnType,NanPropagation>());
}
- const TensorReductionOp<internal::MinReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
+ template <int NanPropagation=PropagateFast>
+ const TensorReductionOp<internal::MinReducer<CoeffReturnType,NanPropagation>, const DimensionList<Index, NumDimensions>, const Derived>
minimum() const {
DimensionList<Index, NumDimensions> in_dims;
- return TensorReductionOp<internal::MinReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MinReducer<CoeffReturnType>());
+ return TensorReductionOp<internal::MinReducer<CoeffReturnType,NanPropagation>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MinReducer<CoeffReturnType,NanPropagation>());
}
template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h b/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h
index 2edc45f1a..fd8fa00fa 100644
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h
+++ b/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h
@@ -192,17 +192,19 @@ struct MinMaxBottomValue<T, false, false> {
};
-template <typename T> struct MaxReducer
+template <typename T, int NaNPropagation=PropagateFast> struct MaxReducer
{
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
- if (t > *accum) { *accum = t; }
+ scalar_max_op<T, T, NaNPropagation> op;
+ *accum = op(t, *accum);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
- (*accum) = pmax<Packet>(*accum, p);
+ scalar_max_op<T, T, NaNPropagation> op;
+ (*accum) = op.packetOp(*accum, p);
}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
- return MinMaxBottomValue<T, true, Eigen::NumTraits<T>::IsInteger>::bottom_value();
+ return MinMaxBottomValue<T, /*IsMax=*/true, Eigen::NumTraits<T>::IsInteger>::bottom_value();
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
@@ -217,32 +219,34 @@ template <typename T> struct MaxReducer
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
- return numext::maxi(saccum, predux_max(vaccum));
+ scalar_max_op<T, T, NaNPropagation> op;
+ return op(saccum, op.predux(vaccum));
}
};
-template <typename T, typename Device>
-struct reducer_traits<MaxReducer<T>, Device> {
+template <typename T, typename Device, int NaNPropagation>
+ struct reducer_traits<MaxReducer<T, NaNPropagation>, Device> {
enum {
Cost = NumTraits<T>::AddCost,
PacketAccess = PacketType<T, Device>::HasMax,
IsStateful = false,
- IsExactlyAssociative = true
+ IsExactlyAssociative = (NaNPropagation!=PropagateFast)
};
};
-
-template <typename T> struct MinReducer
+template <typename T, int NaNPropagation=PropagateFast> struct MinReducer
{
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
- if (t < *accum) { *accum = t; }
+ scalar_min_op<T, T, NaNPropagation> op;
+ *accum = op(t, *accum);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
- (*accum) = pmin<Packet>(*accum, p);
+ scalar_min_op<T, T, NaNPropagation> op;
+ (*accum) = op.packetOp(*accum, p);
}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
- return MinMaxBottomValue<T, false, Eigen::NumTraits<T>::IsInteger>::bottom_value();
+ return MinMaxBottomValue<T, /*IsMax=*/false, Eigen::NumTraits<T>::IsInteger>::bottom_value();
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
@@ -257,21 +261,21 @@ template <typename T> struct MinReducer
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
- return numext::mini(saccum, predux_min(vaccum));
+ scalar_min_op<T, T, NaNPropagation> op;
+ return op(saccum, op.predux(vaccum));
}
};
-template <typename T, typename Device>
-struct reducer_traits<MinReducer<T>, Device> {
+template <typename T, typename Device, int NaNPropagation>
+ struct reducer_traits<MinReducer<T, NaNPropagation>, Device> {
enum {
Cost = NumTraits<T>::AddCost,
PacketAccess = PacketType<T, Device>::HasMin,
IsStateful = false,
- IsExactlyAssociative = true
+ IsExactlyAssociative = (NaNPropagation!=PropagateFast)
};
};
-
template <typename T> struct ProdReducer
{
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
@@ -282,7 +286,6 @@ template <typename T> struct ProdReducer
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
(*accum) = pmul<Packet>(*accum, p);
}
-
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
internal::scalar_cast_op<int, T> conv;
return conv(1);
diff --git a/unsupported/test/cxx11_tensor_expr.cpp b/unsupported/test/cxx11_tensor_expr.cpp
index 7fac3b4ed..556d01d4d 100644
--- a/unsupported/test/cxx11_tensor_expr.cpp
+++ b/unsupported/test/cxx11_tensor_expr.cpp
@@ -302,12 +302,17 @@ static void test_select()
template <typename Scalar>
void test_minmax_nan_propagation_templ() {
for (int size = 1; size < 17; ++size) {
- const Scalar kNan = std::numeric_limits<Scalar>::quiet_NaN();
+ std::cout << "size = " << size << std::endl;
+ const Scalar kNaN = std::numeric_limits<Scalar>::quiet_NaN();
+ const Scalar kInf = std::numeric_limits<Scalar>::infinity();
const Scalar kZero(0);
- Tensor<Scalar, 1> vec_nan(size);
+ Tensor<Scalar, 1> vec_all_nan(size);
+ Tensor<Scalar, 1> vec_one_nan(size);
Tensor<Scalar, 1> vec_zero(size);
- vec_nan.setConstant(kNan);
+ vec_all_nan.setConstant(kNaN);
vec_zero.setZero();
+ vec_one_nan.setZero();
+ vec_one_nan(size/2) = kNaN;
auto verify_all_nan = [&](const Tensor<Scalar, 1>& v) {
for (int i = 0; i < size; ++i) {
@@ -326,12 +331,12 @@ void test_minmax_nan_propagation_templ() {
// max(nan, 0) = nan
// max(0, nan) = nan
// max(0, 0) = 0
- verify_all_nan(vec_nan.template cwiseMax<PropagateNaN>(kNan));
- verify_all_nan(vec_nan.template cwiseMax<PropagateNaN>(vec_nan));
- verify_all_nan(vec_nan.template cwiseMax<PropagateNaN>(kZero));
- verify_all_nan(vec_nan.template cwiseMax<PropagateNaN>(vec_zero));
- verify_all_nan(vec_zero.template cwiseMax<PropagateNaN>(kNan));
- verify_all_nan(vec_zero.template cwiseMax<PropagateNaN>(vec_nan));
+ verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(kNaN));
+ verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(vec_all_nan));
+ verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(kZero));
+ verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(vec_zero));
+ verify_all_nan(vec_zero.template cwiseMax<PropagateNaN>(kNaN));
+ verify_all_nan(vec_zero.template cwiseMax<PropagateNaN>(vec_all_nan));
verify_all_zero(vec_zero.template cwiseMax<PropagateNaN>(kZero));
verify_all_zero(vec_zero.template cwiseMax<PropagateNaN>(vec_zero));
@@ -340,12 +345,12 @@ void test_minmax_nan_propagation_templ() {
// max(nan, 0) = 0
// max(0, nan) = 0
// max(0, 0) = 0
- verify_all_nan(vec_nan.template cwiseMax<PropagateNumbers>(kNan));
- verify_all_nan(vec_nan.template cwiseMax<PropagateNumbers>(vec_nan));
- verify_all_zero(vec_nan.template cwiseMax<PropagateNumbers>(kZero));
- verify_all_zero(vec_nan.template cwiseMax<PropagateNumbers>(vec_zero));
- verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(kNan));
- verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(vec_nan));
+ verify_all_nan(vec_all_nan.template cwiseMax<PropagateNumbers>(kNaN));
+ verify_all_nan(vec_all_nan.template cwiseMax<PropagateNumbers>(vec_all_nan));
+ verify_all_zero(vec_all_nan.template cwiseMax<PropagateNumbers>(kZero));
+ verify_all_zero(vec_all_nan.template cwiseMax<PropagateNumbers>(vec_zero));
+ verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(kNaN));
+ verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(vec_all_nan));
verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(kZero));
verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(vec_zero));
@@ -354,12 +359,12 @@ void test_minmax_nan_propagation_templ() {
// min(nan, 0) = nan
// min(0, nan) = nan
// min(0, 0) = 0
- verify_all_nan(vec_nan.template cwiseMin<PropagateNaN>(kNan));
- verify_all_nan(vec_nan.template cwiseMin<PropagateNaN>(vec_nan));
- verify_all_nan(vec_nan.template cwiseMin<PropagateNaN>(kZero));
- verify_all_nan(vec_nan.template cwiseMin<PropagateNaN>(vec_zero));
- verify_all_nan(vec_zero.template cwiseMin<PropagateNaN>(kNan));
- verify_all_nan(vec_zero.template cwiseMin<PropagateNaN>(vec_nan));
+ verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(kNaN));
+ verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(vec_all_nan));
+ verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(kZero));
+ verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(vec_zero));
+ verify_all_nan(vec_zero.template cwiseMin<PropagateNaN>(kNaN));
+ verify_all_nan(vec_zero.template cwiseMin<PropagateNaN>(vec_all_nan));
verify_all_zero(vec_zero.template cwiseMin<PropagateNaN>(kZero));
verify_all_zero(vec_zero.template cwiseMin<PropagateNaN>(vec_zero));
@@ -368,14 +373,49 @@ void test_minmax_nan_propagation_templ() {
// min(nan, 0) = 0
// min(0, nan) = 0
// min(0, 0) = 0
- verify_all_nan(vec_nan.template cwiseMin<PropagateNumbers>(kNan));
- verify_all_nan(vec_nan.template cwiseMin<PropagateNumbers>(vec_nan));
- verify_all_zero(vec_nan.template cwiseMin<PropagateNumbers>(kZero));
- verify_all_zero(vec_nan.template cwiseMin<PropagateNumbers>(vec_zero));
- verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(kNan));
- verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(vec_nan));
+ verify_all_nan(vec_all_nan.template cwiseMin<PropagateNumbers>(kNaN));
+ verify_all_nan(vec_all_nan.template cwiseMin<PropagateNumbers>(vec_all_nan));
+ verify_all_zero(vec_all_nan.template cwiseMin<PropagateNumbers>(kZero));
+ verify_all_zero(vec_all_nan.template cwiseMin<PropagateNumbers>(vec_zero));
+ verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(kNaN));
+ verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(vec_all_nan));
verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(kZero));
verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(vec_zero));
+
+ // Test min and max reduction
+ Tensor<Scalar, 0> val;
+ val = vec_zero.minimum();
+ VERIFY_IS_EQUAL(val(), kZero);
+ val = vec_zero.template minimum<PropagateNaN>();
+ VERIFY_IS_EQUAL(val(), kZero);
+ val = vec_zero.template minimum<PropagateNumbers>();
+ VERIFY_IS_EQUAL(val(), kZero);
+ val = vec_zero.maximum();
+ VERIFY_IS_EQUAL(val(), kZero);
+ val = vec_zero.template maximum<PropagateNaN>();
+ VERIFY_IS_EQUAL(val(), kZero);
+ val = vec_zero.template maximum<PropagateNumbers>();
+ VERIFY_IS_EQUAL(val(), kZero);
+
+ // Test NaN propagation for tensor of all NaNs.
+ val = vec_all_nan.template minimum<PropagateNaN>();
+ VERIFY((numext::isnan)(val()));
+ val = vec_all_nan.template minimum<PropagateNumbers>();
+ VERIFY_IS_EQUAL(val(), kInf);
+ val = vec_all_nan.template maximum<PropagateNaN>();
+ VERIFY((numext::isnan)(val()));
+ val = vec_all_nan.template maximum<PropagateNumbers>();
+ VERIFY_IS_EQUAL(val(), -kInf);
+
+ // Test NaN propagation for tensor with a single NaN.
+ val = vec_one_nan.template minimum<PropagateNaN>();
+ VERIFY((numext::isnan)(val()));
+ val = vec_one_nan.template minimum<PropagateNumbers>();
+ VERIFY_IS_EQUAL(val(), (size == 1 ? kInf : kZero));
+ val = vec_one_nan.template maximum<PropagateNaN>();
+ VERIFY((numext::isnan)(val()));
+ val = vec_one_nan.template maximum<PropagateNumbers>();
+ VERIFY_IS_EQUAL(val(), (size == 1 ? -kInf : kZero));
}
}