Skip to content

Multi-dimensional arrays support #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions array_api_tests/hypothesis_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
shared, tuples as hypotheses_tuples,
floats, just, composite, one_of, none,
booleans)
from hypothesis.extra.numpy import mutually_broadcastable_shapes
from hypothesis_array import mutually_broadcastable_shapes, get_strategies_namespace
from hypothesis import assume

from .pytest_helpers import nargs
Expand All @@ -16,10 +16,14 @@
integer_or_boolean_dtype_objects, dtype_objects)
from ._array_module import (ones, full, float32, float64, bool as bool_dtype, _UndefinedStub)
from . import _array_module
from ._array_module import mod as xp

from .function_stubs import elementwise_functions


xps = get_strategies_namespace(xp)


# Set this to True to not fail tests just because a dtype isn't implemented.
# If no compatible dtype is implemented for a given test, the test will fail
# with a hypothesis health check error. Note that this functionality will not
Expand Down Expand Up @@ -89,11 +93,11 @@ def tuples(elements, *, min_size=0, max_size=None, unique_by=None, unique=False)
return lists(elements, min_size=min_size, max_size=max_size,
unique_by=unique_by, unique=unique).map(tuple)

shapes = tuples(integers(0, 10)).filter(lambda shape: prod(shape) < MAX_ARRAY_SIZE)
shapes = xps.array_shapes(min_side=0).filter(lambda shape: prod(shape) < MAX_ARRAY_SIZE)

