From eafe8b6f3c03874ff22d584ff6401bfe30ece1fe Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 20 Jan 2022 09:56:32 +0000 Subject: [PATCH 1/2] Make non-elwise/op type promotion tests standalone --- array_api_tests/test_creation_functions.py | 30 ++++++++++++--- array_api_tests/test_data_type_functions.py | 11 ++++++ array_api_tests/test_linalg.py | 42 ++++++++++++++------- array_api_tests/test_type_promotion.py | 38 ------------------- 4 files changed, 65 insertions(+), 56 deletions(-) create mode 100644 array_api_tests/test_data_type_functions.py diff --git a/array_api_tests/test_creation_functions.py b/array_api_tests/test_creation_functions.py index 8e448339..6da83430 100644 --- a/array_api_tests/test_creation_functions.py +++ b/array_api_tests/test_creation_functions.py @@ -1,8 +1,8 @@ import math -import pytest from itertools import count from typing import Iterator, NamedTuple, Union +import pytest from hypothesis import assume, given, note from hypothesis import strategies as st @@ -190,10 +190,7 @@ def test_arange(dtype, data): ), f"out[0]={out[0]}, but should be {_start} {f_func}" -@given( - shape=hh.shapes(min_side=1), - data=st.data(), -) +@given(shape=hh.shapes(min_side=1), data=st.data()) def test_asarray_scalars(shape, data): kw = data.draw( hh.kwargs(dtype=st.none() | xps.scalar_dtypes(), copy=st.none()), label="kw" @@ -482,6 +479,29 @@ def test_linspace(num, dtype, endpoint, data): ah.assert_exactly_equal(out, expected) +@given( + # The number and size of generated arrays is arbitrarily limited to prevent + # meshgrid() running out of memory. + dtypes=hh.mutually_promotable_dtypes(5, dtypes=dh.numeric_dtypes), + data=st.data(), +) +def test_meshgrid(dtypes, data): + arrays = [] + shapes = data.draw( + hh.mutually_broadcastable_shapes( + len(dtypes), min_dims=1, max_dims=1, max_side=5 + ), + label="shapes", + ) + for i, (dtype, shape) in enumerate(zip(dtypes, shapes), 1): + x = data.draw(xps.arrays(dtype=dtype, shape=shape), label=f"x{i}") + arrays.append(x) + assert math.prod(x.size for x in arrays) <= hh.MAX_ARRAY_SIZE # sanity check + out = xp.meshgrid(*arrays) + for i, x in enumerate(out): + ph.assert_dtype("meshgrid", dtypes, x.dtype, repr_name=f"out[{i}].dtype") + + def make_one(dtype: DataType) -> Scalar: if dtype is None or dh.is_float_dtype(dtype): return 1.0 diff --git a/array_api_tests/test_data_type_functions.py b/array_api_tests/test_data_type_functions.py new file mode 100644 index 00000000..366d0f32 --- /dev/null +++ b/array_api_tests/test_data_type_functions.py @@ -0,0 +1,11 @@ +from hypothesis import given + +from . import _array_module as xp +from . import hypothesis_helpers as hh +from . import pytest_helpers as ph + + +@given(hh.mutually_promotable_dtypes(None)) +def test_result_type(dtypes): + out = xp.result_type(*dtypes) + ph.assert_dtype("result_type", dtypes, out, repr_name="out") diff --git a/array_api_tests/test_linalg.py b/array_api_tests/test_linalg.py index 52c8774c..2d8289d7 100644 --- a/array_api_tests/test_linalg.py +++ b/array_api_tests/test_linalg.py @@ -16,7 +16,7 @@ import pytest from hypothesis import assume, given from hypothesis.strategies import (booleans, composite, none, tuples, integers, - shared, sampled_from) + shared, sampled_from, data, just) from .array_helpers import assert_exactly_equal, asarray, equal, zero, infinity from .hypothesis_helpers import (xps, dtypes, shapes, kwargs, matrix_shapes, @@ -33,6 +33,7 @@ from .algos import broadcast_shapes from . import _array_module +from . import _array_module as xp from ._array_module import linalg pytestmark = pytest.mark.ci @@ -556,13 +557,20 @@ def test_svdvals(x): @given( - x1=xps.arrays(dtype=xps.floating_dtypes(), shape=shapes()), - x2=xps.arrays(dtype=xps.floating_dtypes(), shape=shapes()), - kw=kwargs(axes=todo) + dtypes=mutually_promotable_dtypes(dtypes=dh.numeric_dtypes), + shape=shapes(), + data=data(), ) -def test_tensordot(x1, x2, kw): - # res = _array_module.tensordot(x1, x2, **kw) - pass +def test_tensordot(dtypes, shape, data): + # TODO: vary shapes, vary contracted axes, test different axes arguments + x1 = data.draw(xps.arrays(dtype=dtypes[0], shape=shape), label="x1") + x2 = data.draw(xps.arrays(dtype=dtypes[1], shape=shape), label="x2") + + out = xp.tensordot(x1, x2, axes=len(shape)) + + ph.assert_dtype("tensordot", dtypes, out.dtype) + # TODO: assert shape and elements + @pytest.mark.xp_extension('linalg') @given( @@ -605,13 +613,21 @@ def true_trace(x_stack): @given( - x1=xps.arrays(dtype=xps.floating_dtypes(), shape=shapes()), - x2=xps.arrays(dtype=xps.floating_dtypes(), shape=shapes()), - kw=kwargs(axis=todo) + dtypes=mutually_promotable_dtypes(dtypes=dh.numeric_dtypes), + shape=shapes(), + data=data(), ) -def test_vecdot(x1, x2, kw): - # res = _array_module.vecdot(x1, x2, **kw) - pass +def test_vecdot(dtypes, shape, data): + # TODO: vary shapes, test different axis arguments + x1 = data.draw(xps.arrays(dtype=dtypes[0], shape=shape), label="x1") + x2 = data.draw(xps.arrays(dtype=dtypes[1], shape=shape), label="x2") + kw = data.draw(kwargs(axis=just(-1))) + + out = xp.vecdot(x1, x2, **kw) + + ph.assert_dtype("vecdot", dtypes, out.dtype) + # TODO: assert shape and elements + @pytest.mark.xp_extension('linalg') @given( diff --git a/array_api_tests/test_type_promotion.py b/array_api_tests/test_type_promotion.py index 29fb08c9..b1e5a09b 100644 --- a/array_api_tests/test_type_promotion.py +++ b/array_api_tests/test_type_promotion.py @@ -16,16 +16,6 @@ from .function_stubs import elementwise_functions from .typing import DataType, Param, ScalarType -# TODO: move tests not covering elementwise funcs/ops into standalone tests -# result_type, meshgrid, tensordor, vecdot - - -@given(hh.mutually_promotable_dtypes(None)) -def test_result_type(dtypes): - out = xp.result_type(*dtypes) - ph.assert_dtype("result_type", dtypes, out, repr_name="out") - - bitwise_shift_funcs = [ "bitwise_left_shift", "bitwise_right_shift", @@ -133,37 +123,9 @@ def test_func_promotion(func_name, in_dtypes, out_dtype, data): promotion_params.append(p) -@pytest.mark.parametrize("in_dtypes, out_dtype", promotion_params) -@given(shapes=hh.mutually_broadcastable_shapes(3), data=st.data()) -def test_where(in_dtypes, out_dtype, shapes, data): - x1 = data.draw(xps.arrays(dtype=in_dtypes[0], shape=shapes[0]), label="x1") - x2 = data.draw(xps.arrays(dtype=in_dtypes[1], shape=shapes[1]), label="x2") - cond = data.draw(xps.arrays(dtype=xp.bool, shape=shapes[2]), label="condition") - out = xp.where(cond, x1, x2) - ph.assert_dtype("where", in_dtypes, out.dtype, out_dtype) - - numeric_promotion_params = promotion_params[1:] -@pytest.mark.parametrize("in_dtypes, out_dtype", numeric_promotion_params) -@given(shapes=hh.mutually_broadcastable_shapes(2, min_dims=2), data=st.data()) -def test_tensordot(in_dtypes, out_dtype, shapes, data): - x1 = data.draw(xps.arrays(dtype=in_dtypes[0], shape=shapes[0]), label="x1") - x2 = data.draw(xps.arrays(dtype=in_dtypes[1], shape=shapes[1]), label="x2") - out = xp.tensordot(x1, x2) - ph.assert_dtype("tensordot", in_dtypes, out.dtype, out_dtype) - - -@pytest.mark.parametrize("in_dtypes, out_dtype", numeric_promotion_params) -@given(shapes=hh.mutually_broadcastable_shapes(2, min_dims=1), data=st.data()) -def test_vecdot(in_dtypes, out_dtype, shapes, data): - x1 = data.draw(xps.arrays(dtype=in_dtypes[0], shape=shapes[0]), label="x1") - x2 = data.draw(xps.arrays(dtype=in_dtypes[1], shape=shapes[1]), label="x2") - out = xp.vecdot(x1, x2) - ph.assert_dtype("vecdot", in_dtypes, out.dtype, out_dtype) - - op_params: List[Param[str, str, Tuple[DataType, ...], DataType]] = [] op_to_symbol = {**dh.unary_op_to_symbol, **dh.binary_op_to_symbol} for op, symbol in op_to_symbol.items(): From 3ed56a9144a4ab7345d439a1ad0ddc485c8d68c6 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 20 Jan 2022 10:27:40 +0000 Subject: [PATCH 2/2] Test `finfo` and `iinfo` attributes --- array_api_tests/test_data_type_functions.py | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/array_api_tests/test_data_type_functions.py b/array_api_tests/test_data_type_functions.py index 366d0f32..e7cb0516 100644 --- a/array_api_tests/test_data_type_functions.py +++ b/array_api_tests/test_data_type_functions.py @@ -1,8 +1,47 @@ +import pytest from hypothesis import given from . import _array_module as xp +from . import dtype_helpers as dh from . import hypothesis_helpers as hh from . import pytest_helpers as ph +from .typing import DataType + + +def make_dtype_id(dtype: DataType) -> str: + return dh.dtype_to_name[dtype] + + +@pytest.mark.parametrize("dtype", dh.float_dtypes, ids=make_dtype_id) +def test_finfo(dtype): + out = xp.finfo(dtype) + f_func = f"[finfo({dh.dtype_to_name[dtype]})]" + for attr, stype in [ + ("bits", int), + ("eps", float), + ("max", float), + ("min", float), + ("smallest_normal", float), + ]: + assert hasattr(out, attr), f"out has no attribute '{attr}' {f_func}" + value = getattr(out, attr) + assert isinstance( + value, stype + ), f"type(out.{attr})={type(value)!r}, but should be {stype.__name__} {f_func}" + # TODO: test values + + +@pytest.mark.parametrize("dtype", dh.all_int_dtypes, ids=make_dtype_id) +def test_iinfo(dtype): + out = xp.iinfo(dtype) + f_func = f"[iinfo({dh.dtype_to_name[dtype]})]" + for attr in ["bits", "max", "min"]: + assert hasattr(out, attr), f"out has no attribute '{attr}' {f_func}" + value = getattr(out, attr) + assert isinstance( + value, int + ), f"type(out.{attr})={type(value)!r}, but should be int {f_func}" + # TODO: test values @given(hh.mutually_promotable_dtypes(None))