diff --git a/.flake8 b/.flake8
index 0d726f9..2760c29 100755
--- a/.flake8
+++ b/.flake8
@@ -8,4 +8,6 @@ max-line-length = 119
exclude =
.venv/**
build/**
- benchmarks/**
\ No newline at end of file
+ benchmarks/**
+ docs/*
+ tests/test_documentation/test_documentation.py
diff --git a/README.md b/README.md
index 81a3f90..decf586 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,107 @@
-# arrayfire-py
-
-Arrayfire python wrapper
-
-## Coverage
-
-- [x] Computer Vision
-- [] Events
-- [x] Functions to Create and Modify Arrays
-- [x] Functions to Work with Internal Array Layout
-- [x] Image Processing
- - [x] Features
-- [x] Input and Output Functions
-- [x] Interface Functions
-- [x] Linear Algebra
-- [x] Machine Learning
-- [x] Mathematical Functions
-- [x] Signal Processing
-- [x] Statistics
-- [x] Unified API Functions
-- [x] Vector Algorithms
+# arrayfire-python (WIP)
+

+
+[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices.
+
+This project is a **work in progress**. It is meant to provide a numpy-like Python interface for the ArrayFire C library, i.e, it provides array functionality, math operations, printing, etc. This is the front-end python library for using ArrayFire. It is currently supported on Python 3.10+.
+
+Here is an example of the library at work:
+```py
+# Set backend and device (optional: 'cuda', 'opencl', 'oneapi', 'cpu')
+af.setBackend(af.BackendType.cuda)
+af.setDevice(0)
+
+# Create two 5x5 arrays on the GPU
+a = af.randu((5, 5))
+b = af.randu((5, 5))
+
+# Perform element-wise addition and matrix multiplication
+c = a + b
+d = af.matmul(a, b)
+
+# Print the result
+print(c, "Element-wise Sum")
+print(d, "Matrix Product")
+```
+
+# Installing
+
+**Requirement Details**
+This project is separated into 3 different parts:
+```
+arrayfire-py -> arrayfire-binary-python-wrapper -> ArrayFire C Libraries
+```
+This means that arrayfire with python each of these parts is needed:
+- [`arrayfire-py`](https://github.com/arrayfire/arrayfire-python) is the intended User Interface that provides a numpy-like layer to execute math and array operations with ArrayFire. *** This is the preferred Interface ***
+- [`arrayfire-binary-python-wrapper`](https://github.com/arrayfire/arrayfire-binary-python-wrapper) is the wrapper that provides Python direct access to the ArrayFire functions in the C library. This package must have access to ArrayFire binaries.
+- [`ArrayFire C Libraries`](https://github.com/arrayfire/arrayfire) are the binaries obtained from compiling the [ArrayFire C/C++ Project](https://github.com/arrayfire/arrayfire). You obtain these easily through [installers in the ArrayFire download page](https://arrayfire.com/download/).
+
+**Install the last stable version of python wrapper:**
+```sh
+pip install arrayfire_binary_python_wrapper-0.8.0+af3.10.0-py3-none-linux_x86_64.whl # install required binary wrapper with the 3.10 ArrayFire binaries included
+pip install arrayfire-py # install arrayfire python interface library
+```
+
+**Install a pre-built wheel:**
+```
+pip install arrayfire-py -f https://repo.arrayfire.com/python/wheels/arrayfire-python/0.1.0
+```
+
+# Building
+Building this interface is straight forward using [scikit-build-core](https://github.com/scikit-build/scikit-build-core):
+```
+python -m pip install -r dev-requirements.txt
+python -m build --wheel
+```
+
+**Note: Building this project does not require the arrayfire-binary-python-wrapper package; however, the binary wrapper is needed to run any projects with it**
+
+# Running Tests
+
+Tests are located in folder [tests](tests).
+
+To run the tests, use:
+```bash
+python -m pytest tests/
+```
+
+# Contributing
+
+If you are interested in using ArrayFire through python, we would appreciate any feedback and contributions.
+
+The community of ArrayFire developers invites you to build with us if you are
+interested and able to write top-performing tensor functions. Together we can
+fulfill [The ArrayFire
+Mission](https://github.com/arrayfire/arrayfire/wiki/The-ArrayFire-Mission-Statement)
+for fast scientific computing for all.
+
+Contributions of any kind are welcome! Please refer to [the
+wiki](https://github.com/arrayfire/arrayfire/wiki) and our [Code of
+Conduct](33) to learn more about how you can get involved with the ArrayFire
+Community through
+[Sponsorship](https://github.com/arrayfire/arrayfire/wiki/Sponsorship),
+[Developer
+Commits](https://github.com/arrayfire/arrayfire/wiki/Contributing-Code-to-ArrayFire),
+or [Governance](https://github.com/arrayfire/arrayfire/wiki/Governance).
+
+# Citations and Acknowledgements
+
+If you redistribute ArrayFire, please follow the terms established in [the
+license](LICENSE).
+
+ArrayFire development is funded by AccelerEyes LLC and several third parties,
+please see the list of [acknowledgements](ACKNOWLEDGEMENTS.md) for an
+expression of our gratitude.
+
+# Support and Contact Info
+
+* [Slack Chat](https://join.slack.com/t/arrayfire-org/shared_invite/MjI4MjIzMDMzMTczLTE1MDI5ODg4NzYtN2QwNGE3ODA5OQ)
+* [Google Groups](https://groups.google.com/forum/#!forum/arrayfire-users)
+* ArrayFire Services: [Consulting](http://arrayfire.com/consulting) | [Support](http://arrayfire.com/download) | [Training](http://arrayfire.com/training)
+
+# Trademark Policy
+
+The literal mark "ArrayFire" and ArrayFire logos are trademarks of AccelerEyes
+LLC (dba ArrayFire). If you wish to use either of these marks in your own
+project, please consult [ArrayFire's Trademark
+Policy](http://arrayfire.com/trademark-policy/)
diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py
index 7a5c4a3..9cefbea 100755
--- a/arrayfire/__init__.py
+++ b/arrayfire/__init__.py
@@ -103,8 +103,6 @@
from arrayfire.library.array_functions import (
constant,
- zeros,
- ones,
copy_array,
diag,
eval,
@@ -119,17 +117,19 @@
lookup,
lower,
moddims,
- reshape,
+ ones,
pad,
range,
reorder,
replace,
+ reshape,
select,
set_manual_eval_flag,
shift,
tile,
transpose,
upper,
+ zeros,
)
__all__ += ["gloh", "orb", "sift", "dog", "fast", "harris", "susan", "hamming_matcher", "nearest_neighbour"]
diff --git a/arrayfire/array_object.py b/arrayfire/array_object.py
index 3cb49ea..361eab2 100755
--- a/arrayfire/array_object.py
+++ b/arrayfire/array_object.py
@@ -758,10 +758,10 @@ def __getitem__(self, key: IndexKey, /) -> Array:
ndims = self.ndim
indexing = key
-
- if isinstance(key, int | float | slice): # when indexing with one dimension, treat it as indexing a flat array
+
+ if isinstance(key, int | float | slice): # when indexing with one dimension, treat it as indexing a flat array
ndims = 1
- elif isinstance(key, Array): # when indexing with one array, treat it as indexing a flat array
+ elif isinstance(key, Array): # when indexing with one array, treat it as indexing a flat array
ndims = 1
if key.is_bool:
indexing = wrapper.where(key.arr)
@@ -836,9 +836,9 @@ def __setitem__(self, key: IndexKey, value: int | float | bool | Array, /) -> No
del_other = False
indexing = key
- if isinstance(key, int | float | slice): # when indexing with one dimension, treat it as indexing a flat array
+ if isinstance(key, int | float | slice): # when indexing with one dimension, treat it as indexing a flat array
ndims = 1
- elif isinstance(key, Array): # when indexing with one array, treat it as indexing a flat array
+ elif isinstance(key, Array): # when indexing with one array, treat it as indexing a flat array
ndims = 1
if key.is_bool:
indexing = wrapper.where(key.arr)
@@ -930,7 +930,8 @@ def T(self) -> Array:
Note
----
- - The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised.
+ - The array instance must be two-dimensional. If the array instance is not two-dimensional,
+ | an error should be raised.
"""
if self.ndim < 2:
@@ -949,11 +950,13 @@ def H(self) -> Array:
-------
Array
Two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to
- original array with its elements complex conjugated. The returned array must have the same data type as the original array.
+ | original array with its elements complex conjugated.
+ | The returned array must have the same data type as the original array.
Note
----
- - The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised.
+ - The array instance must be two-dimensional. If the array instance is not two-dimensional,
+ | an error should be raised.
"""
if self.ndim < 2:
@@ -1191,7 +1194,8 @@ def reshape(self, shape) -> Array:
-------
out : af.Array
- An array containing the same data as `array` with the specified shape.
- - The total number of elements in `array` must match the product of the dimensions specified in the `shape` tuple.
+ - The total number of elements in `array` must match the product of the dimensions
+ | specified in the `shape` tuple.
Raises
------
diff --git a/arrayfire/library/array_functions.py b/arrayfire/library/array_functions.py
index cc2d9e9..1c905fc 100644
--- a/arrayfire/library/array_functions.py
+++ b/arrayfire/library/array_functions.py
@@ -73,6 +73,7 @@ def constant(scalar: int | float | complex, shape: tuple[int, ...] = (1,), dtype
"""
return cast(Array, wrapper.create_constant_array(scalar, shape, dtype))
+
def zeros(shape: tuple[int, ...], dtype: Dtype = float32) -> Array:
"""
Create a multi-dimensional array filled with zeros
@@ -100,6 +101,7 @@ def zeros(shape: tuple[int, ...], dtype: Dtype = float32) -> Array:
"""
return constant(0, shape, dtype)
+
def ones(shape: tuple[int, ...], dtype: Dtype = float32) -> Array:
"""
Create a multi-dimensional array filled with ones
@@ -127,6 +129,7 @@ def ones(shape: tuple[int, ...], dtype: Dtype = float32) -> Array:
"""
return constant(1, shape, dtype)
+
@afarray_as_array
def diag(array: Array, /, *, diag_index: int = 0, extract: bool = True) -> Array:
"""
@@ -311,7 +314,8 @@ def lower(array: Array, /, *, is_unit_diag: bool = False) -> Array:
Notes
-----
- The function does not alter the elements above the main diagonal; it simply does not include them in the output.
- - This function can be useful for mathematical operations that require lower triangular matrices, such as certain types of matrix factorizations.
+ - This function can be useful for mathematical operations that require lower triangular matrices,
+ | such as certain types of matrix factorizations.
Examples
--------
@@ -367,7 +371,8 @@ def upper(array: Array, /, *, is_unit_diag: bool = False) -> Array:
Notes
-----
- The function does not alter the elements below the main diagonal; it simply does not include them in the output.
- - This function can be useful for mathematical operations that require upper triangular matrices, such as certain types of matrix factorizations.
+ - This function can be useful for mathematical operations that require upper triangular matrices,
+ | such as certain types of matrix factorizations.
Examples
--------
@@ -872,6 +877,7 @@ def moddims(array: Array, shape: tuple[int, ...], /) -> Array:
# TODO add examples to doc
return cast(Array, wrapper.moddims(array.arr, shape))
+
def reshape(array: Array, shape: tuple[int, ...], /) -> Array:
"""
Modify the shape of the array without changing the data layout.
@@ -907,6 +913,7 @@ def reshape(array: Array, shape: tuple[int, ...], /) -> Array:
"""
return moddims(array, shape)
+
@afarray_as_array
def reorder(array: Array, /, *, shape: tuple[int, ...] = (1, 0, 2, 3)) -> Array:
"""
diff --git a/arrayfire/library/computer_vision.py b/arrayfire/library/computer_vision.py
index 2e6de41..647fd9b 100644
--- a/arrayfire/library/computer_vision.py
+++ b/arrayfire/library/computer_vision.py
@@ -164,7 +164,8 @@ def sift(
tuple[Features, Array]
A tuple containing:
- An ArrayFire Features object encapsulating the detected keypoints.
- - An ArrayFire Array containing the corresponding descriptors for each keypoint. The descriptors are 128-dimensional vectors describing the local appearance around each keypoint.
+ - An ArrayFire Array containing the corresponding descriptors for each keypoint.
+ | The descriptors are 128-dimensional vectors describing the local appearance around each keypoint.
Note
----
diff --git a/arrayfire/library/linear_algebra.py b/arrayfire/library/linear_algebra.py
index 67109f2..3decc29 100644
--- a/arrayfire/library/linear_algebra.py
+++ b/arrayfire/library/linear_algebra.py
@@ -92,7 +92,7 @@ def gemm(
rhs_opts: MatProp = MatProp.NONE,
alpha: int | float = 1.0,
beta: int | float = 0.0,
- accum: Array = None
+ accum: Array = None,
) -> Array:
"""
Performs BLAS general matrix multiplication (GEMM) on two Array instances.
diff --git a/benchmarks/README.md b/benchmarks/README.md
new file mode 100644
index 0000000..30894ce
--- /dev/null
+++ b/benchmarks/README.md
@@ -0,0 +1,8 @@
+# Benchmarks Results
+Here are some graphs comparing ArrayFire Python against other packages for some common operations:
+
+
+
+
+
+These graphs were generated with this benchmark code using the ArrayFire C Libraries v3.10
\ No newline at end of file
diff --git a/benchmarks/img/comparison_afcuda_t4.png b/benchmarks/img/comparison_afcuda_t4.png
new file mode 100644
index 0000000..e9c90e8
Binary files /dev/null and b/benchmarks/img/comparison_afcuda_t4.png differ
diff --git a/benchmarks/img/comparison_afoneapi_b580.png b/benchmarks/img/comparison_afoneapi_b580.png
new file mode 100644
index 0000000..6097b60
Binary files /dev/null and b/benchmarks/img/comparison_afoneapi_b580.png differ
diff --git a/benchmarks/img/comparison_afopencl_b580.png b/benchmarks/img/comparison_afopencl_b580.png
new file mode 100644
index 0000000..5f624fc
Binary files /dev/null and b/benchmarks/img/comparison_afopencl_b580.png differ
diff --git a/benchmarks/img/comparison_afopencl_t4.png b/benchmarks/img/comparison_afopencl_t4.png
new file mode 100644
index 0000000..a8b62a1
Binary files /dev/null and b/benchmarks/img/comparison_afopencl_t4.png differ
diff --git a/docs/afjit.py b/docs/afjit.py
index de40c05..1557c19 100644
--- a/docs/afjit.py
+++ b/docs/afjit.py
@@ -5,13 +5,15 @@
# removed, then the execution of this code would be equivalent to the
# following function.
-import arrayfire as af
import time
+import arrayfire as af
+
samples = int(9e8)
x = af.randu((samples))
y = af.randu((samples))
+
def pi_no_jit(x, y, samples):
temp = x * x
af.eval(temp)
@@ -23,11 +25,13 @@ def pi_no_jit(x, y, samples):
af.eval(temp)
return 4.0 * af.sum(temp) / samples
+
def pi_jit(x, y, samples):
temp = af.sqrt(x * x + y * y) < 1
af.eval(temp)
return 4.0 * af.sum(temp) / samples
+
# Print device info
af.info()
@@ -47,4 +51,4 @@ def pi_jit(x, y, samples):
end = time.perf_counter()
print("no jit:", end - start, res)
-# [jit-endsnippet]
\ No newline at end of file
+# [jit-endsnippet]
diff --git a/docs/arrayandmatrixmanipulation.py b/docs/arrayandmatrixmanipulation.py
index 55d5f77..db8bd68 100644
--- a/docs/arrayandmatrixmanipulation.py
+++ b/docs/arrayandmatrixmanipulation.py
@@ -64,11 +64,11 @@
print(a)
-moddims_a = af.moddims(a,(2,4))
+moddims_a = af.moddims(a, (2, 4))
print(moddims_a)
-moddims_b = af.moddims(a,(len(a),))
+moddims_b = af.moddims(a, (len(a),))
print(moddims_b)
# [manipulation4-endsnippet]
@@ -79,24 +79,24 @@
import arrayfire as af
-a = af.randu((2,2,3,1))
+a = af.randu((2, 2, 3, 1))
print(a)
-a_reorder = af.reorder(a,())
+a_reorder = af.reorder(a, ())
# [manipulation5-endsnippet]
# [manipulation6-snippet]
import arrayfire as af
-a = af.randu((3,5))
+a = af.randu((3, 5))
print(a)
-a_shift = af.shift(a,(0,2))
+a_shift = af.shift(a, (0, 2))
print(a_shift)
-a_shift1 = af.shift(a,(-1,2))
+a_shift1 = af.shift(a, (-1, 2))
print(a_shift1)
# [manipulation6-endsnippet]
@@ -106,17 +106,17 @@
import arrayfire as af
-a = af.randu((3,)) #[3,1,1,1]
+a = af.randu((3,)) # [3,1,1,1]
-print (a)
+print(a)
-a_tile = af.tile(a,(2,))
+a_tile = af.tile(a, (2,))
print(a_tile)
-a_tile1 = af.tile(a,(2,2))
+a_tile1 = af.tile(a, (2, 2))
print(a_tile1)
-a_tile2 = af.tile(a,(1,2,3))
+a_tile2 = af.tile(a, (1, 2, 3))
print(a_tile2)
# [manipulation7-endsnippet]
@@ -125,18 +125,18 @@
import arrayfire as af
-a = af.randu((3,3))
-print(a) #[3 3 1 1]
+a = af.randu((3, 3))
+print(a) # [3 3 1 1]
-''' 0.3949 0.8465 0.3709
+""" 0.3949 0.8465 0.3709
0.3561 0.9399 0.2751
- 0.6097 0.6802 0.2720'''
-
+ 0.6097 0.6802 0.2720"""
+
a_transpose = af.transpose(a)
-print(a_transpose) #[3 3 1 1]
+print(a_transpose) # [3 3 1 1]
-''' 0.3949 0.3561 0.6097
+""" 0.3949 0.3561 0.6097
0.8465 0.9399 0.6802
- 0.3709 0.2751 0.2720'''
+ 0.3709 0.2751 0.2720"""
# [manipulation8-endsnippet]
diff --git a/docs/conf.py b/docs/conf.py
index ca827f1..4d7bd35 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -2,47 +2,47 @@
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
-import sys
import os
-sys.path.insert(0, os.path.abspath('..'))
+import sys
+
+sys.path.insert(0, os.path.abspath(".."))
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
-project = 'ArrayFire'
-copyright = '2025, ArrayFire'
-author = 'ArrayFire'
-release = ''
+project = "ArrayFire"
+copyright = "2025, ArrayFire"
+author = "ArrayFire"
+release = ""
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
- 'sphinx.ext.duration',
- 'sphinx.ext.doctest',
- 'sphinx.ext.autodoc',
- 'sphinx.ext.mathjax',
- 'sphinx_collapse',
+ "sphinx.ext.duration",
+ "sphinx.ext.doctest",
+ "sphinx.ext.autodoc",
+ "sphinx.ext.mathjax",
+ "sphinx_collapse",
]
-templates_path = ['_templates']
+templates_path = ["_templates"]
exclude_patterns = []
-
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
-html_theme = 'sphinxawesome_theme'
-html_static_path = ['_static']
+html_theme = "sphinxawesome_theme"
+html_static_path = ["_static"]
html_permalinks = False
html_theme_options = {
"logo_light": "_static/../images/arrayfire_icon.png",
- "logo_dark": "_static/../images/arrayfire_icon.png"
+ "logo_dark": "_static/../images/arrayfire_icon.png",
}
# -- Suppress specific warnings --------------------------------------------
suppress_warnings = [
- 'ref.include_missing',
+ "ref.include_missing",
]
diff --git a/docs/gettingstarted.py b/docs/gettingstarted.py
index 7d6a092..5ef6e01 100644
--- a/docs/gettingstarted.py
+++ b/docs/gettingstarted.py
@@ -1,73 +1,72 @@
-
# [gettingstarted1-snippet]
# Arrays may be created using the array constructor and dimensioned
# as 1D, 2D, 3D; however, the values in these arrays will be undefined
import arrayfire as af
-array = af.constant(0,(100,))
+array = af.constant(0, (100,))
array_2d = af.constant(0, (10, 100))
array_3d = af.constant(0, (10, 10, 10))
# [gettingstarted1-endsnippet]
-
# [gettingstarted2-snippet]
import arrayfire as af
# Generate an array of size three filled with zeros.
# If no data type is specified, ArrayFire defaults to f32.
# The constant function generates the data on the device.
-zeroes = af.constant(0,(3,))
+zeroes = af.constant(0, (3,))
# Generate a 1x4 array of uniformly distributed [0,1] random numbers
# The randu function generates the data on the device.
-rand1 = af.randu((1,4))
+rand1 = af.randu((1, 4))
# Generate a 2x2 array (or matrix, if you prefer) of random numbers
# sampled from a normal distribution.
# The randn function generates data on the device.
-rand2 = af.randu((2,2))
+rand2 = af.randu((2, 2))
# Generate a 3x3 identity matrix. The data is generated on the device.
-iden = af.identity((3,3))
+iden = af.identity((3, 3))
# Lastly, create a 2x1 array (column vector) of uniformly distributed
# 32-bit complex numbers (c32 data type):
-randcplx = af.randu((2,1))
+randcplx = af.randu((2, 1))
# [gettingstarted2-endsnippet]
# [gettingstarted3-snippet]
import arrayfire as af
+
# Create a six-element array on the host
-hA = ([0, 1, 2, 3, 4, 5])
+hA = [0, 1, 2, 3, 4, 5]
# Which can be copied into an ArrayFire Array using the pointer copy
# constructor. Here we copy the data into a 2x3 matrix:
-A = af.moddims(af.Array(hA),(2,3))
+A = af.moddims(af.Array(hA), (2, 3))
# ArrayFire provides a convenince function for printing array
# objects in case you wish to see how the data is stored:
print(A)
-#todo how to create complex numbers
+# todo how to create complex numbers
# [gettingstarted3-endsnippet]
-
# [gettingstarted4-snippet]
-import arrayfire as af
-import pycuda.driver as cuda
import numpy as np
+import pycuda.driver as cuda
+
+import arrayfire as af
# Create an array on the host
host_ptr = af.Array([0, 1, 2, 3, 4, 5])
# Create an ArrayFire array 'a' from host_ptr (2x3 matrix)
-A = af.moddims(host_ptr,(2,3))
+A = af.moddims(host_ptr, (2, 3))
# Allocate CUDA device memory and copy data from host to device
device_ptr = cuda.mem_alloc(host_ptr.nbytes)
@@ -83,19 +82,18 @@
# [gettingstarted4-endsnippet]
-
# [gettingstarted5-snippet]
import arrayfire as af
# Generate two arrays
-a= af.randu((2,2)) # Create a 2x2 array with random numbers between [0, 1]
-b = af.constant(1,(2,1)) # Create a 2x1 array filled with constant value 1
+a = af.randu((2, 2)) # Create a 2x2 array with random numbers between [0, 1]
+b = af.constant(1, (2, 1)) # Create a 2x1 array filled with constant value 1
# Print arrays 'a' and 'b' to the console
print("Array 'a':", a)
-print("Array 'b':",b)
+print("Array 'b':", b)
# Print the results of an expression involving arrays
result = a.col(0) + b + 0.4 # Perform operation: first column of 'a' + 'b' + 0.4
@@ -109,7 +107,7 @@
import arrayfire as af
# Create a 4x5x2 array of uniformly distributed random numbers
-a = af.randu((4,5,2))
+a = af.randu((4, 5, 2))
# Determine the number of dimensions using the `numdims()` function
print("numdims(a):", a.numdims()) # Print the number of dimensions (should be 3)
@@ -150,7 +148,7 @@
# Generate a 3x3 array of uniformly distributed random numbers
R = af.randu((3, 3))
-print(af.constant(1,( 3, 3)) + af.join(af.sin(R))) # will be c32
+print(af.constant(1, (3, 3)) + af.join(af.sin(R))) # will be c32
# Rescale complex values to unit circle
a = af.randn(5)
@@ -158,7 +156,7 @@
# Calculate L2 norm of vectors
X = af.randn((3, 4))
-print(af.sqrt(af.sum(af.pow(X, 2)))) # norm of every column vector
+print(af.sqrt(af.sum(af.pow(X, 2)))) # norm of every column vector
print(af.sqrt(af.sum(af.pow(X, 2), 0))) # same as above
print(af.sqrt(af.sum(af.pow(X, 2), 1))) # norm of every row vector
@@ -167,9 +165,10 @@
# [gettingstarted9-snippet]
-import arrayfire as af
import math
+import arrayfire as af
+
# Generate a 5x5 array of uniformly distributed random numbers
A = af.randu((5, 5))
@@ -188,7 +187,6 @@
# [gettingstarted9-endsnippet]
-
# [gettingstarted10-snippet]
import arrayfire as af
@@ -233,8 +231,8 @@
import arrayfire as af
# Define host arrays
-h_A = ([1, 1, 0, 0, 4, 0, 0, 2, 0])
-h_B = ([1, 0, 1, 0, 1, 0, 1, 1, 1])
+h_A = [1, 1, 0, 0, 4, 0, 0, 2, 0]
+h_B = [1, 0, 1, 0, 1, 0, 1, 1, 1]
# Create ArrayFire arrays A and B from host arrays
A = af.Array(h_A, dims=(3, 3))
@@ -256,11 +254,11 @@
# [gettingstarted12-endsnippet]
-
# [gettingstarted13-snippet]
import arrayfire as af
+
def main():
# Generate random values
a = af.randu(10000, dtype=af.Dtype.f32)
@@ -271,5 +269,3 @@ def main():
# [gettingstarted13-endsnippet]
-
-
diff --git a/docs/indexing.py b/docs/indexing.py
index e5d2364..f83a1d7 100644
--- a/docs/indexing.py
+++ b/docs/indexing.py
@@ -1,50 +1,48 @@
# [indexing1-snippet]
-import arrayfire as af
+import arrayfire as af
-data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
+data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
A = af.Array(data)
-A = af.moddims(A,(4,4))
+A = af.moddims(A, (4, 4))
# [indexing1-endsnippet]
# [indexing2-snippet]
-A[0,0] #Returns an array pointing to the first element
+A[0, 0] # Returns an array pointing to the first element
-A[2,3] #WARN: avoid doing this. Demo only
+A[2, 3] # WARN: avoid doing this. Demo only
# [indexing2-endsnippet]
# [indexing3-snippet]
-ref0 = A[2,-1] # 14 second row last column
-ref1 = A[2,-2] # 10 Second row, second to last(third) column
+ref0 = A[2, -1] # 14 second row last column
+ref1 = A[2, -2] # 10 Second row, second to last(third) column
# [indexing3-endsnippet]
# [indexing4-snippet]
-#Returns an array pointing to the third column
-A[:,2]
+# Returns an array pointing to the third column
+A[:, 2]
# [indexing4-endsnippet]
-
# [indexing5-snippet]
-#Returns an array pointing to the second row
+# Returns an array pointing to the second row
A[1, :]
# [indexing5-endsnippet]
-
# [indexing6-snippet]
- #Returns an array pointing to the first two columns
+# Returns an array pointing to the first two columns
A[:, 0:2]
# [indexing6-endsnippet]
@@ -72,12 +70,12 @@
# [indexing9-snippet]
-inputA = af.constant(3,(10,10))
-inputB = af.constant(2,(10,10))
-data = af.constant(1,(10,10))
+inputA = af.constant(3, (10, 10))
+inputB = af.constant(2, (10, 10))
+data = af.constant(1, (10, 10))
-#Points to the second column of data. Does not allocate memory
-ref = data[:,1]
+# Points to the second column of data. Does not allocate memory
+ref = data[:, 1]
# This call does NOT update data. Memory allocated in matmul
ref = af.matmul(inputA, inputB)
@@ -114,16 +112,15 @@
# [indexing13-snippet]
-A = af.Array[1,2,3,4,5,6,7,8,9]
-A = af.moddims(A,(3,3))
+A = af.Array[1, 2, 3, 4, 5, 6, 7, 8, 9]
+A = af.moddims(A, (3, 3))
# 1.0000 4.0000 7.0000
# 2.0000 5.0000 8.0000
# 3.0000 6.0000 9.0000
-print(A[0,0]) # first element
+print(A[0, 0]) # first element
# 1.0000
-print(A[0,1]) # first row, second column
+print(A[0, 1]) # first row, second column
# 4.0000
# [indexing13-endsnippet]
-
diff --git a/docs/introductiontovectorization.py b/docs/introductiontovectorization.py
index 4551d1b..e7bdfd4 100644
--- a/docs/introductiontovectorization.py
+++ b/docs/introductiontovectorization.py
@@ -1,4 +1,3 @@
-
# [vectorization1-snippet]
import arrayfire as af
@@ -19,11 +18,11 @@
import arrayfire as af
-#[0, 9]
+# [0, 9]
a = af.range(10)
# [1, 10]
-a = a+ 1
+a = a + 1
# [vectorization2-endsnippet]
@@ -32,9 +31,7 @@
import arrayfire as af
# Define the filter coefficients as a list
-g_coef = [1, 2, 1,
- 2, 4, 2,
- 1, 2, 1]
+g_coef = [1, 2, 1, 2, 4, 2, 1, 2, 1]
# Convert the coefficients list to an ArrayFire array and scale it
filter = (1.0 / 16.0) * af.Array(3, 3, g_coef)
@@ -130,7 +127,7 @@
import arrayfire as af
# Create the filter and weight vectors
-filter = af.randu((1, 5)) # Shape: 1x5
+filter = af.randu((1, 5)) # Shape: 1x5
weights = af.randu((5, 5)) # Shape: 5x5
# Transpose the filter to align dimensions for broadcasting
@@ -141,7 +138,7 @@
# Print the filtered weights array
print("Filtered weights:")
-print(filtered_weights) # Incorrect
+print(filtered_weights) # Incorrect
# [vectorization10-endsnippet]
# [vectorization11-snippet]
@@ -149,13 +146,13 @@
import arrayfire as af
# Create the filter and weight vectors
-filter = af.randu((1, 5)) # Shape: 1x5
-batched_filter = af.tile(filter, (1, 1, 5)) # batch on the third dimension
+filter = af.randu((1, 5)) # Shape: 1x5
+batched_filter = af.tile(filter, (1, 1, 5)) # batch on the third dimension
weights = af.randu((5, 5)) # Shape: 5x5
# Leverage matmul batching
-filtered_weights = af.matmul(batched_filter, weights) # shape 1x5x5
-filtered_weights = af.moddims(filtered_weights, (5, 5)) # reshape to 2d 5x5
+filtered_weights = af.matmul(batched_filter, weights) # shape 1x5x5
+filtered_weights = af.moddims(filtered_weights, (5, 5)) # reshape to 2d 5x5
# Print the filtered weights array
print("Filtered weights:")
diff --git a/docs/overview.py b/docs/overview.py
index 18ee70a..1a4d093 100644
--- a/docs/overview.py
+++ b/docs/overview.py
@@ -1,5 +1,6 @@
import arrayfire as af
+
# [pi-example-simple-snippet]
# Monte Carlo estimation of pi
def calc_pi_device(samples) -> float:
@@ -12,5 +13,6 @@ def calc_pi_device(samples) -> float:
within_unit_circle = (x * x + y * y) < 1
# Intuitive function names
return 4 * af.count(within_unit_circle) / samples
-# [pi-example-simple-endsnippet]
+
+# [pi-example-simple-endsnippet]
diff --git a/docs/release_notes.md b/docs/release_notes.md
new file mode 100644
index 0000000..cc17462
--- /dev/null
+++ b/docs/release_notes.md
@@ -0,0 +1,21 @@
+Release Notes {#releasenotes}
+==============
+
+v0.1.0
+======
+Welcome to the ArrayFire Python Bindings! These are the currently supported features:
+
+- Support for all backends (cpu, opencl, oneapi, cuda)
+- Computer Vision
+- Functions to Create and Modify Arrays
+- Functions to Work with Internal Array Layout
+- Image Processing with Features
+- Input and Output Functions
+- Interface Functions
+- Linear Algebra
+- Machine Learning
+- Mathematical Functions
+- Signal Processing
+- Statistics
+- Unified API Functions
+- Vector Algorithms
\ No newline at end of file
diff --git a/tests/test_documentation/test_documentation.py b/tests/test_documentation/test_documentation.py
index ddbb0de..94651b0 100644
--- a/tests/test_documentation/test_documentation.py
+++ b/tests/test_documentation/test_documentation.py
@@ -1,8 +1,8 @@
-import pytest
-import arrayfire as af
import math
+import pytest
+import arrayfire as af
def test_array_shapes():
@@ -19,9 +19,10 @@ def test_array_shapes():
assert array_2d.shape == (10, 100) # Check shape of 2D array
assert array_3d.shape == (10, 10, 10) # Check shape of 3D array
-
# [pi-example-simple-snippet]
# Monte Carlo estimation of pi
+
+
def calc_pi_device(samples) -> float:
# Simple, array based API
# Generate uniformly distributed random numers
@@ -34,6 +35,7 @@ def calc_pi_device(samples) -> float:
return 4 * af.count(within_unit_circle) / samples
# [pi-example-simple-endsnippet]
+
def test_calc_pi_device():
samples = 100000
x = af.randu(samples)
@@ -52,82 +54,87 @@ def test_calc_pi_device():
# Generate an array of size three filled with zeros.
# If no data type is specified, ArrayFire defaults to f32.
# The constant function generates the data on the device.
-zeroes = af.constant(0,(3,))
+zeroes = af.constant(0, (3,))
# Generate a 1x4 array of uniformly distributed [0,1] random numbers
# The randu function generates the data on the device.
-rand1 = af.randu((1,4))
+rand1 = af.randu((1, 4))
# Generate a 2x2 array (or matrix, if you prefer) of random numbers
# sampled from a normal distribution.
# The randn function generates data on the device.
-rand2 = af.randu((2,2))
+rand2 = af.randu((2, 2))
# Generate a 3x3 identity matrix. The data is generated on the device.
-iden = af.identity((3,3))
+iden = af.identity((3, 3))
# Lastly, create a 2x1 array (column vector) of uniformly distributed
# 32-bit complex numbers (c32 data type):
-randcplx = af.randu((2,1))
+randcplx = af.randu((2, 1))
# [gettingstarted2-endsnippet]
import pytest
+
import arrayfire as af
+
def test_arrayfire_operations():
# Generate an array of size three filled with zeros
zeroes = af.constant(0, (3,))
assert zeroes.shape == (3,) # Check shape
-
+
# Generate a 1x4 array of uniformly distributed [0,1] random numbers
rand1 = af.randu((1, 4))
assert rand1.shape == (1, 4) # Check shape
-
+
# Generate a 2x2 array of random numbers sampled from a normal distribution
rand2 = af.randn((2, 2))
assert rand2.shape == (2, 2) # Check shape
-
+
# Generate a 3x3 identity matrix
- iden = af.identity((3,3))
+ iden = af.identity((3, 3))
assert iden.shape == (3, 3) # Check shape
-
+
# Generate a 2x1 array (column vector) of uniformly distributed 32-bit complex numbers
randcplx = af.randu((2, 1))
- assert randcplx.shape == (2, ) # Check shape
+ assert randcplx.shape == (2,) # Check shape
+
# [gettingstarted3-snippet]
import arrayfire as af
+
# Create a six-element array on the host
-hA = ([0, 1, 2, 3, 4, 5])
+hA = [0, 1, 2, 3, 4, 5]
# Which can be copied into an ArrayFire Array using the pointer copy
# constructor. Here we copy the data into a 2x3 matrix:
-A = af.moddims(af.Array(hA),(2,3))
+A = af.moddims(af.Array(hA), (2, 3))
# ArrayFire provides a convenince function for printing array
# objects in case you wish to see how the data is stored:
print(A)
-#todo how to create complex numbers
+# todo how to create complex numbers
# [gettingstarted3-endsnippet]
def test_arrayfire_conversion():
# Create a six-element array on the host
- hA = ([0, 1, 2, 3, 4, 5])
-
+ hA = [0, 1, 2, 3, 4, 5]
+
# Copy data from host array to an ArrayFire array and reshape to 2x3 matrix
- A = af.moddims(af.Array(hA),(2,3))
-
+ A = af.moddims(af.Array(hA), (2, 3))
+
# Assert that the shape of A is (2, 3)
assert A.shape == (2, 3)
-
+
# Assert that the elements in A match hA
for i in range(2):
for j in range(3):
assert A[i, j] == hA[i * 3 + j]
+
# [gettingstarted11-snippet]
import arrayfire as af
@@ -144,37 +151,41 @@ def test_arrayfire_conversion():
import pytest
+
import arrayfire as af
+
def test_arrayfire_scalar_value():
# Create an array consisting of 3 random numbers
a = af.randu(3)
-
+
# Get the scalar value of the array
val = a.scalar()
-
+
# Assert that the scalar value is a float
assert isinstance(val, float)
-
+
# Assert that the scalar value is between 0 and 1 (inclusive)
assert 0 <= val <= 1
+
def test_vectorization():
# [vectorization2-snippet]
import arrayfire as af
- #[0, 9]
+ # [0, 9]
a = af.range(10)
# [1, 10]
- a = a+ 1
+ a = a + 1
# [vectorization2-endsnippet]
# Assertion: Verify the elements of the array 'a'
expected_result = af.Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
assert a == expected_result
+
def test_apply_filter():
# [vectorization9-snippet]
@@ -194,17 +205,15 @@ def test_apply_filter():
print(filtered_weights)
# [vectorization9-endsnippet]
assert filtered_weights.shape == (5, 5)
-
-
-def test_filtered_weights():
+def test_filtered_weights():
# [vectorization10-snippet]
import arrayfire as af
# Create the filter and weight vectors
- filter = af.randu((1, 5)) # Shape: 1x5
+ filter = af.randu((1, 5)) # Shape: 1x5
weights = af.randu((5, 5)) # Shape: 5x5
# Transpose the filter to align dimensions for broadcasting
@@ -214,7 +223,7 @@ def test_filtered_weights():
filtered_weights = filter_transposed * weights
expected_shape = (5, 5) # Expected shape of filtered_weights
-
+
# Assertions
assert filtered_weights.shape == expected_shape
@@ -223,6 +232,7 @@ def test_filtered_weights():
print(filtered_weights)
# [vectorization10-endsnippet]
+
def test_flatten_array():
# [manipulation1-snippet]
@@ -243,7 +253,7 @@ def test_flatten_array():
def test_flip_array():
-
+
# [manipulation2-snippet]
import arrayfire as af
@@ -270,6 +280,7 @@ def test_flip_array():
assert af.min(flip_a) >= 0
assert af.max(flip_a) < 1
+
def test_join_array():
# [manipulation3-snippet]
@@ -292,7 +303,6 @@ def test_join_array():
assert a_join.shape == (10,)
-
def test_moddims_operations():
# [manipulation4-snippet]
@@ -302,11 +312,11 @@ def test_moddims_operations():
print(a)
- moddims_a = af.moddims(a,(2,4))
+ moddims_a = af.moddims(a, (2, 4))
print(moddims_a)
- moddims_b = af.moddims(a,(len(a),))
+ moddims_b = af.moddims(a, (len(a),))
print(moddims_b)
# [manipulation4-endsnippet]
@@ -316,28 +326,27 @@ def test_moddims_operations():
assert a == moddims_b
-
def test_arrayfire_shift():
# [manipulation6-snippet]
import arrayfire as af
- a = af.randu((3,5))
+ a = af.randu((3, 5))
print(a)
- a_shift = af.shift(a,(0,2))
+ a_shift = af.shift(a, (0, 2))
print(a_shift)
- a_shift1 = af.shift(a,(-1,2))
+ a_shift1 = af.shift(a, (-1, 2))
print(a_shift1)
# [manipulation6-endsnippet]
# Check if arrays are equal by comparing element-wise
- assert a != a_shift
+ assert a != a_shift
assert a != a_shift1
- assert a_shift.shape == (3,5)
- assert a_shift1.shape == (3,5)
+ assert a_shift.shape == (3, 5)
+ assert a_shift1.shape == (3, 5)
def transpose_arrayifre():
@@ -345,20 +354,19 @@ def transpose_arrayifre():
import arrayfire as af
- a = af.randu((3,3))
- print(a) #[3 3 1 1]
+ a = af.randu((3, 3))
+ print(a) # [3 3 1 1]
- ''' 0.3949 0.8465 0.3709
+ """ 0.3949 0.8465 0.3709
0.3561 0.9399 0.2751
- 0.6097 0.6802 0.2720'''
-
+ 0.6097 0.6802 0.2720"""
a_transpose = af.transpose(a)
- print(a_transpose) #[3 3 1 1]
+ print(a_transpose) # [3 3 1 1]
- ''' 0.3949 0.3561 0.6097
+ """ 0.3949 0.3561 0.6097
0.8465 0.9399 0.6802
- 0.3709 0.2751 0.2720'''
+ 0.3709 0.2751 0.2720"""
# [manipulation8-endsnippet]
# Convert arrays to Python lists for comparison
a_list = a.to_array().tolist()
@@ -371,32 +379,21 @@ def transpose_arrayifre():
assert a_transpose_list == expected_a_transpose
-
-
def test_moddims():
# [indexing1-snippet]
- import arrayfire as af
+ import arrayfire as af
- data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
+ data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
A = af.Array(data)
- A = af.moddims(A,(4,4))
-
-# [indexing1-endsnippet]
- expected_result = [
- [0, 1, 2, 3],
- [4, 5, 6, 7],
- [8, 9, 10, 11],
- [12, 13, 14, 15]
- ]
-
+ A = af.moddims(A, (4, 4))
+
+ # [indexing1-endsnippet]
+ expected_result = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
+
dims = A.shape
A_list = [[A[i, j] for j in range(dims[1])] for i in range(dims[0])]
# Check if the reshaped array matches the expected result
assert A_list == expected_result
-
-
-
-