From 9ece0a31b91dbeb7b62ea400a2bb60158b94a846 Mon Sep 17 00:00:00 2001 From: JosephGuman <105138387+JosephGuman@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:35:06 -0800 Subject: [PATCH] logical_and reduction (#1123) * Adding functionality for logical_and.reduce() with appropriate modifications in tests \n\n Joseph Guman * Minor style change to test for logical_and.reduce() \n\nSigned-off-by: Joseph Guman * Style changes and adding logical_or.reduce() functionality with UnaryRedCode.ANY Signed-off-by: Joseph Guman * Minor fixes --------- Co-authored-by: Joseph Thomas Guman Co-authored-by: Manolis Papadakis Co-authored-by: Manolis Papadakis --- cunumeric/_ufunc/comparison.py | 2 ++ cunumeric/_ufunc/ufunc.py | 11 +++++++++ tests/integration/test_fallback.py | 11 +++++++-- tests/integration/test_logical_reduction.py | 25 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/integration/test_logical_reduction.py diff --git a/cunumeric/_ufunc/comparison.py b/cunumeric/_ufunc/comparison.py index d1df4e8de..726936166 100644 --- a/cunumeric/_ufunc/comparison.py +++ b/cunumeric/_ufunc/comparison.py @@ -73,6 +73,7 @@ "logical_and", BinaryOpCode.LOGICAL_AND, relation_types_of(all_dtypes), + red_code=UnaryRedCode.ALL, ) logical_or = create_binary_ufunc( @@ -80,6 +81,7 @@ "logical_or", BinaryOpCode.LOGICAL_OR, relation_types_of(all_dtypes), + red_code=UnaryRedCode.ANY, ) logical_xor = create_binary_ufunc( diff --git a/cunumeric/_ufunc/ufunc.py b/cunumeric/_ufunc/ufunc.py index 3bba6b8ad..011ef13d1 100644 --- a/cunumeric/_ufunc/ufunc.py +++ b/cunumeric/_ufunc/ufunc.py @@ -753,6 +753,16 @@ def reduce( f"reduction for {self} is not yet implemented" ) + if self._op_code in [ + BinaryOpCode.LOGICAL_AND, + BinaryOpCode.LOGICAL_OR, + ]: + res_dtype = bool + if dtype is not None: + raise TypeError("Cannot set dtype on a logical reduction") + else: + res_dtype = None + # NumPy seems to be using None as the default axis value for scalars if array.ndim == 0 and axis == 0: axis = None @@ -767,6 +777,7 @@ def reduce( keepdims=keepdims, initial=initial, where=where, + res_dtype=res_dtype, ) diff --git a/tests/integration/test_fallback.py b/tests/integration/test_fallback.py index 4e312d0bb..3d93f5e91 100644 --- a/tests/integration/test_fallback.py +++ b/tests/integration/test_fallback.py @@ -28,8 +28,15 @@ def test_ufunc(): in_num = num.array([0, 1, 2, 3]) in_np = in_num.__array__() - out_num = np.logical_and.reduce(in_num) - out_np = np.logical_and.reduce(in_np) + # This test uses logical_and.accumulate because it is currently + # unimplemented, and we want to verify a behaviour of unimplemented ufunc + # methods. If logical_and.accumulate becomes implemented in the future, + # this assertion will start to fail, and a new (unimplemented) ufunc method + # should be found to replace it + assert not num.logical_and.accumulate._cunumeric.implemented + + out_num = num.logical_and.accumulate(in_num) + out_np = np.logical_and.accumulate(in_np) assert np.array_equal(out_num, out_np) diff --git a/tests/integration/test_logical_reduction.py b/tests/integration/test_logical_reduction.py new file mode 100644 index 000000000..023c2526c --- /dev/null +++ b/tests/integration/test_logical_reduction.py @@ -0,0 +1,25 @@ +import numpy as np +import pytest + +import cunumeric as num + + +@pytest.mark.parametrize("axis", [None, 0, 1, 2, (0, 1, 2)]) +def test_logical_reductions(axis): + input = [[[12, 0, 1, 2], [9, 0, 0, 1]], [[0, 0, 0, 5], [1, 1, 1, 1]]] + in_num = num.array(input) + in_np = np.array(input) + + out_num = num.logical_and.reduce(in_num, axis=axis) + out_np = np.logical_and.reduce(in_np, axis=axis) + assert num.array_equal(out_num, out_np) + + out_num = num.logical_or.reduce(in_num, axis=axis) + out_np = np.logical_or.reduce(in_np, axis=axis) + assert num.array_equal(out_num, out_np) + + +if __name__ == "__main__": + import sys + + sys.exit(pytest.main(sys.argv))