Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ coverage.xml
.pytest_cache/

# documentation build artifacts

docs/*.md
docs/api
site/
mkdocs.yml
output-docs/
6 changes: 6 additions & 0 deletions arrayfire/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@

__all__ += [
"constant",
"zeros",
"ones",
"diag",
"identity",
"iota",
Expand All @@ -89,6 +91,7 @@
"flip",
"join",
"moddims",
"reshape",
"reorder",
"replace",
"select",
Expand All @@ -100,6 +103,8 @@

from arrayfire.library.array_functions import (
constant,
zeros,
ones,
copy_array,
diag,
eval,
Expand All @@ -114,6 +119,7 @@
lookup,
lower,
moddims,
reshape,
pad,
range,
reorder,
Expand Down
55 changes: 53 additions & 2 deletions arrayfire/array_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,8 +869,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:
raise TypeError(f"Array should be at least 2-dimensional. Got {self.ndim}-dimensional array")
Expand All @@ -881,6 +881,24 @@ def T(self) -> Array:
@property
@afarray_as_array
def H(self) -> Array:
"""
Hermitian Conjugate of the array.

Returns
-------
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.

Note
----
- The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised.

"""
if self.ndim < 2:
raise TypeError(f"Array should be at least 2-dimensional. Got {self.ndim}-dimensional array")

# TODO add check if out.dtype == self.dtype
return cast(Array, wrapper.transpose(self._arr, True))

@property
Expand Down Expand Up @@ -1096,6 +1114,39 @@ def device_pointer(self) -> int:
def is_locked_array(self) -> bool:
return wrapper.is_locked_array(self._arr)

@afarray_as_array
def reshape(self, shape) -> Array:
"""
Return a copy of this array with the specified shape without changing the data layout.

Parameters
----------
shape : tuple of int
The desired shape of the output array. It should be a tuple of integers
representing the dimensions of the output array. The product of these
dimensions must match the total number of elements in the input array.

Returns
-------
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.

Raises
------
ValueError
If the total number of elements in the input array does not match the
product of the dimensions specified in the `shape` tuple.

Notes
-----
This function modifies the shape of the input array without changing the
data layout. The resulting array will have the same data, but with a
different shape as specified by the `shape` parameter.
"""
# TODO add examples to doc
return cast(Array, wrapper.moddims(self._arr, shape))

def lock_array(self) -> None:
return wrapper.lock_array(self._arr)

Expand Down
96 changes: 92 additions & 4 deletions arrayfire/library/array_functions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
__all__ = [
"constant",
"zeros",
"ones",
"diag",
"identity",
"iota",
Expand All @@ -17,6 +19,7 @@
"flip",
"join",
"moddims",
"reshape",
"reorder",
"replace",
"select",
Expand Down Expand Up @@ -70,6 +73,59 @@ 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

Parameters
----------
shape : tuple[int, ...], optional, default: (1,)
The shape of the constant array.

dtype : Dtype, optional, default: float32
Data type of the array.

Returns
-------
Array
A multi-dimensional ArrayFire array filled zeros

Notes
-----
The shape parameter determines the dimensions of the resulting array:
- If shape is (x1,), the output is a 1D array of size (x1,).
- If shape is (x1, x2), the output is a 2D array of size (x1, x2).
- If shape is (x1, x2, x3), the output is a 3D array of size (x1, x2, x3).
- If shape is (x1, x2, x3, x4), the output is a 4D array of size (x1, x2, x3, x4).
"""
return constant(0, shape, dtype)

def ones(shape: tuple[int, ...], dtype: Dtype = float32) -> Array:
"""
Create a multi-dimensional array filled with ones

Parameters
----------
shape : tuple[int, ...], optional, default: (1,)
The shape of the constant array.

dtype : Dtype, optional, default: float32
Data type of the array.

Returns
-------
Array
A multi-dimensional ArrayFire array filled ones

Notes
-----
The shape parameter determines the dimensions of the resulting array:
- If shape is (x1,), the output is a 1D array of size (x1,).
- If shape is (x1, x2), the output is a 2D array of size (x1, x2).
- If shape is (x1, x2, x3), the output is a 3D array of size (x1, x2, x3).
- If shape is (x1, x2, x3, x4), the output is a 4D array of size (x1, x2, x3, x4).
"""
return constant(1, shape, dtype)

@afarray_as_array
def diag(array: Array, /, *, diag_index: int = 0, extract: bool = True) -> Array:
Expand Down Expand Up @@ -255,8 +311,7 @@ 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
--------
Expand Down Expand Up @@ -312,8 +367,7 @@ 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
--------
Expand Down Expand Up @@ -818,6 +872,40 @@ 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.

Parameters
----------
array : af.Array
Multi-dimensional array to be reshaped.

shape : tuple of int
The desired shape of the output array. It should be a tuple of integers
representing the dimensions of the output array. The product of these
dimensions must match the total number of elements in the input array.

Returns
-------
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.

Raises
------
ValueError
If the total number of elements in the input array does not match the
product of the dimensions specified in the `shape` tuple.

Notes
-----
This function modifies the shape of the input array without changing the
data layout. The resulting array will have the same data, but with a
different shape as specified by the `shape` parameter.
"""
return moddims(array, shape)

@afarray_as_array
def reorder(array: Array, /, *, shape: tuple[int, ...] = (1, 0, 2, 3)) -> Array:
Expand Down
5 changes: 2 additions & 3 deletions arrayfire/library/computer_vision.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def gloh(
A tuple containing two elements:
- `Features`: An object holding the detected features, including their locations and scales.
- `Array`: An ArrayFire array containing the GLOH descriptors for the detected features, with each descriptor
having 272 elements.
having 272 elements.

Note
----
Expand Down Expand Up @@ -164,8 +164,7 @@ 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
----
Expand Down
5 changes: 5 additions & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ pytest-cov>=5.0.0
# Allows codecov to generate coverage reports
coverage[toml]>=6.4
codecov>=2.1.12

# Allows documentation
sphinx>=7.3.7
sphinxawesome_theme>=5.2.0
sphinx_collapse>=0.1.3
20 changes: 20 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Documentation (WIP)
==========

**This documentation is a work in progress and may not contain all currently supported operations. Please check the functions signature and description for more info on it**

We use [`Sphinx`](https://www.sphinx-doc.org/en/master/index.html) for presenting our documentation.

To build the docs follow these steps:

1. Install the required sphinx packages and extensions from the [dev-requirements.txt](../dev-requirements.txt)
```sh
pip install -r dev-requirements.txt # install sphinx and its extensions
pip install -r requirements.txt # install arrayfire-binary-python-wrapper
```
2. Build docs using sphinx
```sh
sphinx-build -M html docs/ output-docs/ # builds docs as html files stored in output-docs
```
3. Explore the docs starting at `output-docs/index.html`

7 changes: 7 additions & 0 deletions docs/TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
TODO
=====

- Add docstring to function image processing
- Change to where the Restructured Files for the undocumented functions point to (currently some point to docs in the arrayfire-binary-python-wrapper)
- Add more detail to the constants and classes
- Add more information in the python installation section
13 changes: 13 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
a {
color: blue; /* Set the color of links to blue */
text-decoration: underline; /* Underline links */
}

a:hover {
color: darkblue; /* Change link color to dark blue on hover */
}

.responsive-img {
max-width: 100%;
height: auto;
}
50 changes: 50 additions & 0 deletions docs/afjit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# [jit-snippet]

# As JIT is automatically enabled in ArrayFire, this version of the function
# forces each expression to be evaluated. If the eval() function calls are
# removed, then the execution of this code would be equivalent to the
# following function.

import arrayfire as af
import time

samples = int(9e8)
x = af.randu((samples))
y = af.randu((samples))

def pi_no_jit(x, y, samples):
temp = x * x
af.eval(temp)
temp += y * y
af.eval(temp)
temp = af.sqrt(temp)
af.eval(temp)
temp = temp < 1
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()

# Time JIT code
start = time.perf_counter()
res = pi_jit(x, y, samples)
af.sync()
end = time.perf_counter()

print("jit:", end - start, res)
af.device_gc()

# Time no JIT code
start = time.perf_counter()
res = pi_no_jit(x, y, samples)
af.sync()
end = time.perf_counter()
print("no jit:", end - start, res)

# [jit-endsnippet]
Loading