Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REVIEW] Bitwise binary ops AND, OR, XOR (&, |, ^) #1292

Merged
merged 12 commits into from
Mar 28, 2019
31 changes: 17 additions & 14 deletions cpp/include/cudf/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,20 +203,23 @@ typedef enum {
* @brief Types of binary operations that can be performed on data.
*/
typedef enum {
GDF_ADD, /**< operator + */
GDF_SUB, /**< operator - */
GDF_MUL, /**< operator * */
GDF_DIV, /**< operator / using common type of lhs and rhs */
GDF_TRUE_DIV, /**< operator / after promoting type to floating point*/
GDF_FLOOR_DIV, /**< operator / after promoting to float and then flooring the result */
GDF_MOD, /**< operator % */
GDF_POW, /**< lhs ^ rhs */
GDF_EQUAL, /**< operator == */
GDF_NOT_EQUAL, /**< operator != */
GDF_LESS, /**< operator < */
GDF_GREATER, /**< operator > */
GDF_LESS_EQUAL, /**< operator <= */
GDF_GREATER_EQUAL, /**< operator >= */
GDF_ADD, ///< operator +
GDF_SUB, ///< operator -
GDF_MUL, ///< operator *
GDF_DIV, ///< operator / using common type of lhs and rhs
GDF_TRUE_DIV, ///< operator / after promoting type to floating point
GDF_FLOOR_DIV, ///< operator / after promoting to float and then flooring the result
GDF_MOD, ///< operator %
GDF_POW, ///< lhs ^ rhs
GDF_EQUAL, ///< operator ==
GDF_NOT_EQUAL, ///< operator !=
GDF_LESS, ///< operator <
GDF_GREATER, ///< operator >
GDF_LESS_EQUAL, ///< operator <=
GDF_GREATER_EQUAL, ///< operator >=
GDF_BITWISE_AND, ///< operator &
GDF_BITWISE_OR, ///< operator |
GDF_BITWISE_XOR, ///< operator ^
GDF_COALESCE, ///< operator x,y x is null ? y : x
GDF_INVALID_BINARY ///< invalid operation
} gdf_binary_operator;
Expand Down
28 changes: 28 additions & 0 deletions cpp/src/binary/jit/code/operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,34 @@ R"***(
return (y >= x);
}
};

struct BitwiseAnd {
template <typename TypeOut, typename TypeLhs, typename TypeRhs>
static TypeOut operate(TypeLhs x, TypeRhs y) {
return (static_cast<TypeOut>(x) & static_cast<TypeOut>(y));
}
};

using RBitwiseAnd = BitwiseAnd;

struct BitwiseOr {
template <typename TypeOut, typename TypeLhs, typename TypeRhs>
static TypeOut operate(TypeLhs x, TypeRhs y) {
return (static_cast<TypeOut>(x) | static_cast<TypeOut>(y));
}
};

using RBitwiseOr = BitwiseOr;

struct BitwiseXor {
template <typename TypeOut, typename TypeLhs, typename TypeRhs>
static TypeOut operate(TypeLhs x, TypeRhs y) {
return (static_cast<TypeOut>(x) ^ static_cast<TypeOut>(y));
}
};

using RBitwiseXor = BitwiseXor;

)***";

} // namespace code
Expand Down
6 changes: 6 additions & 0 deletions cpp/src/binary/jit/util/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ namespace jit {
return "LessEqual";
case GDF_GREATER_EQUAL:
return "GreaterEqual";
case GDF_BITWISE_AND:
return "BitwiseAnd";
case GDF_BITWISE_OR:
return "BitwiseOr";
case GDF_BITWISE_XOR:
return "BitwiseXor";
default:
return "None";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,60 @@ TEST_F(BinaryOperationIntegrationTest, Pow_Vector_Vector_SI64) {
ASSERT_BINOP(out, lhs, rhs, POW());
}


TEST_F(BinaryOperationIntegrationTest, And_Vector_Vector_SI16_SI64_SI32) {
using AND = cudf::library::operation::BitwiseAnd<int16_t, int64_t, int32_t>;

auto lhs = cudf::test::column_wrapper<int16_t>{500,
[](gdf_size_type row) {return row;},
[](gdf_size_type row) {return (row % 6 > 0);}};
auto rhs = cudf::test::column_wrapper<int64_t>{500,
[](gdf_size_type row) {return 2;},
[](gdf_size_type row) {return (row % 4 > 0);}};
auto out = cudf::test::column_wrapper<int32_t>{lhs.get()->size, true};

auto result = gdf_binary_operation_v_v(out.get(), lhs.get(), rhs.get(), GDF_BITWISE_AND);
ASSERT_TRUE(result == GDF_SUCCESS);

ASSERT_BINOP(out, lhs, rhs, AND());
}


TEST_F(BinaryOperationIntegrationTest, Or_Vector_Vector_SI64_SI16_SI32) {
using OR = cudf::library::operation::BitwiseOr<int64_t, int16_t, int32_t>;

auto lhs = cudf::test::column_wrapper<int64_t>{500,
[](gdf_size_type row) {return row;},
[](gdf_size_type row) {return (row % 6 > 0);}};
auto rhs = cudf::test::column_wrapper<int16_t>{500,
[](gdf_size_type row) {return 2;},
[](gdf_size_type row) {return (row % 4 > 0);}};
auto out = cudf::test::column_wrapper<int32_t>{lhs.get()->size, true};

auto result = gdf_binary_operation_v_v(out.get(), lhs.get(), rhs.get(), GDF_BITWISE_OR);
ASSERT_TRUE(result == GDF_SUCCESS);

ASSERT_BINOP(out, lhs, rhs, OR());
}


TEST_F(BinaryOperationIntegrationTest, Xor_Vector_Vector_SI32_SI16_SI64) {
using XOR = cudf::library::operation::BitwiseXor<int32_t, int16_t, int64_t>;

auto lhs = cudf::test::column_wrapper<int32_t>{500,
[](gdf_size_type row) {return row;},
[](gdf_size_type row) {return (row % 6 > 0);}};
auto rhs = cudf::test::column_wrapper<int16_t>{500,
[](gdf_size_type row) {return 2;},
[](gdf_size_type row) {return (row % 4 > 0);}};
auto out = cudf::test::column_wrapper<int64_t>{lhs.get()->size, true};

auto result = gdf_binary_operation_v_v(out.get(), lhs.get(), rhs.get(), GDF_BITWISE_XOR);
ASSERT_TRUE(result == GDF_SUCCESS);

ASSERT_BINOP(out, lhs, rhs, XOR());
}

} // namespace binop
} // namespace test
} // namespace cudf
21 changes: 21 additions & 0 deletions cpp/tests/binary/util/operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,27 @@ namespace operation {
}
};

