From 951aee83807a84a927a7e7920083586d64870606 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 8 Feb 2024 02:08:38 +0200 Subject: [PATCH 1/6] Update tests. Add randn --- arrayfire/library/linear_algebra.py | 134 +++++++++++++++++++++- arrayfire/library/random.py | 46 ++++++++ requirements.txt | 2 +- tests/_helpers.py | 12 ++ tests/test_library/test_linear_algebra.py | 123 ++++++++++++++++++++ tests/test_library/test_random.py | 60 ++++++++++ 6 files changed, 372 insertions(+), 5 deletions(-) create mode 100644 tests/test_library/test_linear_algebra.py diff --git a/arrayfire/library/linear_algebra.py b/arrayfire/library/linear_algebra.py index 3e24c8c..543062e 100644 --- a/arrayfire/library/linear_algebra.py +++ b/arrayfire/library/linear_algebra.py @@ -29,11 +29,43 @@ def dot( lhs: Array, rhs: Array, /, - lhs_opts: MatProp = MatProp.NONE, - rhs_opts: MatProp = MatProp.NONE, *, return_scalar: bool = False, ) -> int | float | complex | Array: + """ + Calculates the dot product of two input arrays, with options to modify the operation + on the input arrays and the possibility to return the result as a scalar. + + Parameters + ---------- + lhs : Array + A 1-dimensional, int of float Array instance, representing an array. + + rhs : Array + A 1-dimensional, int of float Array instance, representing another array. + + return_scalar : bool, optional + When set to True, the input arrays are flattened, and the output is a scalar value. + Default is False. + + Returns + ------- + out : int | float | complex | Array + The result of the dot product. Returns an Array unless `return_scalar` is True, + in which case a scalar value (int, float, or complex) is returned based on the + data type of the inputs. + + Note + ----- + - The data types of `lhs` and `rhs` should be the same. + - Batch operations are not supported. + - Modification options for `lhs` and `rhs` are currently disabled as function supports only `MatProp.NONE`. + """ + # TODO + # Add support of lhs_opts and rhs_opts and return them as key arguments. + lhs_opts: MatProp = MatProp.NONE + rhs_opts: MatProp = MatProp.NONE + if return_scalar: return wrapper.dot_all(lhs.arr, rhs.arr, lhs_opts, rhs_opts) @@ -50,11 +82,105 @@ def gemm( alpha: int | float = 1.0, beta: int | float = 0.0, ) -> Array: + """ + Performs BLAS general matrix multiplication (GEMM) on two Array instances. + + The operation is defined as: C = alpha * op(lhs) * op(rhs) + beta * C, where op(X) is + one of no operation, transpose, or Hermitian transpose, determined by lhs_opts and rhs_opts. + + Parameters + ---------- + lhs : Array + A 2-dimensional, real or complex array representing the left-hand side matrix. + + rhs : Array + A 2-dimensional, real or complex array representing the right-hand side matrix. + + lhs_opts : MatProp, optional + Operation to perform on `lhs` before multiplication. Default is MatProp.NONE. Options include: + - MatProp.NONE: No operation. + - MatProp.TRANS: Transpose. + - MatProp.CTRANS: Hermitian transpose. + + rhs_opts : MatProp, optional + Operation to perform on `rhs` before multiplication. Default is MatProp.NONE. Options include: + - MatProp.NONE: No operation. + - MatProp.TRANS: Transpose. + - MatProp.CTRANS: Hermitian transpose. + + alpha : int | float, optional + Scalar multiplier for the product of `lhs` and `rhs`. Default is 1.0. + + beta : int | float, optional + Scalar multiplier for the existing matrix C in the accumulation. Default is 0.0. + + Returns + ------- + Array + The result of the matrix multiplication operation. + + Note + ----- + - The data types of `lhs` and `rhs` must be compatible. + - Batch operations are not supported in this version. + """ return cast(Array, wrapper.gemm(lhs.arr, rhs.arr, lhs_opts, rhs_opts, alpha, beta)) @afarray_as_array def matmul(lhs: Array, rhs: Array, /, lhs_opts: MatProp = MatProp.NONE, rhs_opts: MatProp = MatProp.NONE) -> Array: + """ + Performs generalized matrix multiplication between two arrays with optional + transposition or hermitian transposition operations on the input matrices. + + Parameters + ---------- + lhs : af.Array + A 2-dimensional, real or complex ArrayFire array representing the left-hand side matrix. + + rhs : af.Array + A 2-dimensional, real or complex ArrayFire array representing the right-hand side matrix. + + lhs_opts : af.MATPROP, optional + Operation to perform on the `lhs` matrix before multiplication. Defaults to af.MATPROP.NONE. + Options include: + - af.MATPROP.NONE: No operation. + - af.MATPROP.TRANS: Transpose `lhs`. + - af.MATPROP.CTRANS: Hermitian transpose (conjugate transpose) `lhs`. + + rhs_opts : af.MATPROP, optional + Operation to perform on the `rhs` matrix before multiplication. Defaults to af.MATPROP.NONE. + Options include: + - af.MATPROP.NONE: No operation. + - af.MATPROP.TRANS: Transpose `rhs`. + - af.MATPROP.CTRANS: Hermitian transpose (conjugate transpose) `rhs`. + + Returns + ------- + out : af.Array + The result of the matrix multiplication. The output is a 2-dimensional ArrayFire array. + + Notes + ----- + - The data types of `lhs` and `rhs` must be the same. + - Batch operations (multiplying multiple pairs of matrices at once) are not supported in this implementation. + + Examples + -------- + Basic matrix multiplication: + + A = af.randu(5, 4, dtype=af.Dtype.f32) + B = af.randu(4, 6, dtype=af.Dtype.f32) + C = matmul(A, B) + + Matrix multiplication with the left-hand side transposed: + + C = matmul(A, B, lhs_opts=af.MATPROP.TRANS) + + Matrix multiplication with both matrices transposed: + + C = matmul(A, B, lhs_opts=af.MATPROP.TRANS, rhs_opts=af.MATPROP.TRANS) + """ return cast(Array, wrapper.matmul(lhs.arr, rhs.arr, lhs_opts, rhs_opts)) @@ -121,5 +247,5 @@ def solve(a: Array, b: Array, /, *, options: MatProp = MatProp.NONE, pivot: None return cast(Array, wrapper.solve(a.arr, b.arr, options)) -# TODO -# Add Sparse functions? #good_first_issue +# TODO #good_first_issue +# Add Sparse functions diff --git a/arrayfire/library/random.py b/arrayfire/library/random.py index 88d6353..5f98193 100644 --- a/arrayfire/library/random.py +++ b/arrayfire/library/random.py @@ -131,6 +131,52 @@ def from_engine(cls, engine: wrapper.AFRandomEngineHandle) -> RandomEngine: return instance +@afarray_as_array +def randn(shape: tuple[int, ...], /, *, dtype: Dtype = float32, engine: RandomEngine | None = None) -> Array: + """ + Create a multi-dimensional array containing values sampled from a normal distribution with mean 0 + and standard deviation of 1. + + Parameters + ---------- + shape : tuple[int, ...] + The shape of the resulting array. Must be a tuple with at least one element, e.g., shape=(3,). + + dtype : Dtype, optional, default: `float32` + The data type of the array elements. + + engine : RandomEngine | None, optional + The random number generator engine to be used. If None, uses a default engine created by ArrayFire. + + Returns + ------- + Array + A multi-dimensional array whose elements are sampled from a normal distribution. The dimensions of the array + are determined by `shape`: + - If shape is (x,), the output is a 1D array of size (x,). + - If shape is (x, y), the output is a 2D array of size (x, y). + - If shape is (x, y, z), the output is a 3D array of size (x, y, z). + - For more dimensions, the output shape corresponds directly to the specified `shape` tuple. + + Notes + ----- + The function supports creating arrays of up to N dimensions, where N is determined by the length + of the `shape` tuple. + + Raises + ------ + ValueError + If `shape` is not a tuple or has less than one value. + """ + if not isinstance(shape, tuple) or not shape: + raise ValueError("Argument shape must be a tuple with at least 1 value.") + + if engine is None: + return cast(Array, wrapper.randn(shape, dtype)) + + return cast(Array, wrapper.random_normal(shape, dtype, engine.get_engine())) + + @afarray_as_array def randu(shape: tuple[int, ...], /, *, dtype: Dtype = float32, engine: RandomEngine | None = None) -> Array: """ diff --git a/requirements.txt b/requirements.txt index a1bb95b..23e82e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -arrayfire-python-wrapper==0.5.0+af3.9.0 +arrayfire-binary-python-wrapper==0.6.0+af3.9.0 diff --git a/tests/_helpers.py b/tests/_helpers.py index 038062e..c508455 100644 --- a/tests/_helpers.py +++ b/tests/_helpers.py @@ -1,3 +1,15 @@ +import arrayfire as af + + def round_to(list_: list[int | float | complex | bool], symbols: int = 3) -> list[int | float]: # HACK replace for e.g. abs(x1-x2) < 1e-6 ~ https://davidamos.dev/the-right-way-to-compare-floats-in-python/ return [round(x, symbols) for x in list_] + + +def create_from_2d_nested(x1: float, x2: float, x3: float, x4: float, dtype: af.Dtype = af.float32) -> af.Array: + array = af.randu((2, 2), dtype=dtype) + array[0, 0] = x1 + array[0, 1] = x2 + array[1, 0] = x3 + array[1, 1] = x4 + return array diff --git a/tests/test_library/test_linear_algebra.py b/tests/test_library/test_linear_algebra.py new file mode 100644 index 0000000..19b1cb2 --- /dev/null +++ b/tests/test_library/test_linear_algebra.py @@ -0,0 +1,123 @@ +import pytest + +import arrayfire as af +from tests._helpers import create_from_2d_nested + +# Test dot + + +@pytest.fixture +def real_vector_1() -> af.Array: + return af.Array([1.0, 2.0, 3.0]) + + +@pytest.fixture +def real_vector_2() -> af.Array: + return af.Array([4.0, 5.0, 6.0]) + + +@pytest.fixture +def float_vector_1() -> af.Array: + return af.Array([1.5, 2.5, 3.5]) + + +@pytest.fixture +def float_vector_2() -> af.Array: + return af.Array([4.5, 5.5, 6.5]) + + +def test_dot_real_vectors(real_vector_1: af.Array, real_vector_2: af.Array) -> None: + expected = 32 # Calculated manually or using a trusted library + result = af.dot(real_vector_1, real_vector_2) + assert result == expected, f"Expected {expected}, got {result}" + + +def test_dot_float_vectors(float_vector_1: af.Array, float_vector_2: af.Array) -> None: + expected = 61.5 # Calculated manually or using a trusted library + result = af.dot(float_vector_1, float_vector_2) + assert result == expected, f"Expected {expected}, got {result}" + + +def test_dot_return_scalar(real_vector_1: af.Array, real_vector_2: af.Array) -> None: + result = af.dot(real_vector_1, real_vector_2, return_scalar=True) + assert isinstance(result, (int, float)), "Result is not a scalar" + + +# Test gemm + + +@pytest.fixture +def matrix_a() -> af.Array: + return create_from_2d_nested(1, 2, 3, 4) + + +@pytest.fixture +def matrix_b() -> af.Array: + return create_from_2d_nested(5, 6, 7, 8) + + +def test_gemm_basic(matrix_a: af.Array, matrix_b: af.Array) -> None: + result = af.gemm(matrix_a, matrix_b) + expected = create_from_2d_nested(19.0, 22.0, 43.0, 50.0) + assert result == expected, f"Expected {expected}, got {result}" + + +def test_gemm_alpha_beta(matrix_a: af.Array, matrix_b: af.Array) -> None: + alpha = 0.5 + beta = 2.0 + result = af.gemm(matrix_a, matrix_b, alpha=alpha, beta=beta) + expected = create_from_2d_nested(10.5, 12.0, 22.5, 26.0) + assert result == expected, f"Expected {expected}, got {result}" + + +def test_gemm_transpose_options(matrix_a: af.Array, matrix_b: af.Array) -> None: + result = af.gemm(matrix_a, matrix_b, lhs_opts=af.MatProp.TRANS, rhs_opts=af.MatProp.TRANS) + expected = create_from_2d_nested(23.0, 31.0, 34.0, 46.0) + assert result == expected, f"Expected {expected}, got {result}" + + +# Test matmul + + +def test_basic_matrix_multiplication() -> None: + A = af.randu((3, 2), dtype=af.float32) + B = af.randu((2, 4), dtype=af.float32) + C = af.matmul(A, B) + assert C.shape == (3, 4), "Output dimensions should be 3x4." + + +def test_matrix_multiplication_with_lhs_transposed() -> None: + A = af.randu((2, 3), dtype=af.float32) # Transposing makes it 3x2 + B = af.randu((2, 4), dtype=af.float32) + C = af.matmul(A, B, lhs_opts=af.MatProp.TRANS) + assert C.shape == (3, 4), "Output dimensions should be 3x4 when lhs is transposed." + + +def test_matrix_multiplication_with_both_transposed() -> None: + A = af.randu((4, 3), dtype=af.float32) # Transposing makes it 3x4 + B = af.randu((6, 4), dtype=af.float32) # Transposing makes it 4x6 + C = af.matmul(A, B, lhs_opts=af.MatProp.TRANS, rhs_opts=af.MatProp.TRANS) + assert C.shape == (3, 6), "Output dimensions should be 3x6 with both matrices transposed." + + +# BUG +# def test_incompatible_dimensions() -> None: +# A = af.randu((3, 5), dtype=af.float32) +# B = af.randu((4, 6), dtype=af.float32) +# with pytest.raises(ValueError): +# C = af.matmul(A, B) + + +# def test_unsupported_data_type() -> None: +# A = af.Array([1, 2, 3], dtype=af.uint32) # Assuming unsupported data type like unsigned int +# B = af.Array([4, 5, 6], dtype=af.uint32) +# with pytest.raises(TypeError): +# C = af.matmul(A, B) + + +# def test_multiplication_result_verification() -> None: +# A = create_from_2d_nested(1, 2, 3, 4) +# B = create_from_2d_nested(5, 6, 7, 8) +# C = af.matmul(A, B) +# expected = create_from_2d_nested(19, 22, 43, 50) +# assert af.all_true(C == expected), "The multiplication result is incorrect." diff --git a/tests/test_library/test_random.py b/tests/test_library/test_random.py index 6bbad59..6362718 100644 --- a/tests/test_library/test_random.py +++ b/tests/test_library/test_random.py @@ -91,3 +91,63 @@ def test_randu_invalid_shape_type() -> None: with pytest.raises(ValueError): shape = [5, 5] random.randu(shape) # type: ignore[arg-type] + + +# Test cases for the randn function + + +def test_randn_shape_1d() -> None: + shape = (10,) + result: Array = random.randn(shape) + assert isinstance(result, Array) + assert result.shape == shape + + +def test_randn_shape_2d() -> None: + shape = (5, 7) + result: Array = random.randn(shape) + assert isinstance(result, Array) + assert result.shape == shape + + +def test_randn_shape_3d() -> None: + shape = (3, 4, 6) + result: Array = random.randn(shape) + assert isinstance(result, Array) + assert result.shape == shape + + +def test_randn_shape_4d() -> None: + shape = (2, 2, 3, 5) + result: Array = random.randn(shape) + assert isinstance(result, Array) + assert result.shape == shape + + +def test_randn_default_engine() -> None: + shape = (5, 5) + result: Array = random.randn(shape) + assert isinstance(result, Array) + assert result.shape == shape + + +def test_randn_custom_engine() -> None: + shape = (3, 3) + custom_engine = RandomEngine(RandomEngineType.THREEFRY, seed=42) + result: Array = random.randn(shape, engine=custom_engine) + assert isinstance(result, Array) + assert result.shape == shape + + +def test_randn_invalid_shape() -> None: + # Test with an invalid shape (empty tuple) + with pytest.raises(ValueError): + shape = () + random.randn(shape) + + +def test_randn_invalid_shape_type() -> None: + # Test with an invalid shape (non-tuple) + with pytest.raises(ValueError): + shape = [5, 5] + random.randn(shape) # type: ignore[arg-type] From 960e310411f56c9e143a15298e2d3c09eba5f10b Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Thu, 8 Feb 2024 03:47:09 +0200 Subject: [PATCH 2/6] Fix import. Fix tests. Fix backend imports --- arrayfire/__init__.py | 4 +- arrayfire/library/unified_api_functions.py | 37 +++++++------- tests/test_library/test_random.py | 59 +++++++++++----------- 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 36fbc3f..cca8929 100755 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -533,9 +533,9 @@ trunc, ) -__all__ += ["randu"] +__all__ += ["randn", "randu"] -from arrayfire.library.random import randu +from arrayfire.library.random import randn, randu __all__ += [ "fft", diff --git a/arrayfire/library/unified_api_functions.py b/arrayfire/library/unified_api_functions.py index 8922d55..1894b4d 100644 --- a/arrayfire/library/unified_api_functions.py +++ b/arrayfire/library/unified_api_functions.py @@ -1,23 +1,26 @@ -__all__ = [ - "get_active_backend", - "get_available_backends", - "get_backend_count", - "get_backend_id", - "get_device_id", - "set_backend", -] +# TODO +# Temp solution. Remove when arrayfire-binary-python-wrapper is finalized -from arrayfire_wrapper.lib import get_active_backend, get_available_backends, get_backend_count -from arrayfire_wrapper.lib import get_backend_id as wrapped_get_backend_id -from arrayfire_wrapper.lib import get_device_id as wrapped_get_device_id -from arrayfire_wrapper.lib import set_backend +# __all__ = [ +# "get_active_backend", +# "get_available_backends", +# "get_backend_count", +# "get_backend_id", +# "get_device_id", +# "set_backend", +# ] -from arrayfire import Array +# from arrayfire_wrapper.lib import get_active_backend, get_available_backends, get_backend_count +# from arrayfire_wrapper.lib import get_backend_id as wrapped_get_backend_id +# from arrayfire_wrapper.lib import get_device_id as wrapped_get_device_id +# from arrayfire_wrapper.lib import set_backend +# from arrayfire import Array -def get_backend_id(array: Array) -> int: - return wrapped_get_backend_id(array.arr) +# def get_backend_id(array: Array) -> int: +# return wrapped_get_backend_id(array.arr) -def get_device_id(array: Array) -> int: - return wrapped_get_device_id(array.arr) + +# def get_device_id(array: Array) -> int: +# return wrapped_get_device_id(array.arr) diff --git a/tests/test_library/test_random.py b/tests/test_library/test_random.py index 6362718..3f202d6 100644 --- a/tests/test_library/test_random.py +++ b/tests/test_library/test_random.py @@ -1,8 +1,7 @@ import pytest from arrayfire_wrapper.lib import create_random_engine -from arrayfire import Array -from arrayfire.library import random +import arrayfire as af from arrayfire.library.random import RandomEngine, RandomEngineType # Test cases for the Random Engine @@ -38,44 +37,44 @@ def test_random_engine_deletion() -> None: def test_randu_shape_1d() -> None: shape = (10,) - result: Array = random.randu(shape) - assert isinstance(result, Array) + result: af.Array = af.randu(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randu_shape_2d() -> None: shape = (5, 7) - result: Array = random.randu(shape) - assert isinstance(result, Array) + result: af.Array = af.randu(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randu_shape_3d() -> None: shape = (3, 4, 6) - result: Array = random.randu(shape) - assert isinstance(result, Array) + result: af.Array = af.randu(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randu_shape_4d() -> None: shape = (2, 2, 3, 5) - result: Array = random.randu(shape) - assert isinstance(result, Array) + result: af.Array = af.randu(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randu_default_engine() -> None: shape = (5, 5) - result: Array = random.randu(shape) - assert isinstance(result, Array) + result: af.Array = af.randu(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randu_custom_engine() -> None: shape = (3, 3) custom_engine = RandomEngine(RandomEngineType.THREEFRY, seed=42) - result: Array = random.randu(shape, engine=custom_engine) - assert isinstance(result, Array) + result: af.Array = af.randu(shape, engine=custom_engine) + assert isinstance(result, af.Array) assert result.shape == shape @@ -83,14 +82,14 @@ def test_randu_invalid_shape() -> None: # Test with an invalid shape (empty tuple) with pytest.raises(ValueError): shape = () - random.randu(shape) + af.randu(shape) def test_randu_invalid_shape_type() -> None: # Test with an invalid shape (non-tuple) with pytest.raises(ValueError): shape = [5, 5] - random.randu(shape) # type: ignore[arg-type] + af.randu(shape) # type: ignore[arg-type] # Test cases for the randn function @@ -98,44 +97,44 @@ def test_randu_invalid_shape_type() -> None: def test_randn_shape_1d() -> None: shape = (10,) - result: Array = random.randn(shape) - assert isinstance(result, Array) + result: af.Array = af.randn(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randn_shape_2d() -> None: shape = (5, 7) - result: Array = random.randn(shape) - assert isinstance(result, Array) + result: af.Array = af.randn(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randn_shape_3d() -> None: shape = (3, 4, 6) - result: Array = random.randn(shape) - assert isinstance(result, Array) + result: af.Array = af.randn(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randn_shape_4d() -> None: shape = (2, 2, 3, 5) - result: Array = random.randn(shape) - assert isinstance(result, Array) + result: af.Array = af.randn(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randn_default_engine() -> None: shape = (5, 5) - result: Array = random.randn(shape) - assert isinstance(result, Array) + result: af.Array = af.randn(shape) + assert isinstance(result, af.Array) assert result.shape == shape def test_randn_custom_engine() -> None: shape = (3, 3) custom_engine = RandomEngine(RandomEngineType.THREEFRY, seed=42) - result: Array = random.randn(shape, engine=custom_engine) - assert isinstance(result, Array) + result: af.Array = af.randn(shape, engine=custom_engine) + assert isinstance(result, af.Array) assert result.shape == shape @@ -143,11 +142,11 @@ def test_randn_invalid_shape() -> None: # Test with an invalid shape (empty tuple) with pytest.raises(ValueError): shape = () - random.randn(shape) + af.randn(shape) def test_randn_invalid_shape_type() -> None: # Test with an invalid shape (non-tuple) with pytest.raises(ValueError): shape = [5, 5] - random.randn(shape) # type: ignore[arg-type] + af.randn(shape) # type: ignore[arg-type] From 1f6879286cd91814e02b827e31b151332a304a1d Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Thu, 8 Feb 2024 03:54:15 +0200 Subject: [PATCH 3/6] Fix licence --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e519b47..7f92de2 100644 --- a/setup.py +++ b/setup.py @@ -68,7 +68,7 @@ def fix_url_dependencies(req: str) -> str: name="arrayfire", version=VERSION["VERSION"], description="ArrayFire Python Wrapper", - licence="BSD", + license="BSD", long_description=(ABS_PATH / "README.md").open("r").read(), long_description_content_type="text/markdown", author="ArrayFire", From dece02d654df3aa7c8116443f544b9a279a89d74 Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Thu, 8 Feb 2024 04:18:53 +0200 Subject: [PATCH 4/6] Fix imports --- arrayfire/__init__.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index cca8929..8d67389 100755 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -591,23 +591,26 @@ from arrayfire.library.statistics import corrcoef, cov, mean, median, stdev, topk, var -__all__ += [ - "get_active_backend", - "get_available_backends", - "get_backend_count", - "get_backend_id", - "get_device_id", - "set_backend", -] - -from arrayfire.library.unified_api_functions import ( - get_active_backend, - get_available_backends, - get_backend_count, - get_backend_id, - get_device_id, - set_backend, -) +# TODO +# Temp solution. Remove when arrayfire-binary-python-wrapper is finalized + +# __all__ += [ +# "get_active_backend", +# "get_available_backends", +# "get_backend_count", +# "get_backend_id", +# "get_device_id", +# "set_backend", +# ] + +# from arrayfire.library.unified_api_functions import ( +# get_active_backend, +# get_available_backends, +# get_backend_count, +# get_backend_id, +# get_device_id, +# set_backend, +# ) __all__ += [ "accum", From f9fc9506966be9230ba9e9d819dd95b558dd7ee9 Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Thu, 8 Feb 2024 05:33:31 +0200 Subject: [PATCH 5/6] Add newer backend imports --- arrayfire/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 8d67389..0f8d850 100755 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -659,3 +659,9 @@ __all__ += ["cast"] from arrayfire.library.utils import cast + +# Backend + +__all__ += ["set_backend", "get_backend", "BackendType"] + +from arrayfire_wrapper import BackendType, get_backend, set_backend From a814a133cea4bf402041e669fc4bffc6b1f55562 Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Thu, 8 Feb 2024 06:12:30 +0200 Subject: [PATCH 6/6] Fix eval --- arrayfire/library/array_functions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/arrayfire/library/array_functions.py b/arrayfire/library/array_functions.py index 2f80510..2613626 100644 --- a/arrayfire/library/array_functions.py +++ b/arrayfire/library/array_functions.py @@ -241,6 +241,7 @@ def copy_array(array: Array, /) -> Array: def eval(*arrays: Array) -> None: if len(arrays) == 1: wrapper.eval(arrays[0].arr) + return arrs = [array.arr for array in arrays] wrapper.eval_multiple(len(arrays), *arrs)