diff --git a/arrayfire_wrapper/lib/create_and_modify_array/create_array/pad.py b/arrayfire_wrapper/lib/create_and_modify_array/create_array/pad.py index 5542d8b..7fd8b21 100644 --- a/arrayfire_wrapper/lib/create_and_modify_array/create_array/pad.py +++ b/arrayfire_wrapper/lib/create_and_modify_array/create_array/pad.py @@ -22,4 +22,4 @@ def pad(arr: AFArray, begin_shape: tuple[int, ...], end_shape: tuple[int, ...], end_c_shape.c_array, border_type.value, ) - return NotImplemented + return out diff --git a/arrayfire_wrapper/lib/create_and_modify_array/manage_array.py b/arrayfire_wrapper/lib/create_and_modify_array/manage_array.py index 52d4cba..34ad512 100644 --- a/arrayfire_wrapper/lib/create_and_modify_array/manage_array.py +++ b/arrayfire_wrapper/lib/create_and_modify_array/manage_array.py @@ -166,7 +166,7 @@ def get_scalar(arr: AFArray, dtype: Dtype, /) -> int | float | complex | bool | out = dtype.c_type() call_from_clib(get_scalar.__name__, ctypes.pointer(out), arr) if dtype == c32 or dtype == c64: - return complex(out[0], out[1]) # type: ignore + return complex(out[0], out[1]) # type: ignore else: return cast(int | float | complex | bool | None, out.value) diff --git a/tests/test_diag.py b/tests/test_diag.py new file mode 100644 index 0000000..f666b08 --- /dev/null +++ b/tests/test_diag.py @@ -0,0 +1,43 @@ +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize("diagonal_shape", [(2,), (10,), (100,), (1000,)]) +def test_diagonal_shape(diagonal_shape: tuple) -> None: + """Test if diagonal array is keeping the shape of the passed into the input array""" + in_arr = wrapper.constant(1, diagonal_shape, dtypes.s16) + diag_array = wrapper.diag_create(in_arr, 0) + + extracted_diagonal = wrapper.diag_extract(diag_array, 0) + + assert wrapper.get_dims(extracted_diagonal)[0 : len(diagonal_shape)] == diagonal_shape # noqa: E203 + + +@pytest.mark.parametrize("diagonal_shape", [(2,), (10,), (100,), (1000,)]) +def test_diagonal_val(diagonal_shape: tuple) -> None: + """Test if diagonal array is keeping the same value as that of the values passed into the input array""" + dtype = dtypes.s16 + in_arr = wrapper.constant(1, diagonal_shape, dtype) + diag_array = wrapper.diag_create(in_arr, 0) + + extracted_diagonal = wrapper.diag_extract(diag_array, 0) + + assert wrapper.get_scalar(extracted_diagonal, dtype) == wrapper.get_scalar(in_arr, dtype) + + +@pytest.mark.parametrize( + "diagonal_shape", + [ + (10, 10, 10), + (100, 100, 100, 100), + ], +) +def test_invalid_diagonal(diagonal_shape: tuple) -> None: + """Test if an invalid diagonal shape is being properly handled""" + with pytest.raises(RuntimeError): + in_arr = wrapper.constant(1, diagonal_shape, dtypes.s16) + diag_array = wrapper.diag_create(in_arr, 0) + + wrapper.diag_extract(diag_array, 0) diff --git a/tests/test_identity.py b/tests/test_identity.py new file mode 100644 index 0000000..2bf516e --- /dev/null +++ b/tests/test_identity.py @@ -0,0 +1,70 @@ +import random + +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize( + "shape", + [ + (), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_identity_shape(shape: tuple) -> None: + """Test if identity creates an array with the correct shape""" + dtype = dtypes.s16 + + result = wrapper.identity(shape, dtype) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +def test_identity_invalid_shape() -> None: + """Test if identity handles a shape with greater than 4 dimensions""" + with pytest.raises(TypeError) as excinfo: + invalid_shape = ( + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + ) + dtype = dtypes.s16 + + wrapper.identity(invalid_shape, dtype) + + assert f"CShape.__init__() takes from 1 to 5 positional arguments but {len(invalid_shape) + 1} were given" in str( + excinfo.value + ) + + +def test_identity_nonsquare_shape() -> None: + dtype = dtypes.s16 + shape = (5, 6) + + result = wrapper.identity(shape, dtype) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +@pytest.mark.parametrize( + "dtype_index", + [i for i in range(13)], +) +def test_identity_dtype(dtype_index: int) -> None: + """Test if identity creates an array with the correct dtype""" + if dtype_index in [2, 3] and not wrapper.get_dbl_support(): + pytest.skip() + + shape = (5, 5) + dtype = dtypes.c_api_value_to_dtype(dtype_index) + + result = wrapper.identity(shape, dtype) + + assert dtypes.c_api_value_to_dtype(wrapper.get_type(result)) == dtype diff --git a/tests/test_iota.py b/tests/test_iota.py new file mode 100644 index 0000000..0778a99 --- /dev/null +++ b/tests/test_iota.py @@ -0,0 +1,125 @@ +import random + +import numpy as np +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize( + "shape", + [ + (), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_iota_shape(shape: tuple) -> None: + """Test if identity creates an array with the correct shape""" + dtype = dtypes.s16 + t_shape = (1, 1) + + result = wrapper.iota(shape, t_shape, dtype) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +def test_iota_invalid_shape() -> None: + """Test if iota handles a shape with greater than 4 dimensions""" + with pytest.raises(TypeError) as excinfo: + invalid_shape = ( + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + ) + dtype = dtypes.s16 + t_shape = () + + wrapper.iota(invalid_shape, t_shape, dtype) + + assert f"CShape.__init__() takes from 1 to 5 positional arguments but {len(invalid_shape) + 1} were given" in str( + excinfo.value + ) + + +@pytest.mark.parametrize( + "t_shape", + [ + (1,), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_iota_tshape(t_shape: tuple) -> None: + """Test if iota properly uses t_shape to change the size of the array and result in correct dimensions""" + shape = np.array([2, 2]) + dtype = dtypes.s64 + + if len(shape.shape) < len(t_shape): + shape = np.append(shape, np.ones(len(t_shape) - len(shape), dtype=int)) + + result_shape = shape * t_shape + + result = wrapper.iota(tuple(shape), t_shape, dtype) + + result_dims = tuple(int(value) for value in wrapper.get_dims(result)) + + assert (result_dims[0 : len(result_shape)] == result_shape).all() # noqa: E203 + + +@pytest.mark.parametrize( + "t_shape", + [ + (0,), + (-1, -1), + ], +) +def test_iota_tshape_zero(t_shape: tuple) -> None: + """Test it iota properly handles negative or zero t_shapes""" + with pytest.raises(RuntimeError): + shape = (2, 2) + + dtype = dtypes.s16 + + wrapper.iota(shape, t_shape, dtype) + + +def test_iota_tshape_invalid() -> None: + """Test it iota properly handles a tshape with greater than 4 dimensions""" + with pytest.raises(TypeError): + shape = (2, 2) + invalid_tshape = ( + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + random.randint(1, 10), + ) + dtype = dtypes.s16 + + wrapper.iota(shape, invalid_tshape, dtype) + + +@pytest.mark.parametrize( + "dtype_index", + [i for i in range(13)], +) +def test_iota_dtype(dtype_index: int) -> None: + """Test if iota creates an array with the correct dtype""" + if (dtype_index in [1, 4]) or (dtype_index in [2, 3] and not wrapper.get_dbl_support()): + pytest.skip() + + shape = (5, 5) + t_shape = (2, 2) + dtype = dtypes.c_api_value_to_dtype(dtype_index) + + result = wrapper.iota(shape, t_shape, dtype) + + assert dtypes.c_api_value_to_dtype(wrapper.get_type(result)) == dtype diff --git a/tests/test_lower.py b/tests/test_lower.py new file mode 100644 index 0000000..90379a9 --- /dev/null +++ b/tests/test_lower.py @@ -0,0 +1,45 @@ +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize( + "shape", + [ + (3, 3), + (3, 3, 3), + (3, 3, 3, 3), + ], +) +def test_diag_is_unit(shape: tuple) -> None: + """Test if when is_unit_diag in lower returns an array with a unit diagonal""" + dtype = dtypes.s64 + constant_array = wrapper.constant(3, shape, dtype) + + lower_array = wrapper.lower(constant_array, True) + diagonal = wrapper.diag_extract(lower_array, 0) + diagonal_value = wrapper.get_scalar(diagonal, dtype) + + assert diagonal_value == 1 + + +@pytest.mark.parametrize( + "shape", + [ + (3, 3), + (3, 3, 3), + (3, 3, 3, 3), + ], +) +def test_is_original(shape: tuple) -> None: + """Test if is_original keeps the diagonal the same as the original array""" + dtype = dtypes.s64 + constant_array = wrapper.constant(3, shape, dtype) + original_value = wrapper.get_scalar(constant_array, dtype) + + lower_array = wrapper.lower(constant_array, False) + diagonal = wrapper.diag_extract(lower_array, 0) + diagonal_value = wrapper.get_scalar(diagonal, dtype) + + assert original_value == diagonal_value diff --git a/tests/test_pad.py b/tests/test_pad.py new file mode 100644 index 0000000..d31d71a --- /dev/null +++ b/tests/test_pad.py @@ -0,0 +1,71 @@ +import random + +import numpy as np +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize( + "original_shape", + [ + (random.randint(1, 100),), + (random.randint(1, 100), random.randint(1, 100)), + (random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)), + (random.randint(1, 100), random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)), + ], +) +def test_zero_padding(original_shape: tuple) -> None: + """Test if pad creates an array with no padding if no padding is given""" + original_array = wrapper.constant(2, original_shape, dtypes.s64) + padding = wrapper.Pad(0) + + zero_shape = tuple(0 for _ in range(len(original_shape))) + result = wrapper.pad(original_array, zero_shape, zero_shape, padding) + + assert wrapper.get_dims(result)[0 : len(original_shape)] == original_shape # noqa: E203 + + +@pytest.mark.parametrize( + "original_shape", + [ + (random.randint(1, 100),), + (random.randint(1, 100), random.randint(1, 100)), + (random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)), + (random.randint(1, 100), random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)), + ], +) +def test_negative_padding(original_shape: tuple) -> None: + """Test if pad can properly handle if negative padding is given""" + with pytest.raises(RuntimeError): + original_array = wrapper.constant(2, original_shape, dtypes.s64) + padding = wrapper.Pad(0) + + neg_shape = tuple(-1 for _ in range(len(original_shape))) + result = wrapper.pad(original_array, neg_shape, neg_shape, padding) + + assert wrapper.get_dims(result)[0 : len(original_shape)] == original_shape # noqa: E203 + + +@pytest.mark.parametrize( + "original_shape", + [ + (random.randint(1, 100),), + (random.randint(1, 100), random.randint(1, 100)), + (random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)), + (random.randint(1, 100), random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)), + ], +) +def test_padding_shape(original_shape: tuple) -> None: + """Test if pad outputs the correct shape when a padding is adding to the original array""" + original_array = wrapper.constant(2, original_shape, dtypes.s64) + padding = wrapper.Pad(0) + + beg_shape = tuple(random.randint(1, 10) for _ in range(len(original_shape))) + end_shape = tuple(random.randint(1, 10) for _ in range(len(original_shape))) + + result = wrapper.pad(original_array, beg_shape, end_shape, padding) + new_shape = np.array(beg_shape) + np.array(end_shape) + np.array(original_shape) + + assert wrapper.get_dims(result)[0 : len(original_shape)] == tuple(new_shape) # noqa: E203 diff --git a/tests/test_random.py b/tests/test_random.py new file mode 100644 index 0000000..d46cd8e --- /dev/null +++ b/tests/test_random.py @@ -0,0 +1,111 @@ +import random + +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize( + "shape", + [ + (), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_randu_shape(shape: tuple) -> None: + """Test if randu function creates an array with the correct shape.""" + dtype = dtypes.s16 + + result = wrapper.randu(shape, dtype) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +@pytest.mark.parametrize( + "shape", + [ + (), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_random_uniform_shape(shape: tuple) -> None: + """Test if rand uniform function creates an array with the correct shape.""" + dtype = dtypes.s16 + engine = wrapper.create_random_engine(100, 10) + + result = wrapper.random_uniform(shape, dtype, engine) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +@pytest.mark.parametrize( + "shape", + [ + (), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_randn_shape(shape: tuple) -> None: + """Test if randn function creates an array with the correct shape.""" + dtype = dtypes.f32 + + result = wrapper.randn(shape, dtype) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +@pytest.mark.parametrize( + "shape", + [ + (), + (random.randint(1, 10), 1), + (random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + (random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)), + ], +) +def test_random_normal_shape(shape: tuple) -> None: + """Test if random normal function creates an array with the correct shape.""" + dtype = dtypes.f32 + engine = wrapper.create_random_engine(100, 10) + + result = wrapper.random_normal(shape, dtype, engine) + + assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203 + + +@pytest.mark.parametrize( + "engine_index", + [100, 200, 300], +) +def test_create_random_engine(engine_index: int) -> None: + engine = wrapper.create_random_engine(engine_index, 10) + + engine_type = wrapper.random_engine_get_type(engine) + + assert engine_type == engine_index + + +@pytest.mark.parametrize( + "invalid_index", + [random.randint(301, 600), random.randint(301, 600), random.randint(301, 600)], +) +def test_invalid_random_engine(invalid_index: int) -> None: + "Test if invalid engine types are properly handled" + with pytest.raises(RuntimeError): + + invalid_engine = wrapper.create_random_engine(invalid_index, 10) + + engine_type = wrapper.random_engine_get_type(invalid_engine) + + assert engine_type == invalid_engine diff --git a/tests/test_upper.py b/tests/test_upper.py new file mode 100644 index 0000000..adeb41e --- /dev/null +++ b/tests/test_upper.py @@ -0,0 +1,45 @@ +import pytest + +import arrayfire_wrapper.dtypes as dtypes +import arrayfire_wrapper.lib as wrapper + + +@pytest.mark.parametrize( + "shape", + [ + (3, 3), + (3, 3, 3), + (3, 3, 3, 3), + ], +) +def test_diag_is_unit(shape: tuple) -> None: + """Test if when is_unit_diag in lower returns an array with a unit diagonal""" + dtype = dtypes.s64 + constant_array = wrapper.constant(3, shape, dtype) + + lower_array = wrapper.upper(constant_array, True) + diagonal = wrapper.diag_extract(lower_array, 0) + diagonal_value = wrapper.get_scalar(diagonal, dtype) + + assert diagonal_value == 1 + + +@pytest.mark.parametrize( + "shape", + [ + (3, 3), + (3, 3, 3), + (3, 3, 3, 3), + ], +) +def test_is_original(shape: tuple) -> None: + """Test if is_original keeps the diagonal the same as the original array""" + dtype = dtypes.s64 + constant_array = wrapper.constant(3, shape, dtype) + original_value = wrapper.get_scalar(constant_array, dtype) + + lower_array = wrapper.upper(constant_array, False) + diagonal = wrapper.diag_extract(lower_array, 0) + diagonal_value = wrapper.get_scalar(diagonal, dtype) + + assert original_value == diagonal_value