fix(scipy): relax STFT test tolerances
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# SciPy STFT test tolerances
|
||||
|
||||
The x86-64-v3 build can produce small floating-point residuals in inverse-STFT
|
||||
comparisons and scaling round trips. The original bounds reject these results,
|
||||
including residuals around `4e-17` where a round trip expects zero for a signal
|
||||
with amplitude 2.
|
||||
|
||||
## Scope and behavior
|
||||
|
||||
`stft-test-tolerances.patch` changes only the signal tests:
|
||||
|
||||
- The inverse-STFT comparison in `_scipy_spectral_test_shim.py` uses
|
||||
`max(1e-7, 2 * np.finfo(x.dtype).eps)` as its relative tolerance. Float64
|
||||
keeps the original bound, and the existing i686 override remains.
|
||||
- Three scaling round trips in `test_spectral.py` gain an absolute tolerance
|
||||
of one epsilon for the input dtype, allowing small residuals near zero.
|
||||
|
||||
The tests remain enabled, and the production STFT implementation is unchanged.
|
||||
|
||||
## Reproduction and focused checks
|
||||
|
||||
From this directory, apply the patch to a disposable SciPy 1.18.0 checkout:
|
||||
|
||||
```sh
|
||||
patch --fuzz=0 -d /path/to/scipy -p1 < stft-test-tolerances.patch
|
||||
```
|
||||
|
||||
Build and install that tree with SciPy's test dependencies. From outside the
|
||||
source directory, run the installed tests:
|
||||
|
||||
```sh
|
||||
python -m pytest --pyargs scipy.signal.tests.test_spectral \
|
||||
-k 'roundtrip_float32 or roundtrip_scaling' -q
|
||||
```
|
||||
|
||||
Use the same compiler flags and numerical libraries for before/after runs.
|
||||
The earlier reproduction called `TestSTFT.test_roundtrip_float32` and
|
||||
`TestSTFT.test_roundtrip_scaling` against the x86-64-v3 libraries, then loaded
|
||||
patched copies of the test modules. Both failed with the original bounds
|
||||
and passed with the adjusted bounds.
|
||||
|
||||
## Upstream status
|
||||
|
||||
[SciPy issue #25488](https://github.com/scipy/scipy/issues/25488) records
|
||||
related test failures with architecture-specific compiler flags. It is
|
||||
context for the local tolerance repair; this exact patch has not been
|
||||
submitted upstream during this work.
|
||||
|
||||
## Local NixOS integration and build results
|
||||
|
||||
[`../default.nix`](../default.nix) loads [`default.nix`](default.nix) through
|
||||
`pythonPackagesExtensions`, preserving the package's existing patches.
|
||||
The override also covers SciPy used to test other Python dependencies,
|
||||
including pgvector in portal's shared Python environment.
|
||||
|
||||
From the repository root:
|
||||
|
||||
```sh
|
||||
nix build --no-link -L .#nixosConfigurations.portal-1.pkgs.python314Packages.scipy
|
||||
```
|
||||
|
||||
The original remote build of patched SciPy 1.18.0 passed 87,723 tests, with
|
||||
8,342 skips, 300 expected failures, and 22 unexpected passes. The patch and
|
||||
override have been restored byte-for-byte from commit `24cbf74f`; those counts
|
||||
describe the earlier full build.
|
||||
|
||||
Restoration checks confirmed that the patch applies to the pinned source
|
||||
without fuzz, portal's evaluated SciPy retains its existing patch and install
|
||||
checks, and pgvector uses the patched SciPy. A full package or system rebuild
|
||||
was not repeated for this restoration.
|
||||
@@ -0,0 +1,5 @@
|
||||
{ scipy }:
|
||||
scipy.overridePythonAttrs (old: {
|
||||
# Keep the STFT tests enabled with tolerances for x86-64-v3 rounding.
|
||||
patches = (old.patches or [ ]) ++ [ ./stft-test-tolerances.patch ];
|
||||
})
|
||||
@@ -0,0 +1,51 @@
|
||||
Subject: [PATCH] signal: allow floating-point rounding in STFT tests
|
||||
|
||||
Keep the STFT tests enabled for x86-64-v3 builds. Allow two float32
|
||||
epsilons of relative error when comparing inverse-STFT implementations;
|
||||
float64 and the existing i686 override remain unchanged. Allow one
|
||||
float64 epsilon of absolute error in all three scaling round trips,
|
||||
which otherwise require exact zeros (observed residual: 4e-17 for a
|
||||
signal with amplitude 2).
|
||||
|
||||
Upstream issue: https://github.com/scipy/scipy/issues/25488
|
||||
|
||||
--- a/scipy/signal/tests/_scipy_spectral_test_shim.py
|
||||
+++ b/scipy/signal/tests/_scipy_spectral_test_shim.py
|
||||
@@ -294,7 +294,7 @@
|
||||
|
||||
# Adapted tolerances to account for resolution loss:
|
||||
atol = np.finfo(x.dtype).resolution*2 # instead of default atol = 0
|
||||
- rtol = 1e-7 # default for np.allclose()
|
||||
+ rtol = max(1e-7, 2 * np.finfo(x.dtype).eps)
|
||||
|
||||
# Relax atol on 32-Bit platforms a bit to pass CI tests.
|
||||
# - Not clear why there are discrepancies (in the FFT maybe?)
|
||||
--- a/scipy/signal/tests/test_spectral.py
|
||||
+++ b/scipy/signal/tests/test_spectral.py
|
||||
@@ -2044,7 +2044,7 @@
|
||||
|
||||
# Test round trip:
|
||||
x1 = istft(Zs, boundary=True, scaling='spectrum')[1]
|
||||
- assert_allclose(x1, x)
|
||||
+ assert_allclose(x1, x, atol=np.finfo(x.dtype).eps)
|
||||
|
||||
# For a Hann-windowed 256 sample length FFT, we expect a peak at
|
||||
# frequency 64 (since it is 1/4 the length of X) with a height of 1
|
||||
@@ -2074,7 +2074,7 @@
|
||||
|
||||
# Test round trip:
|
||||
x1 = istft(Zp, input_onesided=False, boundary=True, scaling='psd')[1]
|
||||
- assert_allclose(x1, x)
|
||||
+ assert_allclose(x1, x, atol=np.finfo(x.dtype).eps)
|
||||
|
||||
# The power of the one-sided psd-scaled STFT can be determined
|
||||
# analogously (note that the two sides are not of equal shape):
|
||||
@@ -2094,7 +2094,7 @@
|
||||
|
||||
# Test round trip:
|
||||
x1 = istft(Zp0, input_onesided=True, boundary=True, scaling='psd')[1]
|
||||
- assert_allclose(x1, x)
|
||||
+ assert_allclose(x1, x, atol=np.finfo(x.dtype).eps)
|
||||
|
||||
|
||||
class TestSampledSpectralRepresentations:
|
||||
Reference in New Issue
Block a user