Skip to content

Commit

Permalink
Merge branch 'master' into complexity_testing
Browse files Browse the repository at this point in the history
  • Loading branch information
AzeezIsh authored Mar 28, 2024
2 parents 55dda7c + b7e42bd commit 7b8fe9e
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 34 deletions.
2 changes: 1 addition & 1 deletion arrayfire_wrapper/_backend.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__all__ = ["BackendType"]
__all__ = ["BackendType", "get_backend", "set_backend"]

import ctypes
import enum
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ def pad(arr: AFArray, begin_shape: tuple[int, ...], end_shape: tuple[int, ...],
ctypes.pointer(out),
arr,
4,
begin_c_shape.c_array,
ctypes.pointer(begin_c_shape.c_array),
4,
end_c_shape.c_array,
ctypes.pointer(end_c_shape.c_array),
border_type.value,
)
return out
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ def alloc_host(num_bytes: int, /) -> int:
Allocate a buffer on the host with specified number of bytes.
"""
# TODO
# Avoid using AFArray and use ctypes.c_void_p to avoid misunderstanding 'coz its not actually an array
out = AFArray.create_null_pointer()
call_from_clib(alloc_host.__name__, ctypes.pointer(out), CDimT(num_bytes))
return out.value # type: ignore[return-value]
Expand Down
18 changes: 12 additions & 6 deletions arrayfire_wrapper/lib/create_and_modify_array/move_and_reorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,31 @@ def replace_scalar(lhs: AFArray, cond_arr: AFArray, rhs: int | float, /) -> None
call_from_clib(replace.__name__, lhs, cond_arr, ctypes.c_double(rhs))


def select(lhs: AFArray, cond_arr: AFArray, rhs: AFArray, /) -> None:
def select(lhs: AFArray, cond_arr: AFArray, rhs: AFArray, /) -> AFArray:
"""
source: https://arrayfire.org/docs/group__data__func__select.htm#gac4af16e31ddd5ddcf09b670f676fd093
"""
call_from_clib(select.__name__, cond_arr, lhs, rhs)
out = AFArray.create_null_pointer()
call_from_clib(select.__name__, ctypes.pointer(out), cond_arr, lhs, rhs)
return out


def select_scalar_l(lhs: int | float, cond_arr: AFArray, rhs: AFArray, /) -> None:
def select_scalar_l(lhs: int | float, cond_arr: AFArray, rhs: AFArray, /) -> AFArray:
"""
source: https://arrayfire.org/docs/group__data__func__select.htm#gac4af16e31ddd5ddcf09b670f676fd093
"""
call_from_clib(select_scalar_l.__name__, cond_arr, ctypes.c_double(lhs), rhs)
out = AFArray.create_null_pointer()
call_from_clib(select_scalar_l.__name__, ctypes.pointer(out), cond_arr, ctypes.c_double(lhs), rhs)
return out


def select_scalar_r(lhs: AFArray, cond_arr: AFArray, rhs: int | float, /) -> None:
def select_scalar_r(lhs: AFArray, cond_arr: AFArray, rhs: int | float, /) -> AFArray:
"""
source: https://arrayfire.org/docs/group__data__func__select.htm#gac4af16e31ddd5ddcf09b670f676fd093
"""
call_from_clib(select_scalar_l.__name__, cond_arr, lhs, ctypes.c_double(rhs))
out = AFArray.create_null_pointer()
call_from_clib(select_scalar_l.__name__, ctypes.pointer(out), cond_arr, lhs, ctypes.c_double(rhs))
return out


def shift(arr: AFArray, /, d0: int, d1: int = 0, d2: int = 0, d3: int = 0) -> AFArray:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,7 @@ def max_ragged(arr: AFArray, ragged_len: AFArray, dim: int, /) -> tuple[AFArray,
"""
out_values = AFArray.create_null_pointer()
out_idx = AFArray.create_null_pointer()
call_from_clib(
max_ragged.__name__, ctypes.pointer(out_values), ctypes.pointer(out_idx), arr, ragged_len, ctypes.c_int(dim)
)
call_from_clib(max_ragged.__name__, ctypes.pointer(out_values), ctypes.pointer(out_idx), arr, ragged_len, dim)
return (out_values, out_idx)


