# ptwt -- the PyTorch Wavelet Toolbox: differentiable 1-D/2-D/3-D discrete, # stationary, continuous and packet wavelet transforms on torch tensors, checked # against PyWavelets. Pure Python. # # WHY IT IS HERE: DeepInverse's wavelet priors need it. deepinv.models.WaveletDenoiser # and WaveletDictDenoiser (the classic sparsity prior for MRI/CT reconstruction) and # the wavelet noise-level estimator import ptwt; without it they raise ImportError. # # Class 1 under docs/PACKAGING-POLICY.md: Fedora ships no package by this source # name and nothing provides python3dist(ptwt). Verified 2026-10-12: # dnf repoquery --whatprovides 'python3dist(ptwt)' -> empty # EUPL-1.2 is on Fedora's allowed list (ci/check-fedora-licence.py). %global pypi_name ptwt Name: python-%{pypi_name} Version: 1.0.1 Release: 1%{?dist} Summary: Differentiable fast wavelet transforms in PyTorch License: EUPL-1.2 URL: https://github.com/v0lta/PyTorch-Wavelet-Toolbox Source0: %{pypi_source %{pypi_name}} BuildArch: noarch BuildRequires: python3-devel BuildRequires: python3dist(pytest) BuildRequires: python3dist(pytest-xdist) BuildRequires: python3dist(scipy) %global _description %{expand: ptwt implements the fast wavelet transform and its relatives in PyTorch, so they run on the GPU and are differentiable: 1-D, 2-D and 3-D discrete wavelet transforms (convolution, matrix and separable forms, with boundary wavelets), the stationary and continuous transforms, and wavelet packets. It uses PyWavelets' filter banks, and its test suite checks every transform against PyWavelets.} %description %_description %package -n python3-%{pypi_name} Summary: %{summary} %description -n python3-%{pypi_name} %_description %prep %autosetup -p1 -n %{pypi_name}-%{version} # Build-time test shims, written to tests/conftest.py (not installed): # # 1. Seven test modules use scipy.datasets.face() as input. That fetches # face.dat with pooch on first use, and the build has no network. The tests # compare ptwt with PyWavelets on whatever image they get, so a fixed # pseudo-random image of the same shape and dtype (768x1024x3 uint8) # exercises the same code. # # 2. The CWT tests compare ptwt.cwt with pywt.cwt. ptwt follows PyWavelets 1.9, # whose only algorithmic change to cwt was raising the wavelet integration # precision from 2**10 to 2**12 samples (PyWavelets #531/#570, "a fix for a # long-standing problem with pywt.cwt"). Fedora still ships PyWavelets 1.8.0 # (f43 to rawhide, checked 2026-10-12), where 140 CWT cases then differ by # 1-40 percent. With 1.8's cwt run at precision 12 they agree to 1e-14, as # with 1.9 (checked against the 1.9.0 wheel). The shim does that, and only # when pywt.cwt has no precision argument, i.e. before 1.9. # Users comparing ptwt.cwt with Fedora's pywt.cwt will see the same 1.8/1.9 # difference until Fedora updates python-pywt. cat > tests/conftest.py <<'EOF' import inspect import numpy as np import pytest import pywt import pywt._cwt import scipy.datasets from pywt._functions import integrate_wavelet, scale2frequency def _offline_face(gray=False): rng = np.random.default_rng(20261012) img = rng.integers(0, 256, size=(768, 1024, 3), dtype=np.uint8) if gray: return (0.21 * img[..., 0] + 0.71 * img[..., 1] + 0.07 * img[..., 2]).astype(np.uint8) return img @pytest.fixture(autouse=True) def _no_download_face(monkeypatch): monkeypatch.setattr(scipy.datasets, "face", _offline_face) _PYWT_CWT_HAS_PRECISION = "precision" in inspect.signature(pywt.cwt).parameters @pytest.fixture(autouse=True) def _pywt_cwt_precision_12(monkeypatch): if _PYWT_CWT_HAS_PRECISION: return monkeypatch.setattr(pywt._cwt, "integrate_wavelet", lambda wavelet, precision=8: integrate_wavelet(wavelet, precision=12)) monkeypatch.setattr(pywt._cwt, "scale2frequency", lambda wavelet, scale, precision=8: scale2frequency(wavelet, scale, 12)) EOF %generate_buildrequires %pyproject_buildrequires %build %pyproject_wheel %install %pyproject_install # pdm-backend writes no PEP 639 License-File for this project; LICENSE is # listed in %%files by hand. %pyproject_save_files -L %{pypi_name} %check %pyproject_check_import # One torch thread per xdist worker: otherwise each of the N workers starts N # intra-op threads and the run is several times slower (load 41 on 8 cores). export OMP_NUM_THREADS=1 %pytest -c /dev/null --rootdir=. tests -p no:cacheprovider -n %{_smp_build_ncpus} -q -rs %files -n python3-%{pypi_name} -f %{pyproject_files} %license LICENSE %doc README.rst %changelog * Mon Oct 12 2026 Morgan Hough - 1.0.1-1 - Initial package: DeepInverse's wavelet denoisers and priors need it.