template <typename TypeOut, typename TypeLhs, typename TypeRhs>
struct BitwiseAnd {
TypeOut operator()(TypeLhs lhs, TypeRhs rhs) {
return (lhs & rhs);
}
};

template <typename TypeOut, typename TypeLhs, typename TypeRhs>
struct BitwiseOr {
TypeOut operator()(TypeLhs lhs, TypeRhs rhs) {
return (lhs | rhs);
}
};

template <typename TypeOut, typename TypeLhs, typename TypeRhs>
struct BitwiseXor {
TypeOut operator()(TypeLhs lhs, TypeRhs rhs) {
return (lhs ^ rhs);
}
};

} // namespace operation
} // namespace library
} // namespace cudf
Expand Down
3 changes: 3 additions & 0 deletions python/cudf/bindings/binops.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ _BINARY_OP['lt'] = GDF_LESS
_BINARY_OP['gt'] = GDF_GREATER
_BINARY_OP['le'] = GDF_LESS_EQUAL
_BINARY_OP['ge'] = GDF_GREATER_EQUAL
_BINARY_OP['and'] = GDF_BITWISE_AND
_BINARY_OP['or'] = GDF_BITWISE_OR
_BINARY_OP['xor'] = GDF_BITWISE_XOR


def apply_op(lhs, rhs, out, op):
Expand Down
5 changes: 4 additions & 1 deletion python/cudf/bindings/cudf_cpp.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ cdef extern from "cudf.h" nogil:
GDF_LESS,
GDF_GREATER,
GDF_LESS_EQUAL,
GDF_GREATER_EQUAL
GDF_GREATER_EQUAL,
GDF_BITWISE_AND,
GDF_BITWISE_OR,
GDF_BITWISE_XOR,


ctypedef struct gdf_scalar:
Expand Down
48 changes: 48 additions & 0 deletions python/cudf/dataframe/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,54 @@ def __rtruediv__(self, other):

__div__ = __truediv__

def __and__(self, other):
"""Performs vectorized bitwise and (&) on corresponding elements of two
series.

Difference from pandas:
Returned series has type np.result_type(lhs, rhs) instead of bool
devavret marked this conversation as resolved.
Show resolved Hide resolved
"""
if (np.issubdtype(self.dtype.type, np.integer) and
np.issubdtype(other.dtype.type, np.integer)):
return self._binaryop(other, 'and')
else:
raise TypeError(
"Operation & not supported between "
f"{self.dtype.type.__name__} and {other.dtype.type.__name__}"
)

def __or__(self, other):
"""Performs vectorized bitwise or (|) on corresponding elements of two
series.

Difference from pandas:
Returned series has type np.result_type(lhs, rhs) instead of bool
"""
if (np.issubdtype(self.dtype.type, np.integer) and
np.issubdtype(other.dtype.type, np.integer)):
return self._binaryop(other, 'or')
else:
raise TypeError(
"Operation | not supported between "
f"{self.dtype.type.__name__} and {other.dtype.type.__name__}"
)

def __xor__(self, other):
"""Performs vectorized bitwise xor (^) on corresponding elements of two
series.

Difference from pandas:
Returned series has type np.result_type(lhs, rhs) instead of bool
"""
if (np.issubdtype(self.dtype.type, np.integer) and
np.issubdtype(other.dtype.type, np.integer)):
return self._binaryop(other, 'xor')
else:
raise TypeError(
"Operation ^ not supported between "
f"{self.dtype.type.__name__} and {other.dtype.type.__name__}"
)

def _normalize_binop_value(self, other):
if isinstance(other, Series):
return other
Expand Down