Add typed logicals
Reference issue
What does this implement/fix?
Typed (i.e. not necessarily bool) logical operators enable full vectorization without casting to bool, which may be particularly useful for nested logical expressions, comparisons (once typed comparisons are enabled), and other boolean reductions.
This MR generalizes the boolean logical ops:
-
scalar_boolean_and_op/&& -
scalar_boolean_or_op/|| scalar_boolean_xor_op-
scalar_boolean_not_op/!
to operate on any Scalar as if they were boolean.
This is implemented in the following manner: for any scalar T a, a is false if a == T(0). For floating types, -0.0 will also evaluate to false. Conversely, a is true if a != T(0). This allows any type, including complex types and non-standard scalars, to be evaluated as if they were booleans. Vectorized comparison ops typically return bitmasks comprised of all 1's for true, which is problematic if the scalar is a floating point type as all 1's corresponds to nan. This may lead to non-intuitive results, as nan != nan.
Note: C++ doesn't have a dedicated boolean xor operator. The functional equivalent is !=, which is reserved for generic inequality. Otherwise, 12.182384 != -0.283383 would evaluate to false, which would be confusing.
New ops for bitwise logical operations and corresponding overloads for Eigen types are provided:
-
scalar_bitwise_and_op/& -
scalar_bitwise_or_op/| -
scalar_bitwise_xor_op/^ -
scalar_bitwise_not_op/~
Currently, the sparse and tensor binary ops are hard coded to bool as I am less familiar with those uses. If someone could point me to a potentially breaking scenario that involves typed logicals, I can look into it.
Previously, ^ corresponded to scalar_boolean_xor_op, but now it corresponds to scalar_bitiwse_xor_op. However, the previous implementation effectively computed a bitwise xor, so this shouldn't be a problem.