From 049a144798910f51e4ec7e23b94bce7dec0252f6 Mon Sep 17 00:00:00 2001 From: Charles Schlosser Date: Sat, 18 Feb 2023 01:23:47 +0000 Subject: [PATCH] Add typed logicals --- Eigen/src/Core/BooleanRedux.h | 8 +- Eigen/src/Core/VectorwiseOp.h | 4 +- Eigen/src/Core/arch/SSE/PacketMath.h | 1 + Eigen/src/Core/functors/BinaryFunctors.h | 172 ++++++++++++++---- Eigen/src/Core/functors/UnaryFunctors.h | 53 +++++- Eigen/src/Core/util/ForwardDeclarations.h | 9 + Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 18 +- Eigen/src/plugins/ArrayCwiseBinaryOps.h | 19 -- Eigen/src/plugins/ArrayCwiseUnaryOps.h | 14 +- Eigen/src/plugins/CommonCwiseBinaryOps.h | 86 +++++---- doc/snippets/Cwise_boolean_xor.cpp | 2 - test/array_cwise.cpp | 108 ++++++++++- .../Eigen/CXX11/src/Tensor/TensorBase.h | 45 ++++- 13 files changed, 415 insertions(+), 124 deletions(-) delete mode 100644 doc/snippets/Cwise_boolean_xor.cpp diff --git a/Eigen/src/Core/BooleanRedux.h b/Eigen/src/Core/BooleanRedux.h index 20e5bd9ba..e7d1a348b 100644 --- a/Eigen/src/Core/BooleanRedux.h +++ b/Eigen/src/Core/BooleanRedux.h @@ -27,7 +27,7 @@ struct all_unroller EIGEN_DEVICE_FUNC static inline bool run(const Derived &mat) { - return all_unroller::run(mat) && mat.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i); + return all_unroller::run(mat) && mat.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i) != typename Derived::CoeffReturnType(0); } }; @@ -54,7 +54,7 @@ struct any_unroller EIGEN_DEVICE_FUNC static inline bool run(const Derived &mat) { - return any_unroller::run(mat) || mat.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i); + return any_unroller::run(mat) || mat.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i) != typename Derived::CoeffReturnType(0); } }; @@ -94,7 +94,7 @@ EIGEN_DEVICE_FUNC inline bool DenseBase::all() const { for(Index i = 0; i < derived().outerSize(); ++i) for(Index j = 0; j < derived().innerSize(); ++j) - if (!evaluator.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i)) return false; + if (evaluator.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i) == Scalar(0)) return false; return true; } } @@ -118,7 +118,7 @@ EIGEN_DEVICE_FUNC inline bool DenseBase::any() const { for(Index i = 0; i < derived().outerSize(); ++i) for(Index j = 0; j < derived().innerSize(); ++j) - if (evaluator.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i)) return true; + if (evaluator.coeff(IsRowMajor ? i : j, IsRowMajor ? j : i) != Scalar(0)) return true; return false; } } diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index 762cbfc3d..737df139a 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h @@ -350,8 +350,8 @@ template class VectorwiseOp typedef typename ReturnType::Type HypotNormReturnType; typedef typename ReturnType::Type SumReturnType; typedef EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(SumReturnType,Scalar,quotient) MeanReturnType; - typedef typename ReturnType::Type AllReturnType; - typedef typename ReturnType::Type AnyReturnType; + typedef typename ReturnType::Type AllReturnType; + typedef typename ReturnType::Type AnyReturnType; typedef PartialReduxExpr, Direction> CountReturnType; typedef typename ReturnType::Type ProdReturnType; typedef Reverse ConstReverseReturnType; diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index 434d0331e..62646a164 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -216,6 +216,7 @@ template<> struct packet_traits : default_packet_traits HasAdd = 1, HasSub = 1, + HasCmp = 1, // note -- only pcmp_eq is defined HasShift = 0, HasMul = 1, HasNegate = 1, diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index 1cd8c5d87..abfa0fa60 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -428,60 +428,168 @@ struct functor_traits > { }; }; - - /** \internal - * \brief Template functor to compute the and of two booleans + * \brief Template functor to compute the and of two scalars as if they were booleans * * \sa class CwiseBinaryOp, ArrayBase::operator&& */ +template struct scalar_boolean_and_op { - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pand(a,b); } + using result_type = Scalar; + // `false` any value `a` that satisfies `a == Scalar(0)` + // `true` is the complement of `false` + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { + return (a != Scalar(0)) && (b != Scalar(0)) ? Scalar(1) : Scalar(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(Scalar(1)); + // and(a,b) == !or(!a,!b) + Packet not_a = pcmp_eq(a, pzero(a)); + Packet not_b = pcmp_eq(b, pzero(b)); + Packet a_nand_b = por(not_a, not_b); + return pandnot(cst_one, a_nand_b); + } }; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = true - }; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; /** \internal - * \brief Template functor to compute the or of two booleans + * \brief Template functor to compute the or of two scalars as if they were booleans * * \sa class CwiseBinaryOp, ArrayBase::operator|| */ +template struct scalar_boolean_or_op { - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::por(a,b); } + using result_type = Scalar; + // `false` any value `a` that satisfies `a == Scalar(0)` + // `true` is the complement of `false` + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { + return (a != Scalar(0)) || (b != Scalar(0)) ? Scalar(1) : Scalar(0); + } + template + EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(Scalar(1)); + // if or(a,b) == 0, then a == 0 and b == 0 + // or(a,b) == !nor(a,b) + Packet a_nor_b = pcmp_eq(por(a, b), pzero(a)); + return pandnot(cst_one, a_nor_b); + } }; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = true - }; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; }; /** \internal - * \brief Template functor to compute the xor of two booleans + * \brief Template functor to compute the xor of two scalars as if they were booleans * * \sa class CwiseBinaryOp, ArrayBase::operator^ */ +template struct scalar_boolean_xor_op { - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a ^ b; } - template - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pxor(a,b); } + using result_type = Scalar; + // `false` any value `a` that satisfies `a == Scalar(0)` + // `true` is the complement of `false` + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a, const Scalar& b) const { + return (a != Scalar(0)) != (b != Scalar(0)) ? Scalar(1) : Scalar(0); + } + template + EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + const Packet cst_one = pset1(Scalar(1)); + // xor(a,b) == xor(!a,!b) + Packet not_a = pcmp_eq(a, pzero(a)); + Packet not_b = pcmp_eq(b, pzero(b)); + Packet a_xor_b = pxor(not_a, not_b); + return pand(cst_one, a_xor_b); + } }; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = true - }; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; +}; + +/** \internal + * \brief Template functor to compute the bitwise and of two scalars + * + * \sa class CwiseBinaryOp, ArrayBase::operator& + */ +template +struct scalar_bitwise_and_op { + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA 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; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + return pand(a, b); + } +}; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = true }; +}; + +/** \internal + * \brief Template functor to compute the bitwise or of two scalars + * + * \sa class CwiseBinaryOp, ArrayBase::operator| + */ +template +struct scalar_bitwise_or_op { + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA 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; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + return por(a, b); + } +}; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = true }; +}; + +/** \internal + * \brief Template functor to compute the bitwise xor of two scalars + * + * \sa class CwiseBinaryOp, ArrayBase::operator^ + */ +template +struct scalar_bitwise_xor_op { + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA 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; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const { + return pxor(a, b); + } +}; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = true }; }; /** \internal diff --git a/Eigen/src/Core/functors/UnaryFunctors.h b/Eigen/src/Core/functors/UnaryFunctors.h index a76d8d264..e518f982d 100644 --- a/Eigen/src/Core/functors/UnaryFunctors.h +++ b/Eigen/src/Core/functors/UnaryFunctors.h @@ -913,19 +913,54 @@ struct functor_traits > }; /** \internal - * \brief Template functor to compute the logical not of a boolean + * \brief Template functor to compute the logical not of a scalar as if it were a boolean * * \sa class CwiseUnaryOp, ArrayBase::operator! */ -template struct scalar_boolean_not_op { - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator() (const bool& a) const { return !a; } +template +struct scalar_boolean_not_op { + using result_type = Scalar; + // `false` any value `a` that satisfies `a == Scalar(0)` + // `true` is the complement of `false` + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const { + return a == Scalar(0) ? Scalar(1) : Scalar(0); + } + template + EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { + const Packet cst_one = pset1(Scalar(1)); + Packet not_a = pcmp_eq(a, pzero(a)); + return pand(not_a, cst_one); + } }; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasCmp }; +}; + +/** \internal + * \brief Template functor to compute the bitwise not of a scalar + * + * \sa class CwiseUnaryOp, ArrayBase::operator~ + */ +template +struct scalar_bitwise_not_op { + EIGEN_STATIC_ASSERT(!NumTraits::RequireInitialization, BITWISE OPERATIONS MAY ONLY BE PERFORMED ON PLAIN DATA 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; + } + template + EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { + return pandnot(ptrue(a), a); + } +}; +template +struct functor_traits> { + enum { Cost = NumTraits::AddCost, PacketAccess = true }; }; /** \internal diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index facb07447..a00b14914 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -210,6 +210,15 @@ struct scalar_unary_pow_op; template struct scalar_hypot_op; template struct scalar_product_op; template struct scalar_quotient_op; +// logical and bitwise operations +template struct scalar_boolean_and_op; +template struct scalar_boolean_or_op; +template struct scalar_boolean_xor_op; +template struct scalar_boolean_not_op; +template struct scalar_bitwise_and_op; +template struct scalar_bitwise_or_op; +template struct scalar_bitwise_xor_op; +template struct scalar_bitwise_not_op; // SpecialFunctions module template struct scalar_lgamma_op; diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index 17cdb8e5b..c579713ae 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -368,28 +368,28 @@ struct binary_evaluator, Lhs, Rhs>, Iter // "sparse && sparse" template -struct binary_evaluator, IteratorBased, IteratorBased> - : sparse_conjunction_evaluator > +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IteratorBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > { - typedef CwiseBinaryOp XprType; + typedef CwiseBinaryOp, Lhs, Rhs> XprType; typedef sparse_conjunction_evaluator Base; explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} }; // "dense && sparse" template -struct binary_evaluator, IndexBased, IteratorBased> - : sparse_conjunction_evaluator > +struct binary_evaluator, Lhs, Rhs>, IndexBased, IteratorBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > { - typedef CwiseBinaryOp XprType; + typedef CwiseBinaryOp, Lhs, Rhs> XprType; typedef sparse_conjunction_evaluator Base; explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} }; // "sparse && dense" template -struct binary_evaluator, IteratorBased, IndexBased> - : sparse_conjunction_evaluator > +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IndexBased> + : sparse_conjunction_evaluator, Lhs, Rhs> > { - typedef CwiseBinaryOp XprType; + typedef CwiseBinaryOp, Lhs, Rhs> XprType; typedef sparse_conjunction_evaluator Base; explicit binary_evaluator(const XprType& xpr) : Base(xpr) {} }; diff --git a/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 30e3ee107..35461da8b 100644 --- a/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -307,25 +307,6 @@ const CwiseBinaryOp,Constant,Derived operator/(const T& s,const StorageBaseType& a); #endif -/** \returns an expression of the coefficient-wise ^ operator of *this and \a other - * - * \warning this operator is for expression of bool only. - * - * Example: \include Cwise_boolean_xor.cpp - * Output: \verbinclude Cwise_boolean_xor.out - * - * \sa operator&&(), select() - */ -template -EIGEN_DEVICE_FUNC -inline const CwiseBinaryOp -operator^(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const -{ - EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), - THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); - return CwiseBinaryOp(derived(),other.derived()); -} - // NOTE disabled until we agree on argument order #if 0 /** \cpp11 \returns an expression of the coefficient-wise polygamma function. diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index 807a31325..301a900a1 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -9,6 +9,7 @@ typedef CwiseUnaryOp, const Derived> RsqrtRetu typedef CwiseUnaryOp, const Derived> SignReturnType; typedef CwiseUnaryOp, const Derived> InverseReturnType; typedef CwiseUnaryOp, const Derived> BooleanNotReturnType; +typedef CwiseUnaryOp, const Derived> BitwiseNotReturnType; typedef CwiseUnaryOp, const Derived> ExpReturnType; typedef CwiseUnaryOp, const Derived> Expm1ReturnType; @@ -580,8 +581,6 @@ isFinite() const } /** \returns an expression of the coefficient-wise ! operator of *this - * - * \warning this operator is for expression of bool only. * * Example: \include Cwise_boolean_not.cpp * Output: \verbinclude Cwise_boolean_not.out @@ -592,11 +591,18 @@ EIGEN_DEVICE_FUNC inline const BooleanNotReturnType operator!() const { - EIGEN_STATIC_ASSERT((internal::is_same::value), - THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); return BooleanNotReturnType(derived()); } +/** \returns an expression of the bitwise ~ operator of *this + */ +EIGEN_DEVICE_FUNC +inline const BitwiseNotReturnType +operator~() const +{ + return BitwiseNotReturnType(derived()); +} + // --- SpecialFunctions module --- diff --git a/Eigen/src/plugins/CommonCwiseBinaryOps.h b/Eigen/src/plugins/CommonCwiseBinaryOps.h index 2f503296f..26a8f0ce6 100644 --- a/Eigen/src/plugins/CommonCwiseBinaryOps.h +++ b/Eigen/src/plugins/CommonCwiseBinaryOps.h @@ -77,39 +77,61 @@ const CwiseBinaryOp,Derived,Constant > #endif /** \returns an expression of the coefficient-wise boolean \b and operator of \c *this and \a other - * - * \warning this operator is for expression of bool only. - * - * Example: \include Cwise_boolean_and.cpp - * Output: \verbinclude Cwise_boolean_and.out - * - * \sa operator||(), select() - */ -template -EIGEN_DEVICE_FUNC -inline const CwiseBinaryOp -operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const -{ - EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), - THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); - return CwiseBinaryOp(derived(),other.derived()); + * + * Example: \include Cwise_boolean_and.cpp + * Output: \verbinclude Cwise_boolean_and.out + * + * \sa operator||(), select() + */ +template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> +operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const { + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), + other.derived()); } /** \returns an expression of the coefficient-wise boolean \b or operator of \c *this and \a other - * - * \warning this operator is for expression of bool only. - * - * Example: \include Cwise_boolean_or.cpp - * Output: \verbinclude Cwise_boolean_or.out - * - * \sa operator&&(), select() - */ -template -EIGEN_DEVICE_FUNC -inline const CwiseBinaryOp -operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const -{ - EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), - THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); - return CwiseBinaryOp(derived(),other.derived()); + * + * Example: \include Cwise_boolean_or.cpp + * Output: \verbinclude Cwise_boolean_or.out + * + * \sa operator&&(), select() + */ +template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> +operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const { + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), + other.derived()); } + +/** \returns an expression of the bitwise \b and operator of \c *this and \a other + * + * \sa operator|(), operator^() + */ +template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> +operator&(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const { + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), + other.derived()); +} + +/** \returns an expression of the bitwise boolean \b or operator of \c *this and \a other + * + * \sa operator&(), operator^() + */ +template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> +operator|(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const { + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), + other.derived()); +} + +/** \returns an expression of the bitwise xor operator of *this and \a other + * \sa operator&(), operator|() + */ +template +EIGEN_DEVICE_FUNC inline const CwiseBinaryOp, const Derived, const OtherDerived> +operator^(const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) const { + return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), + other.derived()); +} \ No newline at end of file diff --git a/doc/snippets/Cwise_boolean_xor.cpp b/doc/snippets/Cwise_boolean_xor.cpp deleted file mode 100644 index fafbec806..000000000 --- a/doc/snippets/Cwise_boolean_xor.cpp +++ /dev/null @@ -1,2 +0,0 @@ -Array3d v(-1,2,1), w(-3,2,3); -cout << ((v special_values() { const Scalar two = Scalar(2); const Scalar three = Scalar(3); const Scalar sqrt_half = Scalar(std::sqrt(0.5)); - const Scalar sqrt2 = Scalar(std::sqrt(2)); + const Scalar sqrt2 = Scalar(std::sqrt(2)); const Scalar inf = Eigen::NumTraits::infinity(); const Scalar nan = Eigen::NumTraits::quiet_NaN(); const Scalar denorm_min = std::numeric_limits::denorm_min(); @@ -968,6 +968,104 @@ void signed_shift_test(const ArrayType& m) { signed_shift_test_impl::run(m); } +template +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 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)); } + static Scalar eval_bool_xor(const Scalar& x, const Scalar& y) { return bool_to_scalar(scalar_to_bool(x) != scalar_to_bool(y)); } + static Scalar eval_bool_not(const Scalar& x) { return bool_to_scalar(!scalar_to_bool(x)); } + + static void run(const ArrayType& m) { + + Index rows = m.rows(); + Index cols = m.cols(); + + ArrayType m1(rows, cols), m2(rows, cols), m3(rows, cols), m4(rows, cols); + + m1.setRandom(); + m2.setRandom(); + m1 *= ArrayX::Random(rows, cols).cast(); + m2 *= ArrayX::Random(rows, cols).cast(); + + // test boolean and + m3 = m1 && m2; + m4 = m1.binaryExpr(m2, [](const Scalar& x, const Scalar& y) { return eval_bool_and(x, y); }); + VERIFY_IS_CWISE_EQUAL(m3, m4); + for (const Scalar& val : m3) VERIFY(val == Scalar(0) || val == Scalar(1)); + + // test boolean or + m3 = m1 || m2; + m4 = m1.binaryExpr(m2, [](const Scalar& x, const Scalar& y) { return eval_bool_or(x, y); }); + VERIFY_IS_CWISE_EQUAL(m3, m4); + for (const Scalar& val : m3) VERIFY(val == Scalar(0) || val == Scalar(1)); + + // test boolean xor + m3 = m1.binaryExpr(m2, internal::scalar_boolean_xor_op()); + m4 = m1.binaryExpr(m2, [](const Scalar& x, const Scalar& y) { return eval_bool_xor(x, y); }); + VERIFY_IS_CWISE_EQUAL(m3, m4); + for (const Scalar& val : m3) VERIFY(val == Scalar(0) || val == Scalar(1)); + + // test boolean not + m3 = !m1; + m4 = m1.unaryExpr([](const Scalar& x) { return eval_bool_not(x); }); + VERIFY_IS_CWISE_EQUAL(m3, m4); + for (const Scalar& val : m3) VERIFY(val == Scalar(0) || val == Scalar(1)); + + // test something more complicated + m3 = m1 && m2; + m4 = !(!m1 || !m2); + VERIFY_IS_CWISE_EQUAL(m3, m4); + + m3 = m1.binaryExpr(m2, internal::scalar_boolean_xor_op()); + 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()); + + // 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]); + + // 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]); + + // 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]); + + // 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]); + + // 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]); + + m3 = m1 ^ m2; + m4 = (~m1) ^ (~m2); + for (Index i = 0; i < bytes; i++) VERIFY_IS_EQUAL(m3_data[i], m4_data[i]); + } +}; +template +void typed_logicals_test(const ArrayType& m) { + typed_logicals_test_impl::run(m); +} + EIGEN_DECLARE_TEST(array_cwise) { for(int i = 0; i < g_repeat; i++) { @@ -1016,6 +1114,14 @@ EIGEN_DECLARE_TEST(array_cwise) CALL_SUBTEST_7( mixed_pow_test() ); 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)))); + CALL_SUBTEST_3( 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)))); + } VERIFY((internal::is_same< internal::global_math_functions_filtering_base::type, int >::value)); VERIFY((internal::is_same< internal::global_math_functions_filtering_base::type, float >::value)); diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h b/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h index e3fc8f4fc..5e6cdb1ca 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h @@ -490,34 +490,59 @@ class TensorBase return binaryExpr(other.derived(), internal::scalar_quotient_op()); } - template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE - const TensorCwiseBinaryOp, const Derived, const OtherDerived> + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> cwiseMax(const OtherDerived& other) const { - return binaryExpr(other.derived(), internal::scalar_max_op()); + return binaryExpr(other.derived(), internal::scalar_max_op()); } - template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const OtherDerived> cwiseMin(const OtherDerived& other) const { return binaryExpr(other.derived(), internal::scalar_min_op()); } + // logical operators template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE - const TensorCwiseBinaryOp + const TensorCwiseBinaryOp, const Derived, const OtherDerived> operator&&(const OtherDerived& other) const { - return binaryExpr(other.derived(), internal::scalar_boolean_and_op()); + return binaryExpr(other.derived(), internal::scalar_boolean_and_op()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE - const TensorCwiseBinaryOp + const TensorCwiseBinaryOp, const Derived, const OtherDerived> operator||(const OtherDerived& other) const { - return binaryExpr(other.derived(), internal::scalar_boolean_or_op()); + return binaryExpr(other.derived(), internal::scalar_boolean_or_op()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE - const TensorCwiseBinaryOp + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator&(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_bitwise_and_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator|(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_bitwise_or_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> operator^(const OtherDerived& other) const { - return binaryExpr(other.derived(), internal::scalar_boolean_xor_op()); + return binaryExpr(other.derived(), internal::scalar_bitwise_xor_op()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseUnaryOp, const Derived> + operator!() const { + return unaryExpr(internal::scalar_boolean_not_op()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseUnaryOp, const Derived> + operator~() const { + return unaryExpr(internal::scalar_bitwise_not_op()); } // Comparisons and tests.