From fc26e4f4eafa61b28442c51471f058b6697b5a79 Mon Sep 17 00:00:00 2001 From: boulea7 Date: Mon, 28 Sep 2026 17:20:11 +0800 Subject: [PATCH 1/3] TST: cover reflected scalar operators --- ...est_operators_and_elementwise_functions.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/array_api_tests/test_operators_and_elementwise_functions.py b/array_api_tests/test_operators_and_elementwise_functions.py index 6ab7ec34..91ed7378 100644 --- a/array_api_tests/test_operators_and_elementwise_functions.py +++ b/array_api_tests/test_operators_and_elementwise_functions.py @@ -2104,6 +2104,50 @@ def test_subtract(ctx, data): raise +def make_reflected_scalar_params(): + cases = ( + ("__radd__", "add", operator.add, dh.numeric_dtypes, 7, (2, 3)), + ("__rsub__", "subtract", operator.sub, dh.numeric_dtypes, 7, (2, 3)), + ("__rmul__", "multiply", operator.mul, dh.numeric_dtypes, 7, (2, 3)), + ("__rtruediv__", "divide", operator.truediv, dh.all_float_dtypes, 6, (2, 4)), + ("__rfloordiv__", "floor_divide", operator.floordiv, dh.real_dtypes, 7, (2, 3)), + ("__rpow__", "pow", operator.pow, dh.numeric_dtypes, 3, (1, 2)), + ("__rmod__", "remainder", operator.mod, dh.real_dtypes, 7, (2, 3)), + ("__rand__", "bitwise_and", operator.and_, dh.bool_and_all_int_dtypes, 6, (1, 2)), + ("__ror__", "bitwise_or", operator.or_, dh.bool_and_all_int_dtypes, 6, (1, 2)), + ("__rxor__", "bitwise_xor", operator.xor, dh.bool_and_all_int_dtypes, 6, (1, 2)), + ("__rlshift__", "bitwise_left_shift", operator.lshift, dh.all_int_dtypes, 3, (1, 2)), + ("__rrshift__", "bitwise_right_shift", operator.rshift, dh.all_int_dtypes, 8, (1, 2)), + ) + for method, func_name, op, dtypes, scalar, values in cases: + for dtype in dtypes: + if isinstance(dtype, xp._UndefinedStub): + continue + if dtype == xp.bool: + operand, elements = True, (False, True) + else: + scalar_type = dh.get_scalar_type(dtype) + operand = scalar_type(scalar) + elements = tuple(scalar_type(value) for value in values) + yield pytest.param( + method, func_name, op, dtype, operand, elements, + id=f"{method}-{dh.dtype_to_name[dtype]}", + ) + + +@pytest.mark.parametrize( + "method, func_name, op, dtype, scalar, values", make_reflected_scalar_params() +) +def test_reflected_scalar_operator(method, func_name, op, dtype, scalar, values): + x = xp.asarray(values, dtype=dtype) + out = op(scalar, x) + expected = getattr(xp, func_name)(xp.asarray(scalar, dtype=dtype), x) + + ph.assert_dtype(method, in_dtype=dtype, out_dtype=out.dtype) + ph.assert_result_shape(method, in_shapes=[x.shape], out_shape=out.shape) + ph.assert_array_elements(method, out=out, expected=expected) + + @given(hh.arrays(dtype=hh.all_floating_dtypes(), shape=hh.shapes())) def test_tan(x): repro_snippet = ph.format_snippet(f"xp.tan({x!r})") From 019e060f003acfa2eec33761f0e948c937633443 Mon Sep 17 00:00:00 2001 From: boulea7 Date: Wed, 30 Sep 2026 04:01:36 +0800 Subject: [PATCH 2/3] TST: generate reflected operator inputs with Hypothesis --- ...est_operators_and_elementwise_functions.py | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/array_api_tests/test_operators_and_elementwise_functions.py b/array_api_tests/test_operators_and_elementwise_functions.py index 91ed7378..f3c29785 100644 --- a/array_api_tests/test_operators_and_elementwise_functions.py +++ b/array_api_tests/test_operators_and_elementwise_functions.py @@ -2106,40 +2106,49 @@ def test_subtract(ctx, data): def make_reflected_scalar_params(): cases = ( - ("__radd__", "add", operator.add, dh.numeric_dtypes, 7, (2, 3)), - ("__rsub__", "subtract", operator.sub, dh.numeric_dtypes, 7, (2, 3)), - ("__rmul__", "multiply", operator.mul, dh.numeric_dtypes, 7, (2, 3)), - ("__rtruediv__", "divide", operator.truediv, dh.all_float_dtypes, 6, (2, 4)), - ("__rfloordiv__", "floor_divide", operator.floordiv, dh.real_dtypes, 7, (2, 3)), - ("__rpow__", "pow", operator.pow, dh.numeric_dtypes, 3, (1, 2)), - ("__rmod__", "remainder", operator.mod, dh.real_dtypes, 7, (2, 3)), - ("__rand__", "bitwise_and", operator.and_, dh.bool_and_all_int_dtypes, 6, (1, 2)), - ("__ror__", "bitwise_or", operator.or_, dh.bool_and_all_int_dtypes, 6, (1, 2)), - ("__rxor__", "bitwise_xor", operator.xor, dh.bool_and_all_int_dtypes, 6, (1, 2)), - ("__rlshift__", "bitwise_left_shift", operator.lshift, dh.all_int_dtypes, 3, (1, 2)), - ("__rrshift__", "bitwise_right_shift", operator.rshift, dh.all_int_dtypes, 8, (1, 2)), + ("__radd__", "add", operator.add, dh.numeric_dtypes), + ("__rsub__", "subtract", operator.sub, dh.numeric_dtypes), + ("__rmul__", "multiply", operator.mul, dh.numeric_dtypes), + ("__rtruediv__", "divide", operator.truediv, dh.all_float_dtypes), + ("__rfloordiv__", "floor_divide", operator.floordiv, dh.real_dtypes), + ("__rpow__", "pow", operator.pow, dh.numeric_dtypes), + ("__rmod__", "remainder", operator.mod, dh.real_dtypes), + ("__rand__", "bitwise_and", operator.and_, dh.bool_and_all_int_dtypes), + ("__ror__", "bitwise_or", operator.or_, dh.bool_and_all_int_dtypes), + ("__rxor__", "bitwise_xor", operator.xor, dh.bool_and_all_int_dtypes), + ("__rlshift__", "bitwise_left_shift", operator.lshift, dh.all_int_dtypes), + ("__rrshift__", "bitwise_right_shift", operator.rshift, dh.all_int_dtypes), ) - for method, func_name, op, dtypes, scalar, values in cases: + for method, func_name, op, dtypes in cases: for dtype in dtypes: if isinstance(dtype, xp._UndefinedStub): continue - if dtype == xp.bool: - operand, elements = True, (False, True) - else: - scalar_type = dh.get_scalar_type(dtype) - operand = scalar_type(scalar) - elements = tuple(scalar_type(value) for value in values) yield pytest.param( - method, func_name, op, dtype, operand, elements, + method, func_name, op, dtype, id=f"{method}-{dh.dtype_to_name[dtype]}", ) @pytest.mark.parametrize( - "method, func_name, op, dtype, scalar, values", make_reflected_scalar_params() + "method, func_name, op, dtype", make_reflected_scalar_params() ) -def test_reflected_scalar_operator(method, func_name, op, dtype, scalar, values): - x = xp.asarray(values, dtype=dtype) +@given(data=st.data()) +def test_reflected_scalar_operator(method, func_name, op, dtype, data): + # Small positive values avoid division by zero, invalid powers, and overflow. + if dtype == xp.bool: + elements = st.booleans() + else: + elements = st.integers(1, 3).map(dh.get_scalar_type(dtype)) + scalar_strategy = elements + if func_name == "subtract" and dtype in dh.uint_dtypes: + scalar_strategy = st.integers(3, 7) + scalar = data.draw(scalar_strategy, label="scalar") + x = data.draw( + hh.arrays( + dtype=dtype, shape=hh.shapes(min_dims=1, min_side=1), elements=elements + ), + label="x", + ) out = op(scalar, x) expected = getattr(xp, func_name)(xp.asarray(scalar, dtype=dtype), x) From 71b70e1358e2e18c7245641ca221bc3c0b3bdc49 Mon Sep 17 00:00:00 2001 From: boulea7 Date: Thu, 1 Oct 2026 23:51:00 +0800 Subject: [PATCH 3/3] TST: materialize reflected scalar parameters --- array_api_tests/test_operators_and_elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/array_api_tests/test_operators_and_elementwise_functions.py b/array_api_tests/test_operators_and_elementwise_functions.py index f3c29785..a1247459 100644 --- a/array_api_tests/test_operators_and_elementwise_functions.py +++ b/array_api_tests/test_operators_and_elementwise_functions.py @@ -2130,7 +2130,7 @@ def make_reflected_scalar_params(): @pytest.mark.parametrize( - "method, func_name, op, dtype", make_reflected_scalar_params() + "method, func_name, op, dtype", list(make_reflected_scalar_params()) ) @given(data=st.data()) def test_reflected_scalar_operator(method, func_name, op, dtype, data):