array-api-negative-index 0.0.0__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. {array_api_negative_index-0.0.0/src/array_api_negative_index.egg-info → array_api_negative_index-1.0.0}/PKG-INFO +65 -3
  2. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/README.md +62 -2
  3. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/pyproject.toml +5 -1
  4. array_api_negative_index-1.0.0/src/array_api_negative_index/__init__.py +4 -0
  5. array_api_negative_index-1.0.0/src/array_api_negative_index/_main.py +120 -0
  6. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0/src/array_api_negative_index.egg-info}/PKG-INFO +65 -3
  7. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/src/array_api_negative_index.egg-info/SOURCES.txt +2 -1
  8. array_api_negative_index-1.0.0/src/array_api_negative_index.egg-info/requires.txt +2 -0
  9. array_api_negative_index-1.0.0/tests/test_main.py +28 -0
  10. array_api_negative_index-0.0.0/src/array_api_negative_index/__init__.py +0 -1
  11. array_api_negative_index-0.0.0/src/array_api_negative_index/main.py +0 -3
  12. array_api_negative_index-0.0.0/tests/test_main.py +0 -6
  13. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/LICENSE +0 -0
  14. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/setup.cfg +0 -0
  15. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/setup.py +0 -0
  16. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/src/array_api_negative_index/py.typed +0 -0
  17. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/src/array_api_negative_index.egg-info/dependency_links.txt +0 -0
  18. {array_api_negative_index-0.0.0 → array_api_negative_index-1.0.0}/src/array_api_negative_index.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: array-api-negative-index
3
- Version: 0.0.0
3
+ Version: 1.0.0
4
4
  Summary: Utils for indexing arrays with {-n, -(n-1), ..., -1, 0, 1, ..., n-1, n} using array API.
5
5
  Author-email: 34j <34j.95a2p@simplelogin.com>
6
6
  License: MIT
@@ -21,6 +21,8 @@ Classifier: Topic :: Software Development :: Libraries
21
21
  Requires-Python: >=3.9
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
+ Requires-Dist: array-api-compat>=1.11.2
25
+ Requires-Dist: types-array-api>=1.1.4
24
26
  Dynamic: license-file
25
27
 
26
28
  # Array API Negative Index
@@ -63,13 +65,73 @@ Dynamic: license-file
63
65
 
64
66
  ---
65
67
 
66
- Utils for indexing arrays with {-n, -(n-1), ..., -1, 0, 1, ..., n-1, n} using array API.
68
+ Utils for indexing arrays with `{-n, -(n-1), ..., -1, 0, 1, ..., n-1, n}` using array API.
67
69
 
68
70
  ## Installation
69
71
 
70
72
  Install this via pip (or your favourite package manager):
71
73
 
72
- `pip install array-api-negative-index`
74
+ ```shell
75
+ pip install array-api-negative-index
76
+ ```
77
+
78
+ ## Usage
79
+
80
+ - This package provides a utility for packing array elements in the order `[0, 1, 2, ..., n, -n, ..., -2, -1]`.
81
+ - This allows one to access the `i`-th element by `array[i]`, regardless of whether `i` is positive, 0 or negative, thanks to "Negative Indexing" in array API.
82
+ - This is useful for representing the order `m` in spherical harmonics for example.
83
+
84
+ ```python
85
+ from array_api_negative_index import to_symmetric, flip_symmetric, arange_asymmetric
86
+ ```
87
+
88
+ ### `arange_asymmetric()`
89
+
90
+ ```python
91
+ import numpy as np
92
+
93
+ a = arange_asymmetric(3, xp=np)
94
+ print(a)
95
+ ```
96
+
97
+ ```text
98
+ [ 0 1 2 -2 -1]
99
+ ```
100
+
101
+ Not to confuse with `np.arange(-stop + 1, stop)`!
102
+ This caused me to create bugs many times.
103
+
104
+ ```python
105
+ a = np.arange(-2, 3)
106
+ print(a)
107
+ ```
108
+
109
+ ```text
110
+ [-2, -1, 0, 1, 2]
111
+ ```
112
+
113
+ ### `flip_symmetric()`
114
+
115
+ ```python
116
+ b = flip_symmetric(a)
117
+ print(f"{a} -> (flip) -> {b}")
118
+ ```
119
+
120
+ ```text
121
+ [ 0 1 2 -2 -1] -> (flip) -> [ 0 -1 -2 2 1]
122
+ ```
123
+
124
+ ### `to_symmetric()`
125
+
126
+ ```python
127
+ c = np.asarray([0, 3, 5])
128
+ d = to_symmetric(c, asymmetric=True, conjugate=False)
129
+ print(f"{c} -> (to_symmetric) -> {d}")
130
+ ```
131
+
132
+ ```text
133
+ [0 3 5] -> (to_symmetric) -> [ 0 3 5 -5 -3]
134
+ ```
73
135
 