# Use this to avoid memory errors with NumPy.
# See https://github.com/numpy/numpy/issues/15753
shapes = tuples(integers(0, 10)).filter(
shapes = xps.array_shapes(min_side=0).filter(
lambda shape: prod([i for i in shape if i]) < MAX_ARRAY_SIZE)

two_mutually_broadcastable_shapes = mutually_broadcastable_shapes(num_shapes=2)\
Expand Down Expand Up @@ -121,8 +125,17 @@ def two_broadcastable_shapes(draw, shapes=shapes):

nonbroadcastable_ones_array_two_args = hypotheses_tuples(ones_arrays, ones_arrays)

# TODO: Generate general arrays here, rather than just scalars.
numeric_arrays = builds(full, just((1,)), floats())
floating_arrays = xps.arrays(dtype=xps.floating_dtypes(), shape=xps.array_shapes())

@composite
def broadcastable_floating_array_pairs(draw):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we instead want a function broadcastable_array_pairs (or mutually_broadcastable_array_pairs), which takes a dtype strategy as input. This will be similar to the array_scalars function in this file, which I expect this strategy will replace most instances of. The specific dtype combinations can then be set as floating_arrays = broadcastable_array_pairs(floating_dtypes) and so on. See the stuff at the top of test_elementwise.py (which should probably be moved to this file).

dtype = draw(xps.floating_dtypes())
broadcastable_shapes = draw(xps.mutually_broadcastable_shapes(2, min_dims=1))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why min_dims=1? We definitely want to make sure dimension 0 arrays are tested.

Actually, can't you use two_mutually_broadcastable_shapes defined above here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea why I did this heh.

shape1, shape2 = broadcastable_shapes.input_shapes
assume(len(shape1) >= len(shape2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this restriction here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh this goes back to the issue I was having with the special case tests generating indices which (mostly) worked only when the first array had ndims >= the second array. This would be resolved if both arrays in the special case tests shared the same shape, as you suggested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Yeah, there's no need to test broadcasting in the special cases tests (it's already tested separately in test_broadcasting.py), and it just makes building a mask more complicated, so we should just generate arrays of the same shape.

array1 = draw(xps.arrays(dtype=dtype, shape=shape1))
array2 = draw(xps.arrays(dtype=dtype, shape=shape2))
return array1, array2

@composite
def scalars(draw, dtypes, finite=False):
Expand Down Expand Up @@ -227,3 +240,5 @@ def multiaxis_indices(draw, shapes):
extra = draw(lists(one_of(integer_indices(sizes), slices(sizes)), min_size=0, max_size=3))
res += extra
return tuple(res)


8 changes: 4 additions & 4 deletions array_api_tests/special_cases/test_abs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"""

from ..array_helpers import NaN, assert_exactly_equal, exactly_equal, infinity, zero
from ..hypothesis_helpers import numeric_arrays
from ..hypothesis_helpers import floating_arrays, broadcastable_floating_array_pairs
from .._array_module import abs

from hypothesis import given


@given(numeric_arrays)
@given(floating_arrays)
def test_abs_special_cases_one_arg_equal_1(arg1):
"""
Special case test for `abs(x, /)`:
Expand All @@ -27,7 +27,7 @@ def test_abs_special_cases_one_arg_equal_1(arg1):
assert_exactly_equal(res[mask], (NaN(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_abs_special_cases_one_arg_equal_2(arg1):
"""
Special case test for `abs(x, /)`:
Expand All @@ -40,7 +40,7 @@ def test_abs_special_cases_one_arg_equal_2(arg1):
assert_exactly_equal(res[mask], (zero(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_abs_special_cases_one_arg_equal_3(arg1):
"""
Special case test for `abs(x, /)`:
Expand Down
10 changes: 5 additions & 5 deletions array_api_tests/special_cases/test_acos.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"""

from ..array_helpers import NaN, assert_exactly_equal, exactly_equal, greater, less, one, zero
from ..hypothesis_helpers import numeric_arrays
from ..hypothesis_helpers import floating_arrays, broadcastable_floating_array_pairs
from .._array_module import acos

from hypothesis import given


@given(numeric_arrays)
@given(floating_arrays)
def test_acos_special_cases_one_arg_equal_1(arg1):
"""
Special case test for `acos(x, /)`:
Expand All @@ -27,7 +27,7 @@ def test_acos_special_cases_one_arg_equal_1(arg1):
assert_exactly_equal(res[mask], (NaN(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_acos_special_cases_one_arg_equal_2(arg1):
"""
Special case test for `acos(x, /)`:
Expand All @@ -40,7 +40,7 @@ def test_acos_special_cases_one_arg_equal_2(arg1):
assert_exactly_equal(res[mask], (zero(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_acos_special_cases_one_arg_greater(arg1):
"""
Special case test for `acos(x, /)`:
Expand All @@ -53,7 +53,7 @@ def test_acos_special_cases_one_arg_greater(arg1):
assert_exactly_equal(res[mask], (NaN(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_acos_special_cases_one_arg_less(arg1):
"""
Special case test for `acos(x, /)`:
Expand Down
10 changes: 5 additions & 5 deletions array_api_tests/special_cases/test_acosh.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"""

from ..array_helpers import NaN, assert_exactly_equal, exactly_equal, infinity, less, one, zero
from ..hypothesis_helpers import numeric_arrays
from ..hypothesis_helpers import floating_arrays, broadcastable_floating_array_pairs
from .._array_module import acosh

from hypothesis import given


@given(numeric_arrays)
@given(floating_arrays)
def test_acosh_special_cases_one_arg_equal_1(arg1):
"""
Special case test for `acosh(x, /)`:
Expand All @@ -27,7 +27,7 @@ def test_acosh_special_cases_one_arg_equal_1(arg1):
assert_exactly_equal(res[mask], (NaN(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_acosh_special_cases_one_arg_equal_2(arg1):
"""
Special case test for `acosh(x, /)`:
Expand All @@ -40,7 +40,7 @@ def test_acosh_special_cases_one_arg_equal_2(arg1):
assert_exactly_equal(res[mask], (zero(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_acosh_special_cases_one_arg_equal_3(arg1):
"""
Special case test for `acosh(x, /)`:
Expand All @@ -53,7 +53,7 @@ def test_acosh_special_cases_one_arg_equal_3(arg1):
assert_exactly_equal(res[mask], (infinity(arg1.shape, arg1.dtype))[mask])


@given(numeric_arrays)
@given(floating_arrays)
def test_acosh_special_cases_one_arg_less(arg1):
"""
Special case test for `acosh(x, /)`:
Expand Down
Loading