Expand All @@ -156,9 +154,7 @@ def max_by_key(keys: AFArray, values: AFArray, dim: int, /) -> tuple[AFArray, AF
"""
out_keys = AFArray.create_null_pointer()
out_values = AFArray.create_null_pointer()
call_from_clib(
max_by_key.__name__, ctypes.pointer(out_keys), ctypes.pointer(out_values), keys, values, ctypes.c_int(dim)
)
call_from_clib(max_by_key.__name__, ctypes.pointer(out_keys), ctypes.pointer(out_values), keys, values, dim)
return (out_keys, out_values)


Expand Down
2 changes: 1 addition & 1 deletion arrayfire_wrapper/lib/vector_algorithms/set_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ def set_unique(arr: AFArray, is_sorted: bool, /) -> AFArray:
source: https://arrayfire.org/docs/group__set__func__unique.htm#ga6afa1de48cbbc4b2df530c2530087943
"""
out = AFArray.create_null_pointer()
call_from_clib(set_intersect.__name__, ctypes.pointer(out), ctypes.c_bool(is_sorted))
call_from_clib(set_unique.__name__, ctypes.pointer(out), arr, ctypes.c_bool(is_sorted))
return out
2 changes: 1 addition & 1 deletion arrayfire_wrapper/version.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os

_MAJOR = "0"
_MINOR = "6"
_MINOR = "7"
# On main and in a nightly release the patch should be one ahead of the last
# released build.
_PATCH = "0"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "arrayfire-binary-python-wrapper"
version = "0.6.0+AF3.9.0"
version = "0.7.0+AF3.9.0"
requires-python = ">=3.10"
authors = [
{ name = "ArrayFire", email = "[email protected]"},
Expand Down
152 changes: 152 additions & 0 deletions tests/test_arithmetic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import random

import pytest

import arrayfire_wrapper.dtypes as dtype
import arrayfire_wrapper.lib as wrapper
from tests.utility_functions import check_type_supported, get_all_types


@pytest.mark.parametrize(
"shape",
[
(),
(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), random.randint(1, 10)),
],
)
def test_add_shapes(shape: tuple) -> None:
"""Test addition operation between two arrays of the same shape"""
lhs = wrapper.randu(shape, dtype.f16)
rhs = wrapper.randu(shape, dtype.f16)

result = wrapper.add(lhs, rhs)

assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203, W291


def test_add_different_shapes() -> None:
"""Test if addition handles arrays of different shapes"""
with pytest.raises(RuntimeError):
lhs_shape = (2, 3)
rhs_shape = (3, 2)
dtypes = dtype.f16
lhs = wrapper.randu(lhs_shape, dtypes)
rhs = wrapper.randu(rhs_shape, dtypes)

wrapper.add(lhs, rhs)


@pytest.mark.parametrize("dtype_name", get_all_types())
def test_add_supported_dtypes(dtype_name: dtype.Dtype) -> None:
"""Test addition operation across all supported data types."""
check_type_supported(dtype_name)
shape = (5, 5) # Using a common shape for simplicity
lhs = wrapper.randu(shape, dtype_name)
rhs = wrapper.randu(shape, dtype_name)
result = wrapper.add(lhs, rhs)
assert dtype.c_api_value_to_dtype(wrapper.get_type(result)) == dtype_name, f"Failed for dtype: {dtype_name}"


@pytest.mark.parametrize(
"invdtypes",
[
dtype.c64,
dtype.f64,
],
)
def test_add_unsupported_dtypes(invdtypes: dtype.Dtype) -> None:
"""Test addition operation across all supported data types."""
with pytest.raises(RuntimeError):
shape = (5, 5)
lhs = wrapper.randu(shape, invdtypes)
rhs = wrapper.randu(shape, invdtypes)
result = wrapper.add(lhs, rhs)
assert dtype.c_api_value_to_dtype(wrapper.get_type(result)) == invdtypes, f"Didn't Fail for Dtype: {invdtypes}"


def test_add_zero_sized_arrays() -> None:
"""Test addition with arrays where at least one array has zero size."""
with pytest.raises(RuntimeError):
zero_shape = (0, 5)
normal_shape = (5, 5)
zero_array = wrapper.randu(zero_shape, dtype.f32)
normal_array = wrapper.randu(normal_shape, dtype.f32)

# Test addition when lhs is zero-sized
result_lhs_zero = wrapper.add(zero_array, normal_array)
assert wrapper.get_dims(result_lhs_zero) == zero_shape


@pytest.mark.parametrize(
"shape",
[
(),
(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), random.randint(1, 10)),
],
)
def test_subtract_shapes(shape: tuple) -> None:
"""Test subtraction operation between two arrays of the same shape"""
lhs = wrapper.randu(shape, dtype.f16)
rhs = wrapper.randu(shape, dtype.f16)

result = wrapper.sub(lhs, rhs)

assert wrapper.get_dims(result)[0 : len(shape)] == shape # noqa: E203, W291


def test_subtract_different_shapes() -> None:
"""Test if subtraction handles arrays of different shapes"""
with pytest.raises(RuntimeError):
lhs_shape = (2, 3)
rhs_shape = (3, 2)
dtypes = dtype.f16
lhs = wrapper.randu(lhs_shape, dtypes)
rhs = wrapper.randu(rhs_shape, dtypes)

wrapper.sub(lhs, rhs)


