1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! Binary operations on GPU-resident columns.
//!
//! Provides element-wise binary operations (arithmetic, comparison,
//! logical, bitwise) between [`Column`]s and/or [`Scalar`]s.
//!
//! # Examples
//!
//! ```rust,no_run
//! use cudf::{Column, DataType, TypeId};
//! use cudf::binaryop::BinaryOp;
//!
//! let a = Column::from_slice(&[1i32, 2, 3]).unwrap();
//! let b = Column::from_slice(&[10i32, 20, 30]).unwrap();
//! let sum = a.binary_op(&b, BinaryOp::Add, DataType::new(TypeId::Int32)).unwrap();
//! ```
use crate::column::Column;
use crate::error::{CudfError, Result};
use crate::scalar::Scalar;
use crate::types::DataType;
/// Binary operations supported by libcudf.
///
/// These map to `cudf::binary_operator` enum values in libcudf 26.x.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum BinaryOp {
/// Addition
Add = 0,
/// Subtraction
Sub = 1,
/// Multiplication
Mul = 2,
/// Division (integral division for integer types)
Div = 3,
/// True division (always produces floating-point result)
TrueDiv = 4,
/// Floor division
FloorDiv = 5,
/// Modulo
Mod = 6,
/// Positive modulo (result is always >= 0)
PMod = 7,
/// Python-style modulo (result has sign of divisor)
PyMod = 8,
/// Power
Pow = 9,
/// Integer power
IntPow = 10,
/// Logarithm with specified base
LogBase = 11,
/// Two-argument arctangent
Atan2 = 12,
/// Shift left
ShiftLeft = 13,
/// Shift right
ShiftRight = 14,
/// Unsigned shift right
ShiftRightUnsigned = 15,
/// Bitwise AND
BitwiseAnd = 16,
/// Bitwise OR
BitwiseOr = 17,
/// Bitwise XOR
BitwiseXor = 18,
/// Logical AND
LogicalAnd = 19,
/// Logical OR
LogicalOr = 20,
/// Equality comparison
Equal = 21,
/// Inequality comparison
NotEqual = 22,
/// Less than
Less = 23,
/// Greater than
Greater = 24,
/// Less than or equal
LessEqual = 25,
/// Greater than or equal
GreaterEqual = 26,
/// Null-aware equality (NULL == NULL -> true)
NullEquals = 27,
/// Null-aware inequality
NullNotEquals = 28,
/// Null-aware max
NullMax = 29,
/// Null-aware min
NullMin = 30,
/// Generic binary operation (user-defined)
GenericBinary = 31,
/// Null-aware logical AND
NullLogicalAnd = 32,
/// Null-aware logical OR
NullLogicalOr = 33,
/// Invalid binary operator (sentinel)
InvalidBinary = 34,
}
impl Column {
/// Apply a binary operation element-wise between two columns.
///
/// Both columns must have the same length.
///
/// # Examples
///
/// ```rust,no_run
/// use cudf::{Column, DataType, TypeId};
/// use cudf::binaryop::BinaryOp;
///
/// let a = Column::from_slice(&[1i32, 2, 3]).unwrap();
/// let b = Column::from_slice(&[10i32, 20, 30]).unwrap();
/// let result = a.binary_op(&b, BinaryOp::Add, DataType::new(TypeId::Int32)).unwrap();
/// ```
pub fn binary_op(&self, other: &Column, op: BinaryOp, output_type: DataType) -> Result<Column> {
let result = cudf_cxx::binaryop::ffi::binary_operation_col_col(
&self.inner,
&other.inner,
op as i32,
output_type.id() as i32,
)
.map_err(CudfError::from_cxx)?;
Ok(Column { inner: result })
}
/// Apply a binary operation element-wise between this column and a scalar.
///
/// The scalar is broadcast to match the column length.
///
/// # Examples
///
/// ```rust,no_run
/// use cudf::{Column, Scalar, DataType, TypeId};
/// use cudf::binaryop::BinaryOp;
///
/// let col = Column::from_slice(&[1i32, 2, 3]).unwrap();
/// let scalar = Scalar::new(10i32).unwrap();
/// let result = col.binary_op_scalar(&scalar, BinaryOp::Mul, DataType::new(TypeId::Int32)).unwrap();
/// ```
pub fn binary_op_scalar(
&self,
scalar: &Scalar,
op: BinaryOp,
output_type: DataType,
) -> Result<Column> {
let result = cudf_cxx::binaryop::ffi::binary_operation_col_scalar(
&self.inner,
&scalar.inner,
op as i32,
output_type.id() as i32,
)
.map_err(CudfError::from_cxx)?;
Ok(Column { inner: result })
}
}
/// Apply a binary operation between a scalar and a column.
///
/// The scalar is broadcast to match the column length.
pub fn binary_op(
lhs: &Scalar,
rhs: &Column,
op: BinaryOp,
output_type: DataType,
) -> Result<Column> {
let result = cudf_cxx::binaryop::ffi::binary_operation_scalar_col(
&lhs.inner,
&rhs.inner,
op as i32,
output_type.id() as i32,
)
.map_err(CudfError::from_cxx)?;
Ok(Column { inner: result })
}
/// Check if a binary operation is supported for the given types and operator.
///
/// Returns `true` if `lhs_type op rhs_type -> out_type` is supported.
pub fn is_supported_operation(
out_type: DataType,
lhs_type: DataType,
rhs_type: DataType,
op: BinaryOp,
) -> Result<bool> {
cudf_cxx::binaryop::ffi::is_supported_operation(
out_type.id() as i32,
lhs_type.id() as i32,
rhs_type.id() as i32,
op as i32,
)
.map_err(CudfError::from_cxx)
}