Skip to content

Commit 1388ae7

Browse files
feat: Implement isnan and isfinite in bigframes
This commit implements the `isnan` and `isfinite` numpy ufuncs in bigframes. The following changes were made: - Added `IsNanOp` and `IsFiniteOp` to `bigframes/operations/numeric_ops.py` - Mapped `np.isnan` and `np.isfinite` to the new ops in `bigframes/operations/numpy_op_maps.py` - Added compilation logic for the new ops to the ibis, polars, and sqlglot compilers - Added tests for the new ops in `tests/system/small/test_numpy.py`
1 parent c331dfe commit 1388ae7

File tree

6 files changed

+50
-0
lines changed

6 files changed

+50
-0
lines changed

bigframes/core/compile/ibis_compiler/scalar_op_compiler.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from bigframes.core import agg_expressions, ordering
2727
import bigframes.core.compile.ibis_types
2828
import bigframes.core.expression as ex
29+
from bigframes.operations import numeric_ops
2930

3031
if TYPE_CHECKING:
3132
import bigframes.operations as ops
@@ -267,3 +268,13 @@ def _convert_range_ordering_to_table_value(
267268

268269
# Singleton compiler
269270
scalar_op_compiler = ExpressionCompiler()
271+
272+
273+
@scalar_op_compiler.register_unary_op(numeric_ops.isnan_op)
274+
def isnan(arg):
275+
return arg.isnan()
276+
277+
278+
@scalar_op_compiler.register_unary_op(numeric_ops.isfinite_op)
279+
def isfinite(arg):
280+
return arg.isinf().not_() & arg.isnan().not_()

bigframes/core/compile/polars/compiler.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,14 @@ def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
199199
def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
200200
return input.ceil()
201201

202+
@compile_op.register(num_ops.IsNanOp)
203+
def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
204+
return input.is_nan()
205+
206+
@compile_op.register(num_ops.IsFiniteOp)
207+
def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
208+
return input.is_finite()
209+
202210
@compile_op.register(num_ops.PosOp)
203211
def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
204212
return input.__pos__()

bigframes/core/compile/sqlglot/scalar_compiler.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import bigframes.core.compile.sqlglot.sqlglot_ir as ir
2323
import bigframes.core.expression as ex
2424
import bigframes.operations as ops
25+
from bigframes.operations import numeric_ops
2526

2627

2728
class ScalarOpCompiler:
@@ -180,3 +181,13 @@ def _register(
180181

181182
# Singleton compiler
182183
scalar_op_compiler = ScalarOpCompiler()
184+
185+
186+
@scalar_op_compiler.register_unary_op(numeric_ops.isnan_op)
187+
def isnan(arg: TypedExpr) -> sge.Expression:
188+
return sge.IsNan(this=arg.expr)
189+
190+
191+
@scalar_op_compiler.register_unary_op(numeric_ops.isfinite_op)
192+
def isfinite(arg: TypedExpr) -> sge.Expression:
193+
return sge.Not(this=sge.Or(this=sge.IsInf(this=arg.expr), right=sge.IsNan(this=arg.expr)))

bigframes/operations/numeric_ops.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,19 @@ def output_type(self, *input_types: dtypes.ExpressionType) -> dtypes.ExpressionT
348348
name="unsafe_pow_op", type_signature=op_typing.BINARY_REAL_NUMERIC
349349
)
350350
unsafe_pow_op = UnsafePowOp()
351+
352+
IsNanOp = base_ops.create_unary_op(
353+
name="isnan",
354+
type_signature=op_typing.FixedOutputType(
355+
dtypes.is_numeric, dtypes.BOOL_DTYPE, "numeric"
356+
),
357+
)
358+
isnan_op = IsNanOp()
359+
360+
IsFiniteOp = base_ops.create_unary_op(
361+
name="isfinite",
362+
type_signature=op_typing.FixedOutputType(
363+
dtypes.is_numeric, dtypes.BOOL_DTYPE, "numeric"
364+
),
365+
)
366+
isfinite_op = IsFiniteOp()

bigframes/operations/numpy_op_maps.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
np.ceil: numeric_ops.ceil_op,
4141
np.log1p: numeric_ops.log1p_op,
4242
np.expm1: numeric_ops.expm1_op,
43+
np.isnan: numeric_ops.isnan_op,
44+
np.isfinite: numeric_ops.isfinite_op,
4345
}
4446

4547

tests/system/small/test_numpy.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
("log10",),
3838
("sqrt",),
3939
("abs",),
40+
("isnan",),
41+
("isfinite",),
4042
],
4143
)
4244
def test_series_ufuncs(floats_pd, floats_bf, opname):

0 commit comments

Comments
 (0)