@pytest.mark.parametrize("dtype_name", get_all_types())
def test_subtract_supported_dtypes(dtype_name: dtype.Dtype) -> None:
"""Test subtraction operation across all supported data types."""
check_type_supported(dtype_name)
shape = (5, 5)
lhs = wrapper.randu(shape, dtype_name)
rhs = wrapper.randu(shape, dtype_name)
result = wrapper.sub(lhs, rhs)
assert dtype.c_api_value_to_dtype(wrapper.get_type(result)) == dtype_name, f"Failed for dtype: {dtype_name}"


@pytest.mark.parametrize(
"invdtypes",
[
dtype.c64,
dtype.f64,
],
)
def test_subtract_unsupported_dtypes(invdtypes: dtype.Dtype) -> None:
"""Test subtraction operation for unsupported data types."""
with pytest.raises(RuntimeError):
shape = (5, 5)
lhs = wrapper.randu(shape, invdtypes)
rhs = wrapper.randu(shape, invdtypes)
result = wrapper.sub(lhs, rhs)
assert result == invdtypes, f"Didn't Fail for Dtype: {invdtypes}"


def test_subtract_zero_sized_arrays() -> None:
"""Test subtraction with arrays where at least one array has zero size."""
with pytest.raises(RuntimeError):
zero_shape = (0, 5)
normal_shape = (5, 5)
zero_array = wrapper.randu(zero_shape, dtype.f32)
normal_array = wrapper.randu(normal_shape, dtype.f32)

result_lhs_zero = wrapper.sub(zero_array, normal_array)
assert wrapper.get_dims(result_lhs_zero) == zero_shape
31 changes: 15 additions & 16 deletions tests/test_trig.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

import arrayfire_wrapper.dtypes as dtype
import arrayfire_wrapper.lib as wrapper

from . import utility_functions as util
from tests.utility_functions import check_type_supported, get_all_types, get_float_types


@pytest.mark.parametrize(
Expand All @@ -18,10 +17,10 @@
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_all_types())
@pytest.mark.parametrize("dtype_name", get_all_types())
def test_asin_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test inverse sine operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
values = wrapper.randu(shape, dtype_name)
result = wrapper.asin(values)
assert wrapper.get_dims(result)[0 : len(shape)] == shape, f"failed for shape: {shape}" # noqa
Expand All @@ -37,10 +36,10 @@ def test_asin_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_all_types())
@pytest.mark.parametrize("dtype_name", get_all_types())
def test_acos_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test inverse cosine operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
values = wrapper.randu(shape, dtype_name)
result = wrapper.acos(values)
assert wrapper.get_dims(result)[0 : len(shape)] == shape, f"failed for shape: {shape}" # noqa
Expand All @@ -56,10 +55,10 @@ def test_acos_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_all_types())
@pytest.mark.parametrize("dtype_name", get_all_types())
def test_atan_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test inverse tan operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
values = wrapper.randu(shape, dtype_name)
result = wrapper.atan(values)
assert wrapper.get_dims(result)[0 : len(shape)] == shape, f"failed for shape: {shape}" # noqa
Expand All @@ -75,10 +74,10 @@ def test_atan_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_float_types())
@pytest.mark.parametrize("dtype_name", get_float_types())
def test_atan2_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test inverse tan operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
if dtype_name == dtype.f16:
pytest.skip()
lhs = wrapper.randu(shape, dtype_name)
Expand Down Expand Up @@ -110,10 +109,10 @@ def test_atan2_unsupported_dtypes(invdtypes: dtype.Dtype) -> None:
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_all_types())
@pytest.mark.parametrize("dtype_name", get_all_types())
def test_cos_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test cosine operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
values = wrapper.randu(shape, dtype_name)
result = wrapper.cos(values)
assert wrapper.get_dims(result)[0 : len(shape)] == shape, f"failed for shape: {shape}" # noqa
Expand All @@ -129,10 +128,10 @@ def test_cos_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_all_types())
@pytest.mark.parametrize("dtype_name", get_all_types())
def test_sin_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test sin operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
values = wrapper.randu(shape, dtype_name)
result = wrapper.sin(values)
assert wrapper.get_dims(result)[0 : len(shape)] == shape, f"failed for shape: {shape}" # noqa
Expand All @@ -148,10 +147,10 @@ def test_sin_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
(random.randint(1, 10), random.randint(1, 10), random.randint(1, 10), random.randint(1, 10)),
],
)
@pytest.mark.parametrize("dtype_name", util.get_all_types())
@pytest.mark.parametrize("dtype_name", get_all_types())
def test_tan_shape_dtypes(shape: tuple, dtype_name: dtype.Dtype) -> None:
"""Test tan operation across all supported data types."""
util.check_type_supported(dtype_name)
check_type_supported(dtype_name)
values = wrapper.randu(shape, dtype_name)
result = wrapper.tan(values)
assert wrapper.get_dims(result)[0 : len(shape)] == shape, f"failed for shape: {shape}" # noqa

0 comments on commit 7b8fe9e

Please sign in to comment.