Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,7 @@ add_library(
src/text/vocabulary_tokenize.cu
src/text/wordpiece_tokenize.cu
src/transform/bools_to_mask.cu
src/transform/checked_arithmetic.cu
src/transform/compute_column.cu
src/transform/compute_column_kernel_complex.cu
src/transform/compute_column_kernel_null_complex.cu
Expand Down
92 changes: 91 additions & 1 deletion cpp/include/cudf/binaryop.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ enum class binary_operator : int32_t {
///< operands are true, returns true; otherwise returns null
NULL_LOGICAL_OR, ///< three-valued (Kleene) ||: if any operand is true, returns true; if both
///< operands are false, returns false; otherwise returns null
INVALID_BINARY ///< invalid operation
INVALID_BINARY, ///< invalid operation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an expected invariant that INVALID_BINARY is the last item? Feels strange to have it in the middle.

ADD_OVERFLOW, ///< Addition with overflow detection
SUB_OVERFLOW, ///< Subtraction with overflow detection
MUL_OVERFLOW, ///< Multiplication with overflow detection
DIV_OVERFLOW, ///< Division with overflow and divide-by-zero detection
MOD_OVERFLOW ///< Modulo with divide-by-zero detection
};

/// Binary operation common type default
Expand Down Expand Up @@ -239,6 +244,91 @@ std::unique_ptr<column> binary_operation(
cuda::stream_ref stream = cudf::get_default_stream(),
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());

/**
* @brief Performs a checked binary operation between a scalar and a column.
*
* `PROPAGATE` throws `cudf::evaluation_error` when any row fails; `NULLIFY` makes failing rows
* null.
*
* @param lhs Left operand scalar
* @param rhs Right operand column
* @param op Checked binary operator
* @param output_type Desired output type
* @param policy Error handling policy
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned column
* @return Output column
* @throws cudf::evaluation_error if @p policy is `error_policy::PROPAGATE` and any row fails
* @throws cudf::logic_error if @p op is not a checked arithmetic operator
* @throws cudf::data_type_error if the input and output types do not match, are not supported
* arithmetic or fixed-point types, or @p output_type has an invalid fixed-point scale
*/
std::unique_ptr<column> binary_operation(
scalar const& lhs,
column_view const& rhs,
binary_operator op,
data_type output_type,
error_policy policy,
cuda::stream_ref stream = cudf::get_default_stream(),
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());
Comment thread
lamarrr marked this conversation as resolved.

/**
* @brief Performs a checked binary operation between a column and a scalar.
*
* `PROPAGATE` throws `cudf::evaluation_error` when any row fails; `NULLIFY` makes failing rows
* null.
*
* @param lhs Left operand column
* @param rhs Right operand scalar
* @param op Checked binary operator
* @param output_type Desired output type
* @param policy Error handling policy
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned column
* @return Output column
* @throws cudf::evaluation_error if @p policy is `error_policy::PROPAGATE` and any row fails
* @throws cudf::logic_error if @p op is not a checked arithmetic operator
* @throws cudf::data_type_error if the input and output types do not match, are not supported
* arithmetic or fixed-point types, or @p output_type has an invalid fixed-point scale
*/
std::unique_ptr<column> binary_operation(
column_view const& lhs,
scalar const& rhs,
binary_operator op,
data_type output_type,
error_policy policy,
cuda::stream_ref stream = cudf::get_default_stream(),
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());

/**
* @brief Performs a checked binary operation between two columns.
*
* `PROPAGATE` throws `cudf::evaluation_error` when any row fails; `NULLIFY` makes failing rows
* null.
*
* @param lhs Left operand column
* @param rhs Right operand column
* @param op Checked binary operator
* @param output_type Desired output type
* @param policy Error handling policy
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned column
* @return Output column
* @throws cudf::evaluation_error if @p policy is `error_policy::PROPAGATE` and any row fails
* @throws cudf::logic_error if @p op is not a checked arithmetic operator
* @throws cudf::data_type_error if the input and output types do not match, are not supported
* arithmetic or fixed-point types, or @p output_type has an invalid fixed-point scale
* @throws std::invalid_argument if @p lhs and @p rhs have different sizes
*/
std::unique_ptr<column> binary_operation(
column_view const& lhs,
column_view const& rhs,
binary_operator op,
data_type output_type,
error_policy policy,
cuda::stream_ref stream = cudf::get_default_stream(),
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());

/**
* @brief Performs a binary operation between two columns using a
* user-defined PTX function.
Expand Down
75 changes: 51 additions & 24 deletions cpp/include/cudf/unary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,40 @@ namespace CUDF_EXPORT cudf {
* @brief Types of unary operations that can be performed on data.
*/
enum class unary_operator : int32_t {
SIN, ///< Trigonometric sine
COS, ///< Trigonometric cosine
TAN, ///< Trigonometric tangent
ARCSIN, ///< Trigonometric sine inverse
ARCCOS, ///< Trigonometric cosine inverse
ARCTAN, ///< Trigonometric tangent inverse
SINH, ///< Hyperbolic sine
COSH, ///< Hyperbolic cosine
TANH, ///< Hyperbolic tangent
ARCSINH, ///< Hyperbolic sine inverse
ARCCOSH, ///< Hyperbolic cosine inverse
ARCTANH, ///< Hyperbolic tangent inverse
EXP, ///< Exponential (base e, Euler number)
LOG, ///< Natural Logarithm (base e)
SQRT, ///< Square-root (x^0.5)
CBRT, ///< Cube-root (x^(1.0/3))
CEIL, ///< Smallest integer value not less than arg
FLOOR, ///< largest integer value not greater than arg
ABS, ///< Absolute value
RINT, ///< Rounds the floating-point argument arg to an integer value
BIT_COUNT, ///< Count the number of bits set to 1 of an integer value
BIT_INVERT, ///< Bitwise Not (~)
NOT, ///< Logical Not (!)
NEGATE, ///< Unary negation (-), only for signed numeric and duration types.
SIN, ///< Trigonometric sine
COS, ///< Trigonometric cosine
TAN, ///< Trigonometric tangent
ARCSIN, ///< Trigonometric sine inverse
ARCCOS, ///< Trigonometric cosine inverse
ARCTAN, ///< Trigonometric tangent inverse
SINH, ///< Hyperbolic sine
COSH, ///< Hyperbolic cosine
TANH, ///< Hyperbolic tangent
ARCSINH, ///< Hyperbolic sine inverse
ARCCOSH, ///< Hyperbolic cosine inverse
ARCTANH, ///< Hyperbolic tangent inverse
EXP, ///< Exponential (base e, Euler number)
LOG, ///< Natural Logarithm (base e)
SQRT, ///< Square-root (x^0.5)
CBRT, ///< Cube-root (x^(1.0/3))
CEIL, ///< Smallest integer value not less than arg
FLOOR, ///< largest integer value not greater than arg
ABS, ///< Absolute value
RINT, ///< Rounds the floating-point argument arg to an integer value
BIT_COUNT, ///< Count the number of bits set to 1 of an integer value
BIT_INVERT, ///< Bitwise Not (~)
NOT, ///< Logical Not (!)
NEGATE, ///< Unary negation (-), only for signed numeric and duration types.
NEG_OVERFLOW, ///< Negation with overflow detection
ABS_OVERFLOW ///< Absolute value with overflow detection
};

/**
* @brief Performs unary op on all values in column
*
* Note: For `decimal32` and `decimal64`, only `ABS`, `CEIL` and `FLOOR` are supported.
* Checked operators use error_policy::PROPAGATE; use the policy-aware overload to nullify
* errors.
*
* @param input A `column_view` as input
* @param op operation to perform
Expand All @@ -74,6 +78,29 @@ std::unique_ptr<cudf::column> unary_operation(
cuda::stream_ref stream = cudf::get_default_stream(),
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());

/**
* @brief Performs a checked unary operation on all values in a column.
*
* `PROPAGATE` throws `cudf::evaluation_error` when any row fails; `NULLIFY` makes failing rows
* null.
*
* @param input Input column
* @param op Checked unary operator
* @param policy Error handling policy
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned column
* @return Output column
* @throws cudf::evaluation_error if @p policy is `error_policy::PROPAGATE` and any row fails
* @throws cudf::logic_error if @p op is not a checked arithmetic operator
* @throws cudf::data_type_error if @p input is not a supported arithmetic or fixed-point type
*/
std::unique_ptr<cudf::column> unary_operation(
cudf::column_view const& input,
cudf::unary_operator op,
cudf::error_policy policy,
cuda::stream_ref stream = cudf::get_default_stream(),
rmm::device_async_resource_ref mr = cudf::get_current_device_resource_ref());

/**
* @brief Creates a column of `type_id::BOOL8` elements where for every element in `input` `true`
* indicates the value is null and `false` indicates the value is valid.
Expand Down
86 changes: 74 additions & 12 deletions cpp/src/binaryop/binaryop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <cudf/detail/binaryop.hpp>
#include <cudf/detail/null_mask.hpp>
#include <cudf/detail/nvtx/ranges.hpp>
#include <cudf/replace.hpp>
#include <cudf/scalar/scalar.hpp>
#include <cudf/table/table_view.hpp>
#include <cudf/types.hpp>
Expand All @@ -42,13 +43,22 @@
#include <cuda/std/optional>
#include <cuda/stream>

#include <transform/checked_arithmetic.hpp>

#include <string>

namespace cudf {
namespace binops {

bool is_supported_operation(data_type out, data_type lhs, data_type rhs, binary_operator op)
{
if (cudf::detail::checked_arithmetic::is_checked(op)) {
if (out.id() != lhs.id() || lhs.id() != rhs.id()) { return false; }
if (is_fixed_point(lhs)) {
return out.scale() == binary_operation_fixed_point_scale(op, lhs.scale(), rhs.scale());
}
return is_numeric(lhs) && lhs.id() != type_id::BOOL8;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return cudf::binops::compiled::is_supported_operation(out, lhs, rhs, op);
}

Expand Down Expand Up @@ -89,15 +99,20 @@ inline bool is_null_dependent(binary_operator op)
*/
bool is_basic_arithmetic_binop(binary_operator op)
{
return op == binary_operator::ADD or // operator +
op == binary_operator::SUB or // operator -
op == binary_operator::MUL or // operator *
op == binary_operator::DIV or // operator / using common type of lhs and rhs
op == binary_operator::NULL_MIN or // 2 null = null, 1 null = value, else min
op == binary_operator::NULL_MAX or // 2 null = null, 1 null = value, else max
op == binary_operator::MOD or // operator %
op == binary_operator::PMOD or // positive modulo operator
op == binary_operator::PYMOD; // operator % but following Python's negative sign rules
return op == binary_operator::ADD or // operator +
op == binary_operator::SUB or // operator -
op == binary_operator::MUL or // operator *
op == binary_operator::DIV or // operator / using common type of lhs and rhs
op == binary_operator::NULL_MIN or // 2 null = null, 1 null = value, else min
op == binary_operator::NULL_MAX or // 2 null = null, 1 null = value, else max
op == binary_operator::MOD or // operator %
op == binary_operator::PMOD or // positive modulo operator
op == binary_operator::PYMOD || // Python modulo
op == binary_operator::ADD_OVERFLOW || // checked addition
op == binary_operator::SUB_OVERFLOW || // checked subtraction
op == binary_operator::MUL_OVERFLOW || // checked multiplication
op == binary_operator::DIV_OVERFLOW || // checked division
op == binary_operator::MOD_OVERFLOW; // checked modulo
}

/**
Expand Down Expand Up @@ -132,7 +147,8 @@ bool is_supported_fixed_point_binop(binary_operator op)
*/
bool is_same_scale_necessary(binary_operator op)
{
return op != binary_operator::MUL && op != binary_operator::DIV;
return op != binary_operator::MUL && op != binary_operator::DIV &&
op != binary_operator::MUL_OVERFLOW && op != binary_operator::DIV_OVERFLOW;
}

namespace jit {
Expand Down Expand Up @@ -216,6 +232,11 @@ std::unique_ptr<column> binary_operation(LhsType const& lhs,
if constexpr (std::is_same_v<LhsType, column_view> and std::is_same_v<RhsType, column_view>)
CUDF_EXPECTS(lhs.size() == rhs.size(), "Column sizes don't match", std::invalid_argument);

if (cudf::detail::checked_arithmetic::is_checked(op)) {
return cudf::detail::checked_arithmetic::binary_operation(
lhs, rhs, op, output_type, error_policy::PROPAGATE, stream, mr);
}

if (lhs.type().id() == type_id::STRING and rhs.type().id() == type_id::STRING and
output_type.id() == type_id::STRING and
(op == binary_operator::NULL_MAX or op == binary_operator::NULL_MIN))
Expand Down Expand Up @@ -407,8 +428,10 @@ int32_t binary_operation_fixed_point_scale(binary_operator op,
{
CUDF_EXPECTS(binops::is_supported_fixed_point_binop(op),
"Unsupported fixed_point binary operation.");
if (op == binary_operator::MUL) return left_scale + right_scale;
if (op == binary_operator::DIV) return left_scale - right_scale;
if (op == binary_operator::MUL || op == binary_operator::MUL_OVERFLOW)
return left_scale + right_scale;
if (op == binary_operator::DIV || op == binary_operator::DIV_OVERFLOW)
return left_scale - right_scale;
return std::min(left_scale, right_scale);
}

Expand Down Expand Up @@ -453,6 +476,45 @@ std::unique_ptr<column> binary_operation(column_view const& lhs,
return detail::binary_operation(lhs, rhs, op, output_type, stream, mr);
}

std::unique_ptr<column> binary_operation(scalar const& lhs,
column_view const& rhs,
binary_operator op,
data_type output_type,
error_policy policy,
cuda::stream_ref stream,
rmm::device_async_resource_ref mr)
{
CUDF_FUNC_RANGE();
return detail::checked_arithmetic::binary_operation(
lhs, rhs, op, output_type, policy, stream, mr);
}

std::unique_ptr<column> binary_operation(column_view const& lhs,
scalar const& rhs,
binary_operator op,
data_type output_type,
error_policy policy,
cuda::stream_ref stream,
rmm::device_async_resource_ref mr)
{
CUDF_FUNC_RANGE();
return detail::checked_arithmetic::binary_operation(
lhs, rhs, op, output_type, policy, stream, mr);
}

std::unique_ptr<column> binary_operation(column_view const& lhs,
column_view const& rhs,
binary_operator op,
data_type output_type,
error_policy policy,
cuda::stream_ref stream,
rmm::device_async_resource_ref mr)
{
CUDF_FUNC_RANGE();
return detail::checked_arithmetic::binary_operation(
lhs, rhs, op, output_type, policy, stream, mr);
}

std::unique_ptr<column> binary_operation(column_view const& lhs,
column_view const& rhs,
std::string const& ptx,
Expand Down
Loading
Loading