ria-toolkit-oss/tests/utils/test_array_conversion.py
ben 9a960e2f29
Some checks failed
Build Sphinx Docs Set / Build Docs (pull_request) Failing after 1s
Build Project / Build Project (3.10) (pull_request) Successful in 57s
Build Project / Build Project (3.11) (pull_request) Successful in 1m7s
Build Project / Build Project (3.12) (pull_request) Successful in 56s
Test with tox / Test with tox (3.12) (pull_request) Failing after 5m13s
Test with tox / Test with tox (3.11) (pull_request) Failing after 5m48s
Test with tox / Test with tox (3.10) (pull_request) Failing after 8m46s
zfp functionality and servers
2026-03-31 13:51:10 -04:00

210 lines
6.1 KiB
Python
Raw RIA Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Unit tests for ria_toolkit_oss.utils.array_conversion.
Covers:
- is_1xn / is_2xn classification
- convert_to_1xn / convert_to_2xn conversion
- Round-trip invariance
- Error paths for invalid inputs
"""
import numpy as np
import pytest
from ria_toolkit_oss.utils.array_conversion import (
convert_to_1xn,
convert_to_2xn,
is_1xn,
is_2xn,
)
# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
COMPLEX_1XN = np.array([[1 + 2j, 3 + 4j, 5 + 6j]], dtype=np.complex128) # shape (1, 3)
REAL_2XN = np.array([[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]], dtype=np.float64) # shape (2, 3)
# ---------------------------------------------------------------------------
# is_1xn
# ---------------------------------------------------------------------------
def test_is_1xn_true_for_complex_1xn():
assert is_1xn(COMPLEX_1XN) is True
def test_is_1xn_false_for_real_2xn():
assert is_1xn(REAL_2XN) is False
def test_is_1xn_false_for_1d_complex():
arr = np.array([1 + 2j, 3 + 4j]) # 1-D
assert is_1xn(arr) is False
def test_is_1xn_false_for_3d():
arr = np.ones((1, 3, 3), dtype=np.complex128)
assert is_1xn(arr) is False
def test_is_1xn_false_for_real_1xn():
arr = np.array([[1.0, 2.0, 3.0]]) # real 1×N
assert is_1xn(arr) is False
def test_is_1xn_false_for_complex_2xn():
arr = np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]]) # complex 2×N
assert is_1xn(arr) is False
def test_is_1xn_single_sample():
arr = np.array([[1 + 0j]]) # shape (1, 1)
assert is_1xn(arr) is True
# ---------------------------------------------------------------------------
# is_2xn
# ---------------------------------------------------------------------------
def test_is_2xn_true_for_real_2xn():
assert is_2xn(REAL_2XN) is True
def test_is_2xn_false_for_complex_1xn():
assert is_2xn(COMPLEX_1XN) is False
def test_is_2xn_false_for_1d():
arr = np.array([1.0, 2.0, 3.0])
assert is_2xn(arr) is False
def test_is_2xn_false_for_3xn():
arr = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) # shape (3, 2)
assert is_2xn(arr) is False
def test_is_2xn_false_for_complex_2xn():
arr = np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]]) # complex 2×N
assert is_2xn(arr) is False
def test_is_2xn_single_column():
arr = np.array([[1.0], [2.0]]) # shape (2, 1)
assert is_2xn(arr) is True
# ---------------------------------------------------------------------------
# convert_to_2xn
# ---------------------------------------------------------------------------
def test_convert_to_2xn_from_1xn_shape():
result = convert_to_2xn(COMPLEX_1XN)
assert result.shape == (2, COMPLEX_1XN.shape[1])
def test_convert_to_2xn_from_1xn_values():
"""First row is real, second row is imaginary."""
result = convert_to_2xn(COMPLEX_1XN)
assert np.array_equal(result[0], COMPLEX_1XN[0].real)
assert np.array_equal(result[1], COMPLEX_1XN[0].imag)
def test_convert_to_2xn_from_1xn_is_real():
result = convert_to_2xn(COMPLEX_1XN)
assert not np.iscomplexobj(result)
def test_convert_to_2xn_from_2xn_is_copy():
"""Already-2xN input returns a copy (not the same object)."""
result = convert_to_2xn(REAL_2XN)
assert np.array_equal(result, REAL_2XN)
assert result is not REAL_2XN
def test_convert_to_2xn_invalid_raises():
"""1-D array is neither 1xN nor 2xN — must raise ValueError."""
arr = np.array([1.0, 2.0, 3.0])
with pytest.raises(ValueError):
convert_to_2xn(arr)
def test_convert_to_2xn_invalid_complex_2xn_raises():
"""Complex 2×N is not a recognised format — must raise ValueError."""
arr = np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]])
with pytest.raises(ValueError):
convert_to_2xn(arr)
# ---------------------------------------------------------------------------
# convert_to_1xn
# ---------------------------------------------------------------------------
def test_convert_to_1xn_from_2xn_shape():
result = convert_to_1xn(REAL_2XN)
assert result.shape == (1, REAL_2XN.shape[1])
def test_convert_to_1xn_from_2xn_values():
"""Real part from row 0, imaginary from row 1."""
result = convert_to_1xn(REAL_2XN)
assert np.array_equal(result[0].real, REAL_2XN[0])
assert np.array_equal(result[0].imag, REAL_2XN[1])
def test_convert_to_1xn_from_2xn_is_complex():
result = convert_to_1xn(REAL_2XN)
assert np.iscomplexobj(result)
def test_convert_to_1xn_from_1xn_is_copy():
"""Already-1xN input returns a copy (not the same object)."""
result = convert_to_1xn(COMPLEX_1XN)
assert np.array_equal(result, COMPLEX_1XN)
assert result is not COMPLEX_1XN
def test_convert_to_1xn_invalid_raises():
"""1-D array is neither 1xN nor 2xN — must raise ValueError."""
arr = np.array([1.0, 2.0, 3.0])
with pytest.raises(ValueError):
convert_to_1xn(arr)
def test_convert_to_1xn_invalid_3xn_raises():
"""3×N array is not a recognised format — must raise ValueError."""
arr = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
with pytest.raises(ValueError):
convert_to_1xn(arr)
# ---------------------------------------------------------------------------
# Round-trip invariance
# ---------------------------------------------------------------------------
def test_roundtrip_1xn_to_2xn_to_1xn():
"""1xN → 2xN → 1xN should recover the original values."""
intermediate = convert_to_2xn(COMPLEX_1XN)
recovered = convert_to_1xn(intermediate)
assert np.allclose(recovered, COMPLEX_1XN)
def test_roundtrip_2xn_to_1xn_to_2xn():
"""2xN → 1xN → 2xN should recover the original values."""
intermediate = convert_to_1xn(REAL_2XN)
recovered = convert_to_2xn(intermediate)
assert np.allclose(recovered, REAL_2XN)
def test_roundtrip_preserves_precision():
"""Values survive a double conversion with full float64 precision."""
data = np.array([[1.23456789 + 9.87654321j, -0.1 - 0.2j]], dtype=np.complex128)
recovered = convert_to_1xn(convert_to_2xn(data))
assert np.allclose(recovered, data, atol=1e-14)