diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index bcfd0f611..91cfe3171 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -567,18 +567,28 @@ template class DenseBase static const RandomReturnType Random(Index size); static const RandomReturnType Random(); - template - inline EIGEN_DEVICE_FUNC const Select - select(const DenseBase& thenMatrix, - const DenseBase& elseMatrix) const; + template + inline EIGEN_DEVICE_FUNC + CwiseTernaryOp::Scalar, + typename DenseBase::Scalar>, + Derived, ThenDerived, ElseDerived> + select(const DenseBase& thenMatrix, const DenseBase& elseMatrix) const; - template - inline EIGEN_DEVICE_FUNC const Select - select(const DenseBase& thenMatrix, const typename ThenDerived::Scalar& elseScalar) const; + template + inline EIGEN_DEVICE_FUNC + CwiseTernaryOp::Scalar, + typename DenseBase::Scalar>, + Derived, ThenDerived, typename DenseBase::ConstantReturnType> + select(const DenseBase& thenMatrix, + const typename DenseBase::Scalar& elseScalar) const; - template - inline EIGEN_DEVICE_FUNC const Select - select(const typename ElseDerived::Scalar& thenScalar, const DenseBase& elseMatrix) const; + template + inline EIGEN_DEVICE_FUNC + CwiseTernaryOp::Scalar, + typename DenseBase::Scalar>, + Derived, typename DenseBase::ConstantReturnType, ElseDerived> + select(const typename DenseBase::Scalar& thenScalar, + const DenseBase& elseMatrix) const; template RealScalar lpNorm() const; diff --git a/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h index b16b2dad2..1842b4763 100644 --- a/Eigen/src/Core/Fuzzy.h +++ b/Eigen/src/Core/Fuzzy.h @@ -26,7 +26,7 @@ struct isApprox_selector { typename internal::nested_eval::type nested(x); typename internal::nested_eval::type otherNested(y); - return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); + return (nested.matrix() - otherNested.matrix()).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; diff --git a/Eigen/src/Core/Select.h b/Eigen/src/Core/Select.h index d9ed2b213..1fe388efc 100644 --- a/Eigen/src/Core/Select.h +++ b/Eigen/src/Core/Select.h @@ -113,52 +113,63 @@ class Select : public internal::dense_xpr_base< Select -template -inline EIGEN_DEVICE_FUNC const Select -DenseBase::select(const DenseBase& thenMatrix, - const DenseBase& elseMatrix) const -{ - return Select(derived(), thenMatrix.derived(), elseMatrix.derived()); + * if \c *this(i,j) != Scalar(0), and \a elseMatrix(i,j) otherwise. + * + * Example: \include MatrixBase_select.cpp + * Output: \verbinclude MatrixBase_select.out + * + * \sa DenseBase::bitwiseSelect(const DenseBase&, const DenseBase&) + */ +template +template +inline EIGEN_DEVICE_FUNC CwiseTernaryOp< + internal::scalar_boolean_select_op::Scalar, typename DenseBase::Scalar, + typename DenseBase::Scalar>, + Derived, ThenDerived, ElseDerived> +DenseBase::select(const DenseBase& thenMatrix, const DenseBase& elseMatrix) const { + using Op = internal::scalar_boolean_select_op::Scalar, + typename DenseBase::Scalar>; + return CwiseTernaryOp(derived(), thenMatrix.derived(), elseMatrix.derived(), + Op()); } - /** Version of DenseBase::select(const DenseBase&, const DenseBase&) with - * the \em else expression being a scalar value. - * - * \sa DenseBase::select(const DenseBase&, const DenseBase&) const, class Select - */ -template -template -inline EIGEN_DEVICE_FUNC const Select + * the \em else expression being a scalar value. + * + * \sa DenseBase::booleanSelect(const DenseBase&, const DenseBase&) const, class Select + */ +template +template +inline EIGEN_DEVICE_FUNC CwiseTernaryOp< + internal::scalar_boolean_select_op::Scalar, typename DenseBase::Scalar, + typename DenseBase::Scalar>, + Derived, ThenDerived, typename DenseBase::ConstantReturnType> DenseBase::select(const DenseBase& thenMatrix, - const typename ThenDerived::Scalar& elseScalar) const -{ - return Select( - derived(), thenMatrix.derived(), ThenDerived::Constant(rows(),cols(),elseScalar)); + const typename DenseBase::Scalar& elseScalar) const { + using ElseConstantType = typename DenseBase::ConstantReturnType; + using Op = internal::scalar_boolean_select_op::Scalar, + typename DenseBase::Scalar>; + return CwiseTernaryOp(derived(), thenMatrix.derived(), + ElseConstantType(rows(), cols(), elseScalar), Op()); } - /** Version of DenseBase::select(const DenseBase&, const DenseBase&) with - * the \em then expression being a scalar value. - * - * \sa DenseBase::select(const DenseBase&, const DenseBase&) const, class Select - */ -template -template -inline EIGEN_DEVICE_FUNC const Select -DenseBase::select(const typename ElseDerived::Scalar& thenScalar, - const DenseBase& elseMatrix) const -{ - return Select( - derived(), ElseDerived::Constant(rows(),cols(),thenScalar), elseMatrix.derived()); + * the \em then expression being a scalar value. + * + * \sa DenseBase::booleanSelect(const DenseBase&, const DenseBase&) const, class Select + */ +template +template +inline EIGEN_DEVICE_FUNC CwiseTernaryOp< + internal::scalar_boolean_select_op::Scalar, typename DenseBase::Scalar, + typename DenseBase::Scalar>, + Derived, typename DenseBase::ConstantReturnType, ElseDerived> +DenseBase::select(const typename DenseBase::Scalar& thenScalar, + const DenseBase& elseMatrix) const { + using ThenConstantType = typename DenseBase::ConstantReturnType; + using Op = internal::scalar_boolean_select_op::Scalar, + typename DenseBase::Scalar>; + return CwiseTernaryOp( + derived(), ThenConstantType(rows(), cols(), thenScalar), elseMatrix.derived(), Op()); } } // end namespace Eigen diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index abfa0fa60..faf41f52f 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -191,91 +191,122 @@ struct functor_traits > { }; /** \internal - * \brief Template functors for comparison of two scalars - * \todo Implement packet-comparisons - */ -template struct scalar_cmp_op; + * \brief Template functors for comparison of two scalars + * \todo Implement packet-comparisons + */ +template +struct scalar_cmp_op; -template -struct functor_traits > { +template +struct functor_traits> { enum { - Cost = (NumTraits::AddCost+NumTraits::AddCost)/2, - PacketAccess = is_same::value && - packet_traits::HasCmp && - // Since return type is bool, we currently require the inputs - // to be bool to enable packet access. - is_same::value + Cost = (NumTraits::AddCost + NumTraits::AddCost) / 2, + PacketAccess = (UseTypedComparators || is_same::value) && is_same::value && + packet_traits::HasCmp }; }; -template -struct result_of(LhsScalar,RhsScalar)> { - typedef bool type; +template +struct typed_cmp_helper { + static constexpr bool SameType = is_same::value; + static constexpr bool IsNumeric = is_arithmetic::Real>::value; + static constexpr bool UseTyped = UseTypedComparators && SameType && IsNumeric; + using type = typename conditional::type; }; +template +using cmp_return_t = typename typed_cmp_helper::type; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a==b;} - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_eq(a,b); } +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return a == b ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pand(pcmp_eq(a, b), cst_one); + } }; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_lt(a,b); } + +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return a < b ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pand(pcmp_lt(a, b), cst_one); + } }; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a<=b;} - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_le(a,b); } + +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return a <= b ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pand(cst_one, pcmp_le(a, b)); + } }; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a>b;} - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_lt(b,a); } + +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return a > b ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pand(cst_one, pcmp_lt(b, a)); + } }; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a>=b;} - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_le(b,a); } + +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return a >= b ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pand(cst_one, pcmp_le(b, a)); + } }; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return !(a<=b || b<=a);} - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_eq(internal::por(internal::pcmp_le(a, b), internal::pcmp_le(b, a)), internal::pzero(a)); } + +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return !(a <= b || b <= a) ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pandnot(cst_one, por(pcmp_le(a, b), pcmp_le(b, a))); + } }; -template -struct scalar_cmp_op : binary_op_base -{ - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const {return a!=b;} - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pcmp_eq(internal::pcmp_eq(a, b), internal::pzero(a)); } + +template +struct scalar_cmp_op : binary_op_base { + using result_type = cmp_return_t; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const { + return a != b ? result_type(1) : result_type(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(result_type(1)); + return pandnot(cst_one, pcmp_eq(a, b)); + } }; /** \internal @@ -511,6 +542,50 @@ struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; +template ::IsComplex> +struct bitwise_binary_impl { + static constexpr size_t Size = sizeof(Scalar); + using uint_t = typename numext::get_integer_by_size::unsigned_type; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) { + uint_t a_as_uint = numext::bit_cast(a); + uint_t b_as_uint = numext::bit_cast(b); + uint_t result = a_as_uint & b_as_uint; + return numext::bit_cast(result); + } + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) { + uint_t a_as_uint = numext::bit_cast(a); + uint_t b_as_uint = numext::bit_cast(b); + uint_t result = a_as_uint | b_as_uint; + return numext::bit_cast(result); + } + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) { + uint_t a_as_uint = numext::bit_cast(a); + uint_t b_as_uint = numext::bit_cast(b); + uint_t result = a_as_uint ^ b_as_uint; + return numext::bit_cast(result); + } +}; + +template +struct bitwise_binary_impl { + using Real = typename NumTraits::Real; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_and(const Scalar& a, const Scalar& b) { + Real real_result = bitwise_binary_impl::run_and(numext::real(a), numext::real(b)); + Real imag_result = bitwise_binary_impl::run_and(numext::imag(a), numext::imag(b)); + return Scalar(real_result, imag_result); + } + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_or(const Scalar& a, const Scalar& b) { + Real real_result = bitwise_binary_impl::run_or(numext::real(a), numext::real(b)); + Real imag_result = bitwise_binary_impl::run_or(numext::imag(a), numext::imag(b)); + return Scalar(real_result, imag_result); + } + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_xor(const Scalar& a, const Scalar& b) { + Real real_result = bitwise_binary_impl::run_xor(numext::real(a), numext::real(b)); + Real imag_result = bitwise_binary_impl::run_xor(numext::imag(a), numext::imag(b)); + return Scalar(real_result, imag_result); + } +}; + /** \internal * \brief Template functor to compute the bitwise and of two scalars * @@ -518,15 +593,12 @@ struct functor_traits> { */ template struct scalar_bitwise_and_op { - EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES ) + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, + BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) + EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { - Scalar result; - const uint8_t* a_bytes = reinterpret_cast(&a); - const uint8_t* b_bytes = reinterpret_cast(&b); - uint8_t* r_bytes = reinterpret_cast(&result); - for (Index i = 0; i < sizeof(Scalar); i++) r_bytes[i] = a_bytes[i] & b_bytes[i]; - return result; + return bitwise_binary_impl::run_and(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { @@ -545,15 +617,12 @@ struct functor_traits> { */ template struct scalar_bitwise_or_op { - EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, + BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) + EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { - Scalar result; - const uint8_t* a_bytes = reinterpret_cast(&a); - const uint8_t* b_bytes = reinterpret_cast(&b); - uint8_t* r_bytes = reinterpret_cast(&result); - for (Index i = 0; i < sizeof(Scalar); i++) r_bytes[i] = a_bytes[i] | b_bytes[i]; - return result; + return bitwise_binary_impl::run_or(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { @@ -572,15 +641,12 @@ struct functor_traits> { */ template struct scalar_bitwise_xor_op { - EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, + BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) + EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { - Scalar result; - const uint8_t* a_bytes = reinterpret_cast(&a); - const uint8_t* b_bytes = reinterpret_cast(&b); - uint8_t* r_bytes = reinterpret_cast(&result); - for (Index i = 0; i < sizeof(Scalar); i++) r_bytes[i] = a_bytes[i] ^ b_bytes[i]; - return result; + return bitwise_binary_impl::run_xor(a, b); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { diff --git a/Eigen/src/Core/functors/TernaryFunctors.h b/Eigen/src/Core/functors/TernaryFunctors.h index 41c0d5ff7..9aadc271d 100644 --- a/Eigen/src/Core/functors/TernaryFunctors.h +++ b/Eigen/src/Core/functors/TernaryFunctors.h @@ -18,7 +18,30 @@ namespace internal { //---------- associative ternary functors ---------- +template +struct scalar_boolean_select_op { + static constexpr bool ThenElseAreSame = is_same::value; + EIGEN_STATIC_ASSERT(ThenElseAreSame, THEN AND ELSE MUST BE SAME TYPE) + using Scalar = ThenScalar; + using result_type = Scalar; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const ConditionScalar& cond, const ThenScalar& a, + const ElseScalar& b) const { + return cond == ConditionScalar(0) ? b : a; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& cond, const Packet& a, const Packet& b) const { + return pselect(pcmp_eq(cond, pzero(cond)), b, a); + } +}; +template +struct functor_traits> { + using Scalar = ThenScalar; + enum { + Cost = 1, + PacketAccess = is_same::value && is_same::value && packet_traits::HasCmp + }; +}; } // end namespace internal diff --git a/Eigen/src/Core/functors/UnaryFunctors.h b/Eigen/src/Core/functors/UnaryFunctors.h index 1faed10bf..e909f13f8 100644 --- a/Eigen/src/Core/functors/UnaryFunctors.h +++ b/Eigen/src/Core/functors/UnaryFunctors.h @@ -178,6 +178,13 @@ struct scalar_cast_op { typedef NewType result_type; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } }; + +template +struct scalar_cast_op { + typedef bool result_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& a) const { return a != Scalar(0); } +}; + template struct functor_traits > { enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; @@ -942,6 +949,27 @@ struct functor_traits> { enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; +template ::IsComplex> +struct bitwise_unary_impl { + static constexpr size_t Size = sizeof(Scalar); + using uint_t = typename numext::get_integer_by_size::unsigned_type; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_not(const Scalar& a) { + uint_t a_as_uint = numext::bit_cast(a); + uint_t result = ~a_as_uint; + return numext::bit_cast(result); + } +}; + +template +struct bitwise_unary_impl { + using Real = typename NumTraits::Real; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_not(const Scalar& a) { + Real real_result = bitwise_unary_impl::run_not(numext::real(a)); + Real imag_result = bitwise_unary_impl::run_not(numext::imag(a)); + return Scalar(real_result, imag_result); + } +}; + /** \internal * \brief Template functor to compute the bitwise not of a scalar * @@ -950,13 +978,10 @@ struct functor_traits> { template struct scalar_bitwise_not_op { EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA TYPES) + EIGEN_STATIC_ASSERT((!internal::is_same::value), DONT USE BITWISE OPS ON BOOLEAN TYPES) using result_type = Scalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const { - Scalar result; - const uint8_t* a_bytes = reinterpret_cast(&a); - uint8_t* r_bytes = reinterpret_cast(&result); - for (Index i = 0; i < sizeof(Scalar); i++) r_bytes[i] = ~a_bytes[i]; - return result; + return bitwise_unary_impl::run_not(a); } template EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { diff --git a/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/Eigen/src/plugins/MatrixCwiseBinaryOps.h index 5aed0f8d0..53dac96de 100644 --- a/Eigen/src/plugins/MatrixCwiseBinaryOps.h +++ b/Eigen/src/plugins/MatrixCwiseBinaryOps.h @@ -39,10 +39,10 @@ cwiseProduct(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const */ template EIGEN_DEVICE_FUNC -inline const CwiseBinaryOp, const Derived, const OtherDerived> +inline const CwiseBinaryOp, const Derived, const OtherDerived> cwiseEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } /** \returns an expression of the coefficient-wise != operator of *this and \a other @@ -59,10 +59,46 @@ cwiseEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const */ template EIGEN_DEVICE_FUNC -inline const CwiseBinaryOp, const Derived, const OtherDerived> +inline const CwiseBinaryOp, const Derived, const OtherDerived> cwiseNotEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const { - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); +} + +/** \returns an expression of the coefficient-wise < operator of *this and \a other */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp, const Derived, const OtherDerived> +cwiseLesser(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const +{ + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); +} + +/** \returns an expression of the coefficient-wise > operator of *this and \a other */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp, const Derived, const OtherDerived> +cwiseGreater(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const +{ + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); +} + +/** \returns an expression of the coefficient-wise <= operator of *this and \a other */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp, const Derived, const OtherDerived> +cwiseLesserOrEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const +{ + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); +} + +/** \returns an expression of the coefficient-wise >= operator of *this and \a other */ +template +EIGEN_DEVICE_FUNC +inline const CwiseBinaryOp, const Derived, const OtherDerived> +cwiseGreaterOrEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const +{ + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } /** \returns an expression of the coefficient-wise min of *this and \a other @@ -135,7 +171,12 @@ cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } -typedef CwiseBinaryOp, const Derived, const ConstantReturnType> CwiseScalarEqualReturnType; +using CwiseScalarEqualReturnType = CwiseBinaryOp, const Derived, const ConstantReturnType>; +using CwiseScalarNotEqualReturnType = CwiseBinaryOp, const Derived, const ConstantReturnType>; +using CwiseScalarLesserReturnType = CwiseBinaryOp, const Derived, const ConstantReturnType>; +using CwiseScalarGreaterReturnType = CwiseBinaryOp, const Derived, const ConstantReturnType>; +using CwiseScalarLesserOrEqualReturnType = CwiseBinaryOp, const Derived, const ConstantReturnType>; +using CwiseScalarGreaterOrEqualReturnType = CwiseBinaryOp, const Derived, const ConstantReturnType>; /** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s * @@ -152,3 +193,54 @@ cwiseEqual(const Scalar& s) const { return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); } + + +/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s + * + * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. + * In order to check for equality between two vectors or matrices with floating-point coefficients, it is + * generally a far better idea to use a fuzzy comparison as provided by isApprox() and + * isMuchSmallerThan(). + * + * \sa cwiseEqual(const MatrixBase &) const + */ +EIGEN_DEVICE_FUNC +inline const CwiseScalarNotEqualReturnType +cwiseNotEqual(const Scalar& s) const +{ + return CwiseScalarNotEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} + +/** \returns an expression of the coefficient-wise < operator of \c *this and a scalar \a s */ +EIGEN_DEVICE_FUNC +inline const CwiseScalarLesserReturnType +cwiseLesser(const Scalar& s) const +{ + return CwiseScalarLesserReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} + +/** \returns an expression of the coefficient-wise > operator of \c *this and a scalar \a s */ +EIGEN_DEVICE_FUNC +inline const CwiseScalarGreaterReturnType +cwiseGreater(const Scalar& s) const +{ + return CwiseScalarGreaterReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} + +/** \returns an expression of the coefficient-wise <= operator of \c *this and a scalar \a s */ +EIGEN_DEVICE_FUNC +inline const CwiseScalarLesserOrEqualReturnType +cwiseLesserOrEqual(const Scalar& s) const +{ + return CwiseScalarLesserOrEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} + +/** \returns an expression of the coefficient-wise >= operator of \c *this and a scalar \a s */ +EIGEN_DEVICE_FUNC +inline const CwiseScalarGreaterOrEqualReturnType +cwiseGreaterOrEqual(const Scalar& s) const +{ + return CwiseScalarGreaterOrEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op()); +} + + diff --git a/test/array_cwise.cpp b/test/array_cwise.cpp index 44a6a503e..81ee57280 100644 --- a/test/array_cwise.cpp +++ b/test/array_cwise.cpp @@ -590,6 +590,21 @@ template void comparisons(const ArrayType& m) typedef typename ArrayType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; + // explicitly test both typed and boolean comparison ops + using typed_eq = internal::scalar_cmp_op; + using typed_ne = internal::scalar_cmp_op; + using typed_lt = internal::scalar_cmp_op; + using typed_le = internal::scalar_cmp_op; + using typed_gt = internal::scalar_cmp_op; + using typed_ge = internal::scalar_cmp_op; + + using bool_eq = internal::scalar_cmp_op; + using bool_ne = internal::scalar_cmp_op; + using bool_lt = internal::scalar_cmp_op; + using bool_le = internal::scalar_cmp_op; + using bool_gt = internal::scalar_cmp_op; + using bool_ge = internal::scalar_cmp_op; + Index rows = m.rows(); Index cols = m.cols(); @@ -603,6 +618,8 @@ template void comparisons(const ArrayType& m) m4 = (m4.abs()==Scalar(0)).select(1,m4); + // use operator overloads with default return type + VERIFY(((m1 + Scalar(1)) > m1).all()); VERIFY(((m1 - Scalar(1)) < m1).all()); if (rows*cols>1) @@ -627,6 +644,34 @@ template void comparisons(const ArrayType& m) VERIFY( ( (m1(r,c)+1) > m1).any() ); VERIFY( ( m1(r,c) == m1).any() ); + // currently, any() / all() are not vectorized, so use VERIFY_IS_CWISE_EQUAL to test vectorized path + + // use typed comparisons, regardless of operator overload behavior + typename ArrayType::ConstantReturnType typed_true = ArrayType::Constant(rows, cols, Scalar(1)); + // (m1 + Scalar(1)) > m1).all() + VERIFY_IS_CWISE_EQUAL((m1 + Scalar(1)).binaryExpr(m1, typed_gt()), typed_true); + // (m1 - Scalar(1)) < m1).all() + VERIFY_IS_CWISE_EQUAL((m1 - Scalar(1)).binaryExpr(m1, typed_lt()), typed_true); + // (m1 + Scalar(1)) == (m1 + Scalar(1))).all() + VERIFY_IS_CWISE_EQUAL((m1 + Scalar(1)).binaryExpr(m1 + Scalar(1), typed_eq()), typed_true); + // (m1 - Scalar(1)) != m1).all() + VERIFY_IS_CWISE_EQUAL((m1 - Scalar(1)).binaryExpr(m1, typed_ne()), typed_true); + // (m1 <= m2 || m1 >= m2).all() + VERIFY_IS_CWISE_EQUAL(m1.binaryExpr(m2, typed_le()) || m1.binaryExpr(m2, typed_ge()), typed_true); + + // use boolean comparisons, regardless of operator overload behavior + ArrayXX::ConstantReturnType bool_true = ArrayXX::Constant(rows, cols, true); + // (m1 + Scalar(1)) > m1).all() + VERIFY_IS_CWISE_EQUAL((m1 + Scalar(1)).binaryExpr(m1, bool_gt()), bool_true); + // (m1 - Scalar(1)) < m1).all() + VERIFY_IS_CWISE_EQUAL((m1 - Scalar(1)).binaryExpr(m1, bool_lt()), bool_true); + // (m1 + Scalar(1)) == (m1 + Scalar(1))).all() + VERIFY_IS_CWISE_EQUAL((m1 + Scalar(1)).binaryExpr(m1 + Scalar(1), bool_eq()), bool_true); + // (m1 - Scalar(1)) != m1).all() + VERIFY_IS_CWISE_EQUAL((m1 - Scalar(1)).binaryExpr(m1, bool_ne()), bool_true); + // (m1 <= m2 || m1 >= m2).all() + VERIFY_IS_CWISE_EQUAL(m1.binaryExpr(m2, bool_le()) || m1.binaryExpr(m2, bool_ge()), bool_true); + // test Select VERIFY_IS_APPROX( (m1m2).select(m1,m2), m1.cwiseMax(m2) ); @@ -642,7 +687,7 @@ template void comparisons(const ArrayType& m) VERIFY_IS_APPROX( (m1.abs()>=ArrayType::Constant(rows,cols,mid)) .select(m1,0), m3); // even shorter version: - VERIFY_IS_APPROX( (m1.abs()RealScalar(0.1)).count() == rows*cols); @@ -1039,7 +1084,7 @@ struct typed_logicals_test_impl { using Scalar = typename ArrayType::Scalar; static bool scalar_to_bool(const Scalar& x) { return x != Scalar(0); } - static Scalar bool_to_scalar(const bool& x) { return x ? Scalar(1) : Scalar(0); } + static Scalar bool_to_scalar(bool x) { return x ? Scalar(1) : Scalar(0); } static Scalar eval_bool_and(const Scalar& x, const Scalar& y) { return bool_to_scalar(scalar_to_bool(x) && scalar_to_bool(y)); } static Scalar eval_bool_or(const Scalar& x, const Scalar& y) { return bool_to_scalar(scalar_to_bool(x) || scalar_to_bool(y)); } @@ -1091,40 +1136,45 @@ struct typed_logicals_test_impl { m4 = (!m1).binaryExpr((!m2), internal::scalar_boolean_xor_op()); VERIFY_IS_CWISE_EQUAL(m3, m4); - const Index bytes = rows * cols * sizeof(Scalar); - const uint8_t* m1_data = reinterpret_cast(m1.data()); - const uint8_t* m2_data = reinterpret_cast(m2.data()); - uint8_t* m3_data = reinterpret_cast(m3.data()); - uint8_t* m4_data = reinterpret_cast(m4.data()); + const size_t bytes = size_t(rows) * size_t(cols) * sizeof(Scalar); + + std::vector m1_buffer(bytes), m2_buffer(bytes), m3_buffer(bytes), m4_buffer(bytes); + + std::memcpy(m1_buffer.data(), m1.data(), bytes); + std::memcpy(m2_buffer.data(), m2.data(), bytes); // test bitwise and m3 = m1 & m2; - for (Index i = 0; i < bytes; i++) m4_data[i] = m1_data[i] & m2_data[i]; - for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + std::memcpy(m3_buffer.data(), m3.data(), bytes); + for (size_t i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_buffer[i], uint8_t(m1_buffer[i] & m2_buffer[i])); // test bitwise or m3 = m1 | m2; - for (Index i = 0; i < bytes; i++) m4_data[i] = m1_data[i] | m2_data[i]; - for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + std::memcpy(m3_buffer.data(), m3.data(), bytes); + for (size_t i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_buffer[i], uint8_t(m1_buffer[i] | m2_buffer[i])); // test bitwise xor m3 = m1 ^ m2; - for (Index i = 0; i < bytes; i++) m4_data[i] = m1_data[i] ^ m2_data[i]; - for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + std::memcpy(m3_buffer.data(), m3.data(), bytes); + for (size_t i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_buffer[i], uint8_t(m1_buffer[i] ^ m2_buffer[i])); // test bitwise not m3 = ~m1; - for (Index i = 0; i < bytes; i++) m4_data[i] = ~m1_data[i]; - for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + std::memcpy(m3_buffer.data(), m3.data(), bytes); + for (size_t i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_buffer[i], uint8_t(~m1_buffer[i])); // test something more complicated m3 = m1 & m2; m4 = ~(~m1 | ~m2); - for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + std::memcpy(m3_buffer.data(), m3.data(), bytes); + std::memcpy(m4_buffer.data(), m4.data(), bytes); + for (size_t i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_buffer[i], m4_buffer[i]); m3 = m1 ^ m2; m4 = (~m1) ^ (~m2); - for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + std::memcpy(m3_buffer.data(), m3.data(), bytes); + std::memcpy(m4_buffer.data(), m4.data(), bytes); + for (size_t i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_buffer[i], m4_buffer[i]); } }; template @@ -1181,7 +1231,6 @@ EIGEN_DECLARE_TEST(array_cwise) CALL_SUBTEST_8( signbit_tests() ); } for (int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( typed_logicals_test(ArrayX(internal::random(1, EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_2( typed_logicals_test(ArrayX(internal::random(1, EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_2( typed_logicals_test(ArrayX(internal::random(1, EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_3( typed_logicals_test(ArrayX(internal::random(1, EIGEN_TEST_MAX_SIZE)))); diff --git a/test/main.h b/test/main.h index 853858173..99149ca4f 100644 --- a/test/main.h +++ b/test/main.h @@ -496,7 +496,7 @@ typename NumTraits::NonInteger test_relative_error(cons typedef typename NumTraits::NonInteger RealScalar; typename internal::nested_eval::type ea(a.derived()); typename internal::nested_eval::type eb(b.derived()); - return sqrt(RealScalar((ea-eb).cwiseAbs2().sum()) / RealScalar((std::min)(eb.cwiseAbs2().sum(),ea.cwiseAbs2().sum()))); + return sqrt(RealScalar((ea.matrix()-eb.matrix()).cwiseAbs2().sum()) / RealScalar((std::min)(eb.cwiseAbs2().sum(),ea.cwiseAbs2().sum()))); } template diff --git a/unsupported/test/cxx11_tensor_comparisons.cpp b/unsupported/test/cxx11_tensor_comparisons.cpp index 1a18e07cc..0c8df4f7c 100644 --- a/unsupported/test/cxx11_tensor_comparisons.cpp +++ b/unsupported/test/cxx11_tensor_comparisons.cpp @@ -14,14 +14,16 @@ using Eigen::Tensor; using Eigen::RowMajor; +using Scalar = float; + static void test_orderings() { - Tensor mat1(2,3,7); - Tensor mat2(2,3,7); - Tensor lt(2,3,7); - Tensor le(2,3,7); - Tensor gt(2,3,7); - Tensor ge(2,3,7); + Tensor mat1(2,3,7); + Tensor mat2(2,3,7); + Tensor lt(2,3,7); + Tensor le(2,3,7); + Tensor gt(2,3,7); + Tensor ge(2,3,7); mat1.setRandom(); mat2.setRandom(); @@ -46,8 +48,8 @@ static void test_orderings() static void test_equality() { - Tensor mat1(2,3,7); - Tensor mat2(2,3,7); + Tensor mat1(2,3,7); + Tensor mat2(2,3,7); mat1.setRandom(); mat2.setRandom(); @@ -61,8 +63,8 @@ static void test_equality() } } - Tensor eq(2,3,7); - Tensor ne(2,3,7); + Tensor eq(2,3,7); + Tensor ne(2,3,7); eq = (mat1 == mat2); ne = (mat1 != mat2); diff --git a/unsupported/test/cxx11_tensor_expr.cpp b/unsupported/test/cxx11_tensor_expr.cpp index ddc813242..f99c80a22 100644 --- a/unsupported/test/cxx11_tensor_expr.cpp +++ b/unsupported/test/cxx11_tensor_expr.cpp @@ -200,14 +200,14 @@ static void test_boolean() std::iota(vec.data(), vec.data() + kSize, 0); // Test ||. - Tensor bool1 = vec < vec.constant(1) || vec > vec.constant(4); + Tensor bool1 = (vec < vec.constant(1) || vec > vec.constant(4)).cast(); for (int i = 0; i < kSize; ++i) { bool expected = i < 1 || i > 4; VERIFY_IS_EQUAL(bool1[i], expected); } // Test &&, including cast of operand vec. - Tensor bool2 = vec.cast() && vec < vec.constant(4); + Tensor bool2 = vec.cast() && (vec < vec.constant(4)).cast(); for (int i = 0; i < kSize; ++i) { bool expected = bool(i) && i < 4; VERIFY_IS_EQUAL(bool2[i], expected); @@ -218,7 +218,7 @@ static void test_boolean() // CoeffReturnType is set to match Op return type of bool for Unary and Binary // Ops. Tensor bool3 = vec.cast() && bool2; - bool3 = vec < vec.constant(4) && bool2; + bool3 = (vec < vec.constant(4)).cast() && bool2; } static void test_functors()