From fab51ad57e89c20ff891e98a928c0df65ec8b39d Mon Sep 17 00:00:00 2001 From: Anton Soloviev Date: Sat, 10 Oct 2026 02:26:16 -0700 Subject: [PATCH] BUG: preserve coefficients during inverse multiresolution analysis --- pywt/_mra.py | 4 +-- .../tests/test_imra_preserves_coefficients.py | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 pywt/tests/test_imra_preserves_coefficients.py diff --git a/pywt/_mra.py b/pywt/_mra.py index a41431e34..17d7d6fea 100644 --- a/pywt/_mra.py +++ b/pywt/_mra.py @@ -280,7 +280,7 @@ def imra2(mra_coeffs): Statistical Association Vol. 92, No. 439 (Sep., 1997), pp. 868-880. https://doi.org/10.2307/2965551 """ - rec = mra_coeffs[0] + rec = mra_coeffs[0].copy() for j in range(1, len(mra_coeffs)): for n in range(3): rec += mra_coeffs[j][n] @@ -427,7 +427,7 @@ def imran(mra_coeffs): Statistical Association Vol. 92, No. 439 (Sep., 1997), pp. 868-880. https://doi.org/10.2307/2965551 """ - rec = mra_coeffs[0] + rec = mra_coeffs[0].copy() for j in range(1, len(mra_coeffs)): for k, v in mra_coeffs[j].items(): rec += v diff --git a/pywt/tests/test_imra_preserves_coefficients.py b/pywt/tests/test_imra_preserves_coefficients.py new file mode 100644 index 000000000..0043816e5 --- /dev/null +++ b/pywt/tests/test_imra_preserves_coefficients.py @@ -0,0 +1,32 @@ +import numpy as np +import pytest +from numpy.testing import assert_allclose, assert_array_equal + +import pywt + + +@pytest.mark.parametrize('nd', [False, True]) +@pytest.mark.parametrize('stationary', [False, True]) +@pytest.mark.parametrize('readonly', [False, True]) +@pytest.mark.parametrize('dtype', ['float32', 'float64', 'complex64', 'complex128']) +def test_inverse_mra_preserves_coefficients(nd, stationary, readonly, dtype): + x = np.arange(64).reshape(8, 8).astype(dtype) + if x.dtype.kind == 'c': + x.imag = x[::-1].real + forward, inverse = (pywt.mran, pywt.imran) if nd else (pywt.mra2, pywt.imra2) + transform = ('swt' if stationary else 'dwt') + ('n' if nd else '2') + coeffs = forward(x, 'db1', level=2, transform=transform) + arrays = [coeffs[0]] + for details in coeffs[1:]: + arrays.extend(details.values() if nd else details) + original = [a.copy() for a in arrays] + if readonly: + for a in arrays: + a.flags.writeable = False + + first = inverse(coeffs) + for actual, expected in zip(arrays, original): + assert_array_equal(actual, expected) + second = inverse(coeffs) + assert_allclose(first, x, rtol=1e-5, atol=1e-5) + assert_array_equal(first, second)