74
136
  ## Contributors ✨
75
137
 
@@ -38,13 +38,73 @@
38
38
 
39
39
  ---
40
40
 
41
- Utils for indexing arrays with {-n, -(n-1), ..., -1, 0, 1, ..., n-1, n} using array API.
41
+ Utils for indexing arrays with `{-n, -(n-1), ..., -1, 0, 1, ..., n-1, n}` using array API.
42
42
 
43
43
  ## Installation
44
44
 
45
45
  Install this via pip (or your favourite package manager):
46
46
 
47
- `pip install array-api-negative-index`
47
+ ```shell
48
+ pip install array-api-negative-index
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ - This package provides a utility for packing array elements in the order `[0, 1, 2, ..., n, -n, ..., -2, -1]`.
54
+ - This allows one to access the `i`-th element by `array[i]`, regardless of whether `i` is positive, 0 or negative, thanks to "Negative Indexing" in array API.
55
+ - This is useful for representing the order `m` in spherical harmonics for example.
56
+
57
+ ```python
58
+ from array_api_negative_index import to_symmetric, flip_symmetric, arange_asymmetric
59
+ ```
60
+
61
+ ### `arange_asymmetric()`
62
+
63
+ ```python
64
+ import numpy as np
65
+
66
+ a = arange_asymmetric(3, xp=np)
67
+ print(a)
68
+ ```
69
+
70
+ ```text
71
+ [ 0 1 2 -2 -1]
72
+ ```
73
+
74
+ Not to confuse with `np.arange(-stop + 1, stop)`!
75
+ This caused me to create bugs many times.
76
+
77
+ ```python
78
+ a = np.arange(-2, 3)
79
+ print(a)
80
+ ```
81
+
82
+ ```text
83
+ [-2, -1, 0, 1, 2]
84
+ ```
85
+
86
+ ### `flip_symmetric()`
87
+
88
+ ```python
89
+ b = flip_symmetric(a)
90
+ print(f"{a} -> (flip) -> {b}")
91
+ ```
92
+
93
+ ```text
94
+ [ 0 1 2 -2 -1] -> (flip) -> [ 0 -1 -2 2 1]
95
+ ```
96
+
97
+ ### `to_symmetric()`
98
+
99
+ ```python
100
+ c = np.asarray([0, 3, 5])
101
+ d = to_symmetric(c, asymmetric=True, conjugate=False)
102
+ print(f"{c} -> (to_symmetric) -> {d}")
103
+ ```
104
+
105
+ ```text
106
+ [0 3 5] -> (to_symmetric) -> [ 0 3 5 -5 -3]
107
+ ```
48
108
 
49
109
  ## Contributors ✨
50
110
 
@@ -4,7 +4,7 @@ requires = [ "setuptools" ]
4
4
 
5
5
  [project]
6
6
  name = "array-api-negative-index"
7
- version = "0.0.0"
7
+ version = "1.0.0"
8
8
  description = "Utils for indexing arrays with {-n, -(n-1), ..., -1, 0, 1, ..., n-1, n} using array API."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -26,6 +26,8 @@ classifiers = [
26
26
  ]
27
27
 
28
28
  dependencies = [
29
+ "array-api-compat>=1.11.2",
30
+ "types-array-api>=1.1.4",
29
31
  ]
30
32
  urls."Bug Tracker" = "https://github.com/34j/array-api-negative-index/issues"
31
33
  urls.Changelog = "https://github.com/34j/array-api-negative-index/blob/main/CHANGELOG.md"
@@ -34,8 +36,10 @@ urls.repository = "https://github.com/34j/array-api-negative-index"
34
36
 
35
37
  [dependency-groups]
36
38
  dev = [
39
+ "numpy>=2.0.2",
37
40
  "pytest>=8,<9",
38
41
  "pytest-cov>=6,<7",
42
+ "torch>=2.8.0",
39
43
  ]
40
44
  docs = [
41
45
  "furo>=2023.5.20; python_version>='3.11'",
@@ -0,0 +1,4 @@
1
+ __version__ = "1.0.0"
2
+ from ._main import arange_asymmetric, flip_symmetric, to_symmetric
3
+
4
+ __all__ = ["arange_asymmetric", "flip_symmetric", "to_symmetric"]
@@ -0,0 +1,120 @@
1
+ from typing import Any
2
+
3
+ from array_api._2024_12 import Array, ArrayNamespaceFull
4
+ from array_api_compat import array_namespace
5
+
6
+
7
+ def to_symmetric(
8
+ input: Array,
9
+ /,
10
+ *,
11
+ axis: int = 0,
12
+ asymmetric: bool = False,
13
+ conjugate: bool = False,
14
+ ) -> Array:
15
+ """
16
+ Extend a tensor to its opposite symmetric form.
17
+
18
+ Parameters
19
+ ----------
20
+ input : Array
21
+ The input tensor.
22
+ axis : int, optional
23
+ The axis to extend, by default 0
24
+ asymmetric : bool, optional
25
+ If True, the input tensor is multiplied by -1, by default False
26
+ conjugate : bool, optional
27
+ If True, the input tensor is conjugated, by default False
28
+
29
+ Returns
30
+ -------
31
+ Array
32
+ The symmetric tensor.
33
+ If not include_zero_twice,
34
+ forall a < input.shape[axis] result[-a] = result[a]
35
+ Else,
36
+ forall a < input.shape[axis] result[-a-1] = result[a]
37
+
38
+ """
39
+ xp = array_namespace(input)
40
+ input_to_symmetric = input
41
+ if asymmetric:
42
+ input_to_symmetric = -input_to_symmetric
43
+ if conjugate:
44
+ input_to_symmetric = xp.conj(input_to_symmetric)
45
+ axis = axis % input.ndim
46
+ input_to_symmetric = input_to_symmetric[
47
+ (slice(None),) * axis + (slice(1, None), ...)
48
+ ]
49
+ input_to_symmetric = xp.flip(input_to_symmetric, axis=axis)
50
+ return xp.concat([input, input_to_symmetric], axis=axis)
51
+
52
+
53
+ def arange_asymmetric(
54
+ stop: int,
55
+ /,
56
+ *,
57
+ xp: ArrayNamespaceFull,
58
+ dtype: Any = None,
59
+ device: Any = None,
60
+ ) -> Array:
61
+ """
62
+ Create a symmetric array with values from -stop+1 to stop-1.
63
+
64
+ Parameters
65
+ ----------
66
+ stop : int
67
+ The stop value (exclusive).
68
+ dtype : Any, optional
69
+ The desired data type of the output array, by default None
70
+ device : Any, optional
71
+ The device on which to create the array, by default None
72
+ xp : ArrayNamespaceFull, optional
73
+ The array namespace to use, by default None
74
+
75
+ Returns
76
+ -------
77
+ Array
78
+ An array [0, 1, ..., stop-1, -stop+1, ..., -1].
79
+ The shape is (2 * stop - 1,).
80
+
81
+ """
82
+ return to_symmetric(
83
+ xp.arange(stop, dtype=dtype, device=device),
84
+ asymmetric=True,
85
+ )
86
+
87
+
88
+ def flip_symmetric(input: Array, /, *, axis: int = 0) -> Array:
89
+ """
90
+ Flip a symmetric array.
91
+
92
+ Parameters
93
+ ----------
94
+ input : Array
95
+ The input array.
96
+ axis : int, optional
97
+ The axis to flip, by default 0
98
+ include_zero_twice : bool, optional
99
+ If True, the zeroth element is included twice, by default False
100
+
101
+ Returns
102
+ -------
103
+ Array
104
+ The flipped array.
105
+ Forall a < input.shape[axis] result[-a-1] = result[a] = input[a] = input[-a-1]
106
+
107
+ """
108
+ xp = array_namespace(input)
109
+ axis = axis % input.ndim
110
+ zero = input[
111
+ (
112
+ slice(
113
+ None,
114
+ ),
115
+ )
116
+ * axis
117
+ + (slice(0, 1), ...)
118
+ ]
119
+ nonzero = input[(slice(None),) * axis + (slice(1, None), ...)]
120
+ return xp.concat([zero, xp.flip(nonzero, axis=axis)], axis=axis)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: array-api-negative-index
3
- Version: 0.0.0
3
+ Version: 1.0.0
4
4
  Summary: Utils for indexing arrays with {-n, -(n-1), ..., -1, 0, 1, ..., n-1, n} using array API.
5
5
  Author-email: 34j <34j.95a2p@simplelogin.com>
6
6
  License: MIT
@@ -21,6 +21,8 @@ Classifier: Topic :: Software Development :: Libraries
21
21
  Requires-Python: >=3.9
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
+ Requires-Dist: array-api-compat>=1.11.2
25
+ Requires-Dist: types-array-api>=1.1.4
24
26
  Dynamic: license-file
25
27
 
26
28
  # Array API Negative Index
@@ -63,13 +65,73 @@ Dynamic: license-file
63
65
 
64
66
  ---
65
67
 
66
- Utils for indexing arrays with {-n, -(n-1), ..., -1, 0, 1, ..., n-1, n} using array API.
68
+ Utils for indexing arrays with `{-n, -(n-1), ..., -1, 0, 1, ..., n-1, n}` using array API.
67
69
 
68
70
  ## Installation
69
71
 
70
72
  Install this via pip (or your favourite package manager):
71
73
 
72
- `pip install array-api-negative-index`
74
+ ```shell
75
+ pip install array-api-negative-index
76
+ ```
77
+
78
+ ## Usage
79
+
80
+ - This package provides a utility for packing array elements in the order `[0, 1, 2, ..., n, -n, ..., -2, -1]`.
81
+ - This allows one to access the `i`-th element by `array[i]`, regardless of whether `i` is positive, 0 or negative, thanks to "Negative Indexing" in array API.
82
+ - This is useful for representing the order `m` in spherical harmonics for example.
83
+
84
+ ```python
85
+ from array_api_negative_index import to_symmetric, flip_symmetric, arange_asymmetric
86
+ ```
87
+
88
+ ### `arange_asymmetric()`
89
+
90
+ ```python
91
+ import numpy as np
92
+
93
+ a = arange_asymmetric(3, xp=np)
94
+ print(a)
95
+ ```
96
+
97
+ ```text
98
+ [ 0 1 2 -2 -1]
99
+ ```
100
+
101
+ Not to confuse with `np.arange(-stop + 1, stop)`!
102
+ This caused me to create bugs many times.
103
+
104
+ ```python
105
+ a = np.arange(-2, 3)
106
+ print(a)
107
+ ```
108
+
109
+ ```text
110
+ [-2, -1, 0, 1, 2]
111
+ ```
112
+
113
+ ### `flip_symmetric()`
114
+
115
+ ```python
116
+ b = flip_symmetric(a)
117
+ print(f"{a} -> (flip) -> {b}")
118
+ ```
119
+
120
+ ```text
121
+ [ 0 1 2 -2 -1] -> (flip) -> [ 0 -1 -2 2 1]
122
+ ```
123
+
124
+ ### `to_symmetric()`
125
+
126
+ ```python
127
+ c = np.asarray([0, 3, 5])
128
+ d = to_symmetric(c, asymmetric=True, conjugate=False)
129
+ print(f"{c} -> (to_symmetric) -> {d}")
130
+ ```
131
+
132
+ ```text
133
+ [0 3 5] -> (to_symmetric) -> [ 0 3 5 -5 -3]
134
+ ```
73
135
 
74
136
  ## Contributors ✨
75
137
 
@@ -3,10 +3,11 @@ README.md
3
3
  pyproject.toml
4
4
  setup.py
5
5
  src/array_api_negative_index/__init__.py
6
- src/array_api_negative_index/main.py
6
+ src/array_api_negative_index/_main.py
7
7
  src/array_api_negative_index/py.typed
8
8
  src/array_api_negative_index.egg-info/PKG-INFO
9
9
  src/array_api_negative_index.egg-info/SOURCES.txt
10
10
  src/array_api_negative_index.egg-info/dependency_links.txt
11
+ src/array_api_negative_index.egg-info/requires.txt
11
12
  src/array_api_negative_index.egg-info/top_level.txt
12
13
  tests/test_main.py
@@ -0,0 +1,2 @@
1
+ array-api-compat>=1.11.2
2
+ types-array-api>=1.1.4
@@ -0,0 +1,28 @@
1
+ import pytest
2
+ from array_api._2024_12 import ArrayNamespaceFull
3
+
4
+ from array_api_negative_index import flip_symmetric, to_symmetric
5
+
6
+
7
+ def test_flip_symmetric(xp: ArrayNamespaceFull) -> None:
8
+ array = xp.asarray([0, 1, 2, 3, 4])
9
+ assert xp.all(flip_symmetric(array) == xp.asarray([0, 4, 3, 2, 1]))
10
+ assert xp.all(flip_symmetric(flip_symmetric(array)) == array)
11
+
12
+
13
+ @pytest.mark.parametrize("asymmetric", [True, False])
14
+ @pytest.mark.parametrize("conjugate", [True, False])
15
+ def test_to_symmetric_manual(
16
+ asymmetric: bool, conjugate: bool, xp: ArrayNamespaceFull
17
+ ) -> None:
18
+ array = xp.asarray([0, 1 + 1j, 2 - 1j])
19
+ result = to_symmetric(xp.asarray(array), asymmetric=asymmetric, conjugate=conjugate)
20
+ if asymmetric and conjugate:
21
+ expected = [0, 1 + 1j, 2 - 1j, -2 - 1j, -1 + 1j]
22
+ elif asymmetric and not conjugate:
23
+ expected = [0, 1 + 1j, 2 - 1j, -2 + 1j, -1 - 1j]
24
+ elif not asymmetric and conjugate:
25
+ expected = [0, 1 + 1j, 2 - 1j, 2 + 1j, 1 - 1j]
26
+ else:
27
+ expected = [0, 1 + 1j, 2 - 1j, 2 - 1j, 1 + 1j]
28
+ assert xp.all(result == xp.asarray(expected))
@@ -1 +0,0 @@
1
- __version__ = "0.0.0"
@@ -1,3 +0,0 @@
1
- def add(n1: int, n2: int) -> int:
2
- """Add the arguments."""
3
- return n1 + n2
@@ -1,6 +0,0 @@
1
- from array_api_negative_index.main import add
2
-
3
-
4
- def test_add():
5
- """Adding two number works as expected."""
6
- assert add(1, 1) == 2