spectrochempy-hypercomplex 0.1.1__tar.gz → 0.1.2__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.
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/PKG-INFO +2 -2
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/pyproject.toml +2 -2
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex/__init__.py +2 -2
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex/_quaternion.py +12 -8
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex.egg-info/PKG-INFO +2 -2
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex.egg-info/requires.txt +1 -1
- spectrochempy_hypercomplex-0.1.2/tests/test_hypercomplex.py +126 -0
- spectrochempy_hypercomplex-0.1.1/tests/test_hypercomplex.py +0 -49
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/setup.cfg +0 -0
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex.egg-info/SOURCES.txt +0 -0
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex.egg-info/dependency_links.txt +0 -0
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex.egg-info/entry_points.txt +0 -0
- {spectrochempy_hypercomplex-0.1.1 → spectrochempy_hypercomplex-0.1.2}/src/spectrochempy_hypercomplex.egg-info/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spectrochempy-hypercomplex
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Hypercomplex / quaternion support plugin for SpectroChemPy
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
|
-
Requires-Dist: spectrochempy<0.10,>=0.9
|
|
6
|
+
Requires-Dist: spectrochempy<0.10,>=0.9
|
|
7
7
|
Requires-Dist: numpy
|
|
8
8
|
Requires-Dist: numpy-quaternion>=2024.0.7
|
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "spectrochempy-hypercomplex"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Hypercomplex / quaternion support plugin for SpectroChemPy"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"spectrochempy>=0.9
|
|
11
|
+
"spectrochempy>=0.9,<0.10",
|
|
12
12
|
"numpy",
|
|
13
13
|
"numpy-quaternion>=2024.0.7",
|
|
14
14
|
]
|
|
@@ -310,9 +310,9 @@ class HyperComplexPlugin(SpectroChemPyPlugin):
|
|
|
310
310
|
"""Hypercomplex / quaternion support for SpectroChemPy."""
|
|
311
311
|
|
|
312
312
|
name = "hypercomplex"
|
|
313
|
-
version = "0.1.
|
|
313
|
+
version = "0.1.2"
|
|
314
314
|
description = "Hypercomplex / quaternion data support"
|
|
315
|
-
spectrochempy_min_version = "0.9.0
|
|
315
|
+
spectrochempy_min_version = "0.9.0"
|
|
316
316
|
PLUGIN_API_VERSION = CORE_PLUGIN_API_VERSION
|
|
317
317
|
capabilities = [PluginCapability.ACCESSOR]
|
|
318
318
|
|
|
@@ -65,10 +65,8 @@ def as_quaternion(*args):
|
|
|
65
65
|
else:
|
|
66
66
|
raise ValueError("as_quaternion requires 2 or 4 arguments")
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
return data.reshape(w.shape)
|
|
68
|
+
stacked = np.stack([w, x, y, z], axis=-1)
|
|
69
|
+
return as_quat_array(stacked)
|
|
72
70
|
|
|
73
71
|
|
|
74
72
|
def quat_as_complex_array(arr):
|
|
@@ -90,8 +88,11 @@ def quat_as_complex_array(arr):
|
|
|
90
88
|
if typequaternion is None or arr.dtype != typequaternion:
|
|
91
89
|
return arr
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
w
|
|
91
|
+
float_arr = as_float_array(arr)
|
|
92
|
+
w = float_arr[..., 0]
|
|
93
|
+
x = float_arr[..., 1]
|
|
94
|
+
y = float_arr[..., 2]
|
|
95
|
+
z = float_arr[..., 3]
|
|
95
96
|
|
|
96
97
|
return (w + 1j * x), (y + 1j * z)
|
|
97
98
|
|
|
@@ -136,8 +137,11 @@ def get_component(data, select="REAL"):
|
|
|
136
137
|
w = x = y = z = None
|
|
137
138
|
|
|
138
139
|
if typequaternion is not None and new.dtype == typequaternion:
|
|
139
|
-
|
|
140
|
-
w
|
|
140
|
+
float_arr = as_float_array(new)
|
|
141
|
+
w = float_arr[..., 0]
|
|
142
|
+
x = float_arr[..., 1]
|
|
143
|
+
y = float_arr[..., 2]
|
|
144
|
+
z = float_arr[..., 3]
|
|
141
145
|
if select == "R":
|
|
142
146
|
new = w + x * 1j
|
|
143
147
|
elif select == "I":
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spectrochempy-hypercomplex
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Hypercomplex / quaternion support plugin for SpectroChemPy
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
|
-
Requires-Dist: spectrochempy<0.10,>=0.9
|
|
6
|
+
Requires-Dist: spectrochempy<0.10,>=0.9
|
|
7
7
|
Requires-Dist: numpy
|
|
8
8
|
Requires-Dist: numpy-quaternion>=2024.0.7
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# ruff: noqa: S101
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestHyperAccessor:
|
|
7
|
+
def test_accessor_registered(self):
|
|
8
|
+
import spectrochempy as scp
|
|
9
|
+
|
|
10
|
+
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
11
|
+
assert hasattr(ds, "hyper")
|
|
12
|
+
|
|
13
|
+
def test_is_quaternion_false_for_real(self):
|
|
14
|
+
import spectrochempy as scp
|
|
15
|
+
|
|
16
|
+
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
17
|
+
assert ds.hyper.is_quaternion is False
|
|
18
|
+
|
|
19
|
+
def test_set_quaternion_creates_quaternion_dtype(self):
|
|
20
|
+
import spectrochempy as scp
|
|
21
|
+
|
|
22
|
+
ds = scp.NDDataset([1.0, 2.0, 3.0, 4.0])
|
|
23
|
+
result = ds.hyper.set_quaternion()
|
|
24
|
+
assert result._data.dtype.name == "quaternion"
|
|
25
|
+
|
|
26
|
+
def test_component_real_data_noop(self):
|
|
27
|
+
import spectrochempy as scp
|
|
28
|
+
|
|
29
|
+
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
30
|
+
result = ds.hyper.component("RR")
|
|
31
|
+
assert result is not None
|
|
32
|
+
|
|
33
|
+
def test_RR_RI_IR_II_raise_for_real(self):
|
|
34
|
+
import spectrochempy as scp
|
|
35
|
+
|
|
36
|
+
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
37
|
+
for prop in ["RR", "RI", "IR", "II"]:
|
|
38
|
+
with pytest.raises(TypeError):
|
|
39
|
+
getattr(ds.hyper, prop)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestNDMathHandlers:
|
|
43
|
+
def test_handler_registration(self):
|
|
44
|
+
from spectrochempy.plugins import manager
|
|
45
|
+
|
|
46
|
+
registry = manager.plugin_manager.registry
|
|
47
|
+
assert registry.get_handler("ndmath.execution_branch") is not None
|
|
48
|
+
assert registry.get_handler("ndmath.execute") is not None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TestQuaternionFunctions:
|
|
52
|
+
def test_as_quaternion_roundtrip(self):
|
|
53
|
+
from spectrochempy_hypercomplex._quaternion import as_quaternion
|
|
54
|
+
from spectrochempy_hypercomplex._quaternion import quat_as_complex_array
|
|
55
|
+
|
|
56
|
+
w = np.array([1.0, 2.0, 3.0])
|
|
57
|
+
x = np.array([0.5, 0.6, 0.7])
|
|
58
|
+
q = as_quaternion(w, x, w, x)
|
|
59
|
+
c1, c2 = quat_as_complex_array(q)
|
|
60
|
+
assert np.allclose(c1, w + 1j * x)
|
|
61
|
+
assert np.allclose(c2, w + 1j * x)
|
|
62
|
+
|
|
63
|
+
def test_as_quaternion_2args(self):
|
|
64
|
+
from spectrochempy_hypercomplex._quaternion import as_quaternion
|
|
65
|
+
|
|
66
|
+
r = np.array([1.0, 2.0]) + 1j * np.array([0.5, 0.6])
|
|
67
|
+
i = np.array([3.0, 4.0]) + 1j * np.array([0.7, 0.8])
|
|
68
|
+
q = as_quaternion(r, i)
|
|
69
|
+
assert q.dtype.name == "quaternion"
|
|
70
|
+
assert q.shape == (2,)
|
|
71
|
+
|
|
72
|
+
def test_as_quaternion_2d_shape_preserved(self):
|
|
73
|
+
from spectrochempy_hypercomplex._quaternion import as_quaternion
|
|
74
|
+
|
|
75
|
+
w = np.ones((3, 4))
|
|
76
|
+
x = np.zeros((3, 4))
|
|
77
|
+
q = as_quaternion(w, x, w, x)
|
|
78
|
+
assert q.shape == (3, 4)
|
|
79
|
+
|
|
80
|
+
def test_quat_as_complex_array_nd(self):
|
|
81
|
+
from spectrochempy_hypercomplex._quaternion import as_quaternion
|
|
82
|
+
from spectrochempy_hypercomplex._quaternion import quat_as_complex_array
|
|
83
|
+
|
|
84
|
+
w = np.arange(24.0).reshape(2, 3, 4)
|
|
85
|
+
x = np.arange(24.0, 48.0).reshape(2, 3, 4)
|
|
86
|
+
q = as_quaternion(w, x, w, x)
|
|
87
|
+
c1, c2 = quat_as_complex_array(q)
|
|
88
|
+
assert c1.shape == (2, 3, 4)
|
|
89
|
+
assert np.allclose(c1, w + 1j * x)
|
|
90
|
+
|
|
91
|
+
def test_get_component_quaternion_2d(self):
|
|
92
|
+
from spectrochempy_hypercomplex._quaternion import as_quaternion
|
|
93
|
+
from spectrochempy_hypercomplex._quaternion import get_component
|
|
94
|
+
|
|
95
|
+
w = np.ones((3, 4))
|
|
96
|
+
x = np.full((3, 4), 2.0)
|
|
97
|
+
y = np.full((3, 4), 3.0)
|
|
98
|
+
z = np.full((3, 4), 4.0)
|
|
99
|
+
q = as_quaternion(w, x, y, z)
|
|
100
|
+
assert np.allclose(get_component(q, "RR"), w)
|
|
101
|
+
assert np.allclose(get_component(q, "RI"), x)
|
|
102
|
+
assert np.allclose(get_component(q, "IR"), y)
|
|
103
|
+
assert np.allclose(get_component(q, "II"), z)
|
|
104
|
+
|
|
105
|
+
def test_get_component_raises_bad_select(self):
|
|
106
|
+
from spectrochempy_hypercomplex._quaternion import as_quaternion
|
|
107
|
+
from spectrochempy_hypercomplex._quaternion import get_component
|
|
108
|
+
|
|
109
|
+
q = as_quaternion(np.ones(3), np.zeros(3), np.ones(3), np.zeros(3))
|
|
110
|
+
with pytest.raises(ValueError, match="cannot interpret"):
|
|
111
|
+
get_component(q, "RRI")
|
|
112
|
+
|
|
113
|
+
def test_data_remains_real_noop(self):
|
|
114
|
+
from spectrochempy_hypercomplex._quaternion import get_component
|
|
115
|
+
|
|
116
|
+
arr = np.array([1.0, 2.0, 3.0])
|
|
117
|
+
result = get_component(arr, "RR")
|
|
118
|
+
assert np.array_equal(result, arr)
|
|
119
|
+
|
|
120
|
+
def test_interleaved2complex(self):
|
|
121
|
+
from spectrochempy_hypercomplex._quaternion import interleaved2complex
|
|
122
|
+
|
|
123
|
+
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
|
|
124
|
+
result = interleaved2complex(data)
|
|
125
|
+
expected = np.array([1.0 + 2.0j, 3.0 + 4.0j, 5.0 + 6.0j])
|
|
126
|
+
assert np.allclose(result, expected)
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# ruff: noqa: S101
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class TestHyperAccessor:
|
|
6
|
-
def test_accessor_registered(self):
|
|
7
|
-
import spectrochempy as scp
|
|
8
|
-
|
|
9
|
-
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
10
|
-
assert hasattr(ds, "hyper")
|
|
11
|
-
|
|
12
|
-
def test_is_quaternion_false_for_real(self):
|
|
13
|
-
import spectrochempy as scp
|
|
14
|
-
|
|
15
|
-
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
16
|
-
assert ds.hyper.is_quaternion is False
|
|
17
|
-
|
|
18
|
-
def test_set_quaternion_creates_quaternion_dtype(self):
|
|
19
|
-
import spectrochempy as scp
|
|
20
|
-
|
|
21
|
-
ds = scp.NDDataset([1.0, 2.0, 3.0, 4.0])
|
|
22
|
-
result = ds.hyper.set_quaternion()
|
|
23
|
-
# After conversion, the data should have a quaternion dtype
|
|
24
|
-
assert result._data.dtype.name == "quaternion"
|
|
25
|
-
|
|
26
|
-
def test_component_real_data_noop(self):
|
|
27
|
-
import spectrochempy as scp
|
|
28
|
-
|
|
29
|
-
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
30
|
-
# For real data, get_component returns the array unchanged
|
|
31
|
-
result = ds.hyper.component("RR")
|
|
32
|
-
assert result is not None
|
|
33
|
-
|
|
34
|
-
def test_RR_RI_IR_II_raise_for_real(self):
|
|
35
|
-
import spectrochempy as scp
|
|
36
|
-
|
|
37
|
-
ds = scp.NDDataset([1.0, 2.0, 3.0])
|
|
38
|
-
for prop in ["RR", "RI", "IR", "II"]:
|
|
39
|
-
with pytest.raises(TypeError):
|
|
40
|
-
getattr(ds.hyper, prop)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class TestNDMathHandlers:
|
|
44
|
-
def test_handler_registration(self):
|
|
45
|
-
from spectrochempy.plugins import manager
|
|
46
|
-
|
|
47
|
-
registry = manager.plugin_manager.registry
|
|
48
|
-
assert registry.get_handler("ndmath.execution_branch") is not None
|
|
49
|
-
assert registry.get_handler("ndmath.execute") is not None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|