up follow livre

This commit is contained in:
Tykayn 2025-08-30 18:14:14 +02:00 committed by tykayn
parent b4b4398bb0
commit 3a7a3849ae
12242 changed files with 2564461 additions and 6914 deletions

View file

@ -0,0 +1,12 @@
import numpy as np
# list of numarray data types
integer_types: list[str] = [
"int8", "uint8", "int16", "uint16",
"int32", "uint32", "int64", "uint64"]
float_types: list[str] = ["float32", "float64"]
complex_types: list[str] = ["complex64", "complex128"]
types: list[str] = integer_types + float_types

View file

@ -0,0 +1,21 @@
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 0 1 1 1
1 1 0 0 0 1 1
1 0 1 0 1 0 1
0 0 0 1 0 0 0
1 0 1 0 1 0 1
1 1 0 0 0 1 1
1 1 1 0 1 1 1
1 0 1 1 1 0 1
0 0 0 1 0 0 0
1 0 0 1 0 0 1
1 1 1 1 1 1 1
1 0 0 1 0 0 1
0 0 0 1 0 0 0
1 0 1 1 1 0 1

View file

@ -0,0 +1,294 @@
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
4 4 4 4 4 4 4
5 5 5 5 5 5 5
6 6 6 6 6 6 6
7 7 7 7 7 7 7
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 32 33 34 35
36 37 38 39 40 41 42
43 44 45 46 47 48 49
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 2 3 4 5 6 7
8 1 2 3 4 5 6
9 8 1 2 3 4 5
10 9 8 1 2 3 4
11 10 9 8 1 2 3
12 11 10 9 8 1 2
13 12 11 10 9 8 1
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 2 1 2 1 2 1
2 1 2 1 2 1 2
1 2 1 2 1 2 1
2 1 2 1 2 1 2
1 2 1 2 1 2 1
2 1 2 1 2 1 2
1 2 1 2 1 2 1
1 2 3 4 5 6 7
2 3 4 5 6 7 8
3 4 5 6 7 8 9
4 5 6 7 8 9 10
5 6 7 8 9 10 11
6 7 8 9 10 11 12
7 8 9 10 11 12 13
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 0 2 2 2
1 1 0 0 0 2 2
1 0 3 0 2 0 4
0 0 0 2 0 0 0
5 0 2 0 6 0 7
2 2 0 0 0 7 7
2 2 2 0 7 7 7
1 1 1 0 2 2 2
1 1 0 0 0 2 2
3 0 1 0 4 0 2
0 0 0 1 0 0 0
5 0 6 0 1 0 7
5 5 0 0 0 1 1
5 5 5 0 1 1 1
1 1 1 0 2 2 2
3 3 0 0 0 4 4
5 0 6 0 7 0 8
0 0 0 9 0 0 0
10 0 11 0 12 0 13
14 14 0 0 0 15 15
16 16 16 0 17 17 17
1 1 1 0 2 3 3
1 1 0 0 0 3 3
1 0 4 0 3 0 3
0 0 0 3 0 0 0
3 0 3 0 5 0 6
3 3 0 0 0 6 6
3 3 7 0 6 6 6
1 2 3 0 4 5 6
7 8 0 0 0 9 10
11 0 12 0 13 0 14
0 0 0 15 0 0 0
16 0 17 0 18 0 19
20 21 0 0 0 22 23
24 25 26 0 27 28 29
1 1 1 0 2 2 2
1 1 0 0 0 2 2
1 0 3 0 2 0 2
0 0 0 2 0 0 0
2 0 2 0 4 0 5
2 2 0 0 0 5 5
2 2 2 0 5 5 5
1 1 1 0 2 2 2
1 1 0 0 0 2 2
1 0 3 0 4 0 2
0 0 0 5 0 0 0
6 0 7 0 8 0 9
6 6 0 0 0 9 9
6 6 6 0 9 9 9
1 2 3 0 4 5 6
7 1 0 0 0 4 5
8 0 1 0 9 0 4
0 0 0 1 0 0 0
10 0 11 0 1 0 12
13 10 0 0 0 1 14
15 13 10 0 16 17 1
1 2 3 0 4 5 6
1 2 0 0 0 5 6
1 0 7 0 8 0 6
0 0 0 9 0 0 0
10 0 11 0 12 0 13
10 14 0 0 0 15 13
10 14 16 0 17 15 13
1 1 1 0 1 1 1
1 1 0 0 0 1 1
1 0 1 0 1 0 1
0 0 0 1 0 0 0
1 0 1 0 1 0 1
1 1 0 0 0 1 1
1 1 1 0 1 1 1
1 1 2 0 3 3 3
1 1 0 0 0 3 3
1 0 1 0 4 0 3
0 0 0 1 0 0 0
5 0 6 0 1 0 1
5 5 0 0 0 1 1
5 5 5 0 7 1 1
1 2 1 0 1 3 1
2 1 0 0 0 1 3
1 0 1 0 1 0 1
0 0 0 1 0 0 0
1 0 1 0 1 0 1
4 1 0 0 0 1 5
1 4 1 0 1 5 1
1 2 3 0 4 5 6
2 3 0 0 0 6 7
3 0 8 0 6 0 9
0 0 0 6 0 0 0
10 0 6 0 11 0 12
13 6 0 0 0 12 14
6 15 16 0 12 14 17
1 1 1 0 2 2 2
1 1 0 0 0 2 2
1 0 1 0 3 0 2
0 0 0 1 0 0 0
4 0 5 0 1 0 1
4 4 0 0 0 1 1
4 4 4 0 1 1 1
1 0 2 2 2 0 3
0 0 0 2 0 0 0
4 0 0 5 0 0 5
5 5 5 5 5 5 5
5 0 0 5 0 0 6
0 0 0 7 0 0 0
8 0 7 7 7 0 9
1 0 2 2 2 0 3
0 0 0 2 0 0 0
4 0 0 4 0 0 5
4 4 4 4 4 4 4
6 0 0 4 0 0 4
0 0 0 7 0 0 0
8 0 7 7 7 0 9
1 0 2 2 2 0 3
0 0 0 4 0 0 0
5 0 0 6 0 0 7
8 8 8 8 8 8 8
9 0 0 10 0 0 11
0 0 0 12 0 0 0
13 0 14 14 14 0 15
1 0 2 3 3 0 4
0 0 0 3 0 0 0
5 0 0 3 0 0 6
5 5 3 3 3 6 6
5 0 0 3 0 0 6
0 0 0 3 0 0 0
7 0 3 3 8 0 9
1 0 2 3 4 0 5
0 0 0 6 0 0 0
7 0 0 8 0 0 9
10 11 12 13 14 15 16
17 0 0 18 0 0 19
0 0 0 20 0 0 0
21 0 22 23 24 0 25
1 0 2 2 2 0 3
0 0 0 2 0 0 0
2 0 0 2 0 0 2
2 2 2 2 2 2 2
2 0 0 2 0 0 2
0 0 0 2 0 0 0
4 0 2 2 2 0 5
1 0 2 2 2 0 3
0 0 0 2 0 0 0
2 0 0 2 0 0 2
2 2 2 2 2 2 2
2 0 0 2 0 0 2
0 0 0 2 0 0 0
4 0 2 2 2 0 5
1 0 2 3 4 0 5
0 0 0 2 0 0 0
6 0 0 7 0 0 8
9 6 10 11 7 12 13
14 0 0 10 0 0 12
0 0 0 15 0 0 0
16 0 17 18 15 0 19
1 0 2 3 4 0 5
0 0 0 3 0 0 0
6 0 0 3 0 0 7
6 8 9 3 10 11 7
6 0 0 3 0 0 7
0 0 0 3 0 0 0
12 0 13 3 14 0 15
1 0 2 2 2 0 3
0 0 0 2 0 0 0
2 0 0 2 0 0 2
2 2 2 2 2 2 2
2 0 0 2 0 0 2
0 0 0 2 0 0 0
4 0 2 2 2 0 5
1 0 2 2 3 0 4
0 0 0 2 0 0 0
5 0 0 2 0 0 6
5 5 2 2 2 6 6
5 0 0 2 0 0 6
0 0 0 2 0 0 0
7 0 8 2 2 0 9
1 0 2 3 2 0 4
0 0 0 2 0 0 0
5 0 0 6 0 0 7
8 5 6 9 6 7 10
5 0 0 6 0 0 7
0 0 0 11 0 0 0
12 0 11 13 11 0 14
1 0 2 3 4 0 5
0 0 0 4 0 0 0
6 0 0 7 0 0 8
9 10 7 11 12 8 13
10 0 0 12 0 0 14
0 0 0 15 0 0 0
16 0 15 17 18 0 19
1 0 2 2 2 0 3
0 0 0 2 0 0 0
2 0 0 2 0 0 2
2 2 2 2 2 2 2
2 0 0 2 0 0 2
0 0 0 2 0 0 0
4 0 2 2 2 0 5

View file

@ -0,0 +1,42 @@
0 0 1
1 1 1
1 0 0
1 0 0
1 1 1
0 0 1
0 0 0
1 1 1
0 0 0
0 1 1
0 1 0
1 1 0
0 0 0
0 0 0
0 0 0
0 1 1
1 1 1
1 1 0
0 1 0
1 1 1
0 1 0
1 0 0
0 1 0
0 0 1
0 1 0
0 1 0
0 1 0
1 1 1
1 1 1
1 1 1
1 1 0
0 1 0
0 1 1
1 0 1
0 1 0
1 0 1
0 0 1
0 1 0
1 0 0
1 1 0
1 1 1
0 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,102 @@
import numpy as np
from scipy._lib._array_api import xp_assert_close
from scipy import ndimage
from scipy.ndimage import _ctest
from scipy.ndimage import _cytest
from scipy._lib._ccallback import LowLevelCallable
FILTER1D_FUNCTIONS = [
lambda filter_size: _ctest.filter1d(filter_size),
lambda filter_size: _cytest.filter1d(filter_size, with_signature=False),
lambda filter_size: LowLevelCallable(
_cytest.filter1d(filter_size, with_signature=True)
),
lambda filter_size: LowLevelCallable.from_cython(
_cytest, "_filter1d",
_cytest.filter1d_capsule(filter_size),
),
]
FILTER2D_FUNCTIONS = [
lambda weights: _ctest.filter2d(weights),
lambda weights: _cytest.filter2d(weights, with_signature=False),
lambda weights: LowLevelCallable(_cytest.filter2d(weights, with_signature=True)),
lambda weights: LowLevelCallable.from_cython(_cytest,
"_filter2d",
_cytest.filter2d_capsule(weights),),
]
TRANSFORM_FUNCTIONS = [
lambda shift: _ctest.transform(shift),
lambda shift: _cytest.transform(shift, with_signature=False),
lambda shift: LowLevelCallable(_cytest.transform(shift, with_signature=True)),
lambda shift: LowLevelCallable.from_cython(_cytest,
"_transform",
_cytest.transform_capsule(shift),),
]
def test_generic_filter():
def filter2d(footprint_elements, weights):
return (weights*footprint_elements).sum()
def check(j):
func = FILTER2D_FUNCTIONS[j]
im = np.ones((20, 20))
im[:10,:10] = 0
footprint = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
footprint_size = np.count_nonzero(footprint)
weights = np.ones(footprint_size)/footprint_size
res = ndimage.generic_filter(im, func(weights),
footprint=footprint)
std = ndimage.generic_filter(im, filter2d, footprint=footprint,
extra_arguments=(weights,))
xp_assert_close(res, std, err_msg=f"#{j} failed")
for j, func in enumerate(FILTER2D_FUNCTIONS):
check(j)
def test_generic_filter1d():
def filter1d(input_line, output_line, filter_size):
for i in range(output_line.size):
output_line[i] = 0
for j in range(filter_size):
output_line[i] += input_line[i+j]
output_line /= filter_size
def check(j):
func = FILTER1D_FUNCTIONS[j]
im = np.tile(np.hstack((np.zeros(10), np.ones(10))), (10, 1))
filter_size = 3
res = ndimage.generic_filter1d(im, func(filter_size),
filter_size)
std = ndimage.generic_filter1d(im, filter1d, filter_size,
extra_arguments=(filter_size,))
xp_assert_close(res, std, err_msg=f"#{j} failed")
for j, func in enumerate(FILTER1D_FUNCTIONS):
check(j)
def test_geometric_transform():
def transform(output_coordinates, shift):
return output_coordinates[0] - shift, output_coordinates[1] - shift
def check(j):
func = TRANSFORM_FUNCTIONS[j]
im = np.arange(12).reshape(4, 3).astype(np.float64)
shift = 0.5
res = ndimage.geometric_transform(im, func(shift))
std = ndimage.geometric_transform(im, transform, extra_arguments=(shift,))
xp_assert_close(res, std, err_msg=f"#{j} failed")
for j, func in enumerate(TRANSFORM_FUNCTIONS):
check(j)

View file

@ -0,0 +1,67 @@
""" Testing data types for ndimage calls
"""
import numpy as np
from scipy._lib._array_api import assert_array_almost_equal
import pytest
from scipy import ndimage
def test_map_coordinates_dts():
# check that ndimage accepts different data types for interpolation
data = np.array([[4, 1, 3, 2],
[7, 6, 8, 5],
[3, 5, 3, 6]])
shifted_data = np.array([[0, 0, 0, 0],
[0, 4, 1, 3],
[0, 7, 6, 8]])
idx = np.indices(data.shape)
dts = (np.uint8, np.uint16, np.uint32, np.uint64,
np.int8, np.int16, np.int32, np.int64,
np.intp, np.uintp, np.float32, np.float64)
for order in range(0, 6):
for data_dt in dts:
these_data = data.astype(data_dt)
for coord_dt in dts:
# affine mapping
mat = np.eye(2, dtype=coord_dt)
off = np.zeros((2,), dtype=coord_dt)
out = ndimage.affine_transform(these_data, mat, off)
assert_array_almost_equal(these_data, out)
# map coordinates
coords_m1 = idx.astype(coord_dt) - 1
coords_p10 = idx.astype(coord_dt) + 10
out = ndimage.map_coordinates(these_data, coords_m1, order=order)
assert_array_almost_equal(out, shifted_data)
# check constant fill works
out = ndimage.map_coordinates(these_data, coords_p10, order=order)
assert_array_almost_equal(out, np.zeros((3,4)))
# check shift and zoom
out = ndimage.shift(these_data, 1)
assert_array_almost_equal(out, shifted_data)
out = ndimage.zoom(these_data, 1)
assert_array_almost_equal(these_data, out)
@pytest.mark.xfail(True, reason="Broken on many platforms")
def test_uint64_max():
# Test interpolation respects uint64 max. Reported to fail at least on
# win32 (due to the 32 bit visual C compiler using signed int64 when
# converting between uint64 to double) and Debian on s390x.
# Interpolation is always done in double precision floating point, so
# we use the largest uint64 value for which int(float(big)) still fits
# in a uint64.
# This test was last enabled on macOS only, and there it started failing
# on arm64 as well (see gh-19117).
big = 2**64 - 1025
arr = np.array([big, big, big], dtype=np.uint64)
# Tests geometric transform (map_coordinates, affine_transform)
inds = np.indices(arr.shape) - 0.1
x = ndimage.map_coordinates(arr, inds)
assert x[1] == int(float(big))
assert x[2] == int(float(big))
# Tests zoom / shift
x = ndimage.shift(arr, 0.1)
assert x[1] == int(float(big))
assert x[2] == int(float(big))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,187 @@
import math
import numpy as np
from scipy._lib._array_api import (
xp_assert_equal,
assert_array_almost_equal,
assert_almost_equal,
is_cupy,
)
import pytest
from scipy import ndimage
skip_xp_backends = pytest.mark.skip_xp_backends
pytestmark = [skip_xp_backends(cpu_only=True, exceptions=['cupy', 'jax.numpy'])]
@skip_xp_backends('jax.numpy', reason="jax-ml/jax#23827")
class TestNdimageFourier:
@pytest.mark.parametrize('shape', [(32, 16), (31, 15), (1, 10)])
@pytest.mark.parametrize('dtype, dec', [("float32", 6), ("float64", 14)])
def test_fourier_gaussian_real01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
a = np.zeros(shape, dtype=dtype)
a[0, 0] = 1.0
a = xp.asarray(a)
a = fft.rfft(a, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_gaussian(a, [5.0, 2.5], shape[0], 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.irfft(a, n=shape[0], axis=0)
assert_almost_equal(ndimage.sum(a), xp.asarray(1), decimal=dec,
check_0d=False)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15)])
@pytest.mark.parametrize('dtype, dec', [("complex64", 6), ("complex128", 14)])
def test_fourier_gaussian_complex01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
a = np.zeros(shape, dtype=dtype)
a[0, 0] = 1.0
a = xp.asarray(a)
a = fft.fft(a, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_gaussian(a, [5.0, 2.5], -1, 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.ifft(a, n=shape[0], axis=0)
assert_almost_equal(ndimage.sum(xp.real(a)), xp.asarray(1.0), decimal=dec,
check_0d=False)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15), (1, 10)])
@pytest.mark.parametrize('dtype, dec', [("float32", 6), ("float64", 14)])
def test_fourier_uniform_real01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
a = np.zeros(shape, dtype=dtype)
a[0, 0] = 1.0
a = xp.asarray(a)
a = fft.rfft(a, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_uniform(a, [5.0, 2.5], shape[0], 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.irfft(a, n=shape[0], axis=0)
assert_almost_equal(ndimage.sum(a), xp.asarray(1.0), decimal=dec,
check_0d=False)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15)])
@pytest.mark.parametrize('dtype, dec', [("complex64", 6), ("complex128", 14)])
def test_fourier_uniform_complex01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
a = np.zeros(shape, dtype=dtype)
a[0, 0] = 1.0
a = xp.asarray(a)
a = fft.fft(a, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_uniform(a, [5.0, 2.5], -1, 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.ifft(a, n=shape[0], axis=0)
assert_almost_equal(ndimage.sum(xp.real(a)), xp.asarray(1.0), decimal=dec,
check_0d=False)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15)])
@pytest.mark.parametrize('dtype, dec', [("float32", 4), ("float64", 11)])
def test_fourier_shift_real01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
expected = np.arange(shape[0] * shape[1], dtype=dtype).reshape(shape)
expected = xp.asarray(expected)
a = fft.rfft(expected, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_shift(a, [1, 1], shape[0], 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.irfft(a, n=shape[0], axis=0)
assert_array_almost_equal(a[1:, 1:], expected[:-1, :-1], decimal=dec)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15)])
@pytest.mark.parametrize('dtype, dec', [("complex64", 4), ("complex128", 11)])
def test_fourier_shift_complex01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
expected = np.arange(shape[0] * shape[1], dtype=dtype).reshape(shape)
expected = xp.asarray(expected)
a = fft.fft(expected, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_shift(a, [1, 1], -1, 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.ifft(a, n=shape[0], axis=0)
assert_array_almost_equal(xp.real(a)[1:, 1:], expected[:-1, :-1], decimal=dec)
assert_array_almost_equal(xp.imag(a), xp.zeros(shape), decimal=dec)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15), (1, 10)])
@pytest.mark.parametrize('dtype, dec', [("float32", 5), ("float64", 14)])
def test_fourier_ellipsoid_real01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
a = np.zeros(shape, dtype=dtype)
a[0, 0] = 1.0
a = xp.asarray(a)
a = fft.rfft(a, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_ellipsoid(a, [5.0, 2.5], shape[0], 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.irfft(a, n=shape[0], axis=0)
assert_almost_equal(ndimage.sum(a), xp.asarray(1.0), decimal=dec,
check_0d=False)
@pytest.mark.parametrize('shape', [(32, 16), (31, 15)])
@pytest.mark.parametrize('dtype, dec', [("complex64", 5), ("complex128", 14)])
def test_fourier_ellipsoid_complex01(self, shape, dtype, dec, xp):
fft = getattr(xp, 'fft')
a = np.zeros(shape, dtype=dtype)
a[0, 0] = 1.0
a = xp.asarray(a)
a = fft.fft(a, n=shape[0], axis=0)
a = fft.fft(a, n=shape[1], axis=1)
a = ndimage.fourier_ellipsoid(a, [5.0, 2.5], -1, 0)
a = fft.ifft(a, n=shape[1], axis=1)
a = fft.ifft(a, n=shape[0], axis=0)
assert_almost_equal(ndimage.sum(xp.real(a)), xp.asarray(1.0), decimal=dec,
check_0d=False)
def test_fourier_ellipsoid_unimplemented_ndim(self, xp):
# arrays with ndim > 3 raise NotImplementedError
x = xp.ones((4, 6, 8, 10), dtype=xp.complex128)
with pytest.raises(NotImplementedError):
ndimage.fourier_ellipsoid(x, 3)
def test_fourier_ellipsoid_1d_complex(self, xp):
# expected result of 1d ellipsoid is the same as for fourier_uniform
for shape in [(32, ), (31, )]:
for type_, dec in zip([xp.complex64, xp.complex128], [5, 14]):
x = xp.ones(shape, dtype=type_)
a = ndimage.fourier_ellipsoid(x, 5, -1, 0)
b = ndimage.fourier_uniform(x, 5, -1, 0)
assert_array_almost_equal(a, b, decimal=dec)
@pytest.mark.parametrize('shape', [(0, ), (0, 10), (10, 0)])
@pytest.mark.parametrize('dtype', ["float32", "float64",
"complex64", "complex128"])
@pytest.mark.parametrize('test_func',
[ndimage.fourier_ellipsoid,
ndimage.fourier_gaussian,
ndimage.fourier_uniform])
def test_fourier_zero_length_dims(self, shape, dtype, test_func, xp):
if (
is_cupy(xp)
and test_func.__name__ == "fourier_ellipsoid"
and math.prod(shape) == 0
):
pytest.xfail("CuPy's fourier_ellipsoid does not accept size==0 arrays")
dtype = getattr(xp, dtype)
a = xp.ones(shape, dtype=dtype)
b = test_func(a, 3)
xp_assert_equal(a, b)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
import pytest
import numpy as np
from .._ni_support import _get_output
@pytest.mark.parametrize(
'dtype',
[
# String specifiers
'f4', 'float32', 'complex64', 'complex128',
# Type and dtype specifiers
np.float32, float, np.dtype('f4'),
# Derive from input
None,
],
)
def test_get_output_basic(dtype):
shape = (2, 3)
input_ = np.zeros(shape, dtype='float32')
# For None, derive dtype from input
expected_dtype = 'float32' if dtype is None else dtype
# Output is dtype-specifier, retrieve shape from input
result = _get_output(dtype, input_)
assert result.shape == shape
assert result.dtype == np.dtype(expected_dtype)
# Output is dtype specifier, with explicit shape, overriding input
result = _get_output(dtype, input_, shape=(3, 2))
assert result.shape == (3, 2)
assert result.dtype == np.dtype(expected_dtype)
# Output is pre-allocated array, return directly
output = np.zeros(shape, dtype=dtype)
result = _get_output(output, input_)
assert result is output
@pytest.mark.thread_unsafe
def test_get_output_complex():
shape = (2, 3)
input_ = np.zeros(shape)
# None, promote input type to complex
result = _get_output(None, input_, complex_output=True)
assert result.shape == shape
assert result.dtype == np.dtype('complex128')
# Explicit type, promote type to complex
with pytest.warns(UserWarning, match='promoting specified output dtype to complex'):
result = _get_output(float, input_, complex_output=True)
assert result.shape == shape
assert result.dtype == np.dtype('complex128')
# String specifier, simply verify complex output
result = _get_output('complex64', input_, complex_output=True)
assert result.shape == shape
assert result.dtype == np.dtype('complex64')
def test_get_output_error_cases():
input_ = np.zeros((2, 3), 'float32')
# Two separate paths can raise the same error
with pytest.raises(RuntimeError, match='output must have complex dtype'):
_get_output('float32', input_, complex_output=True)
with pytest.raises(RuntimeError, match='output must have complex dtype'):
_get_output(np.zeros((2, 3)), input_, complex_output=True)
with pytest.raises(RuntimeError, match='output must have numeric dtype'):
_get_output('void', input_)
with pytest.raises(RuntimeError, match='shape not correct'):
_get_output(np.zeros((3, 2)), input_)

View file

@ -0,0 +1,70 @@
"""Tests for spline filtering."""
import pytest
import numpy as np
from scipy._lib._array_api import assert_almost_equal
from scipy import ndimage
skip_xp_backends = pytest.mark.skip_xp_backends
pytestmark = [skip_xp_backends(cpu_only=True, exceptions=['cupy', 'jax.numpy'])]
def get_spline_knot_values(order):
"""Knot values to the right of a B-spline's center."""
knot_values = {0: [1],
1: [1],
2: [6, 1],
3: [4, 1],
4: [230, 76, 1],
5: [66, 26, 1]}
return knot_values[order]
def make_spline_knot_matrix(xp, n, order, mode='mirror'):
"""Matrix to invert to find the spline coefficients."""
knot_values = get_spline_knot_values(order)
# NB: do computations with numpy, convert to xp as the last step only
matrix = np.zeros((n, n))
for diag, knot_value in enumerate(knot_values):
indices = np.arange(diag, n)
if diag == 0:
matrix[indices, indices] = knot_value
else:
matrix[indices, indices - diag] = knot_value
matrix[indices - diag, indices] = knot_value
knot_values_sum = knot_values[0] + 2 * sum(knot_values[1:])
if mode == 'mirror':
start, step = 1, 1
elif mode == 'reflect':
start, step = 0, 1
elif mode == 'grid-wrap':
start, step = -1, -1
else:
raise ValueError(f'unsupported mode {mode}')
for row in range(len(knot_values) - 1):
for idx, knot_value in enumerate(knot_values[row + 1:]):
matrix[row, start + step*idx] += knot_value
matrix[-row - 1, -start - 1 - step*idx] += knot_value
return xp.asarray(matrix / knot_values_sum)
@pytest.mark.parametrize('order', [0, 1, 2, 3, 4, 5])
@pytest.mark.parametrize('mode', ['mirror', 'grid-wrap', 'reflect'])
def test_spline_filter_vs_matrix_solution(order, mode, xp):
n = 100
eye = xp.eye(n, dtype=xp.float64)
spline_filter_axis_0 = ndimage.spline_filter1d(eye, axis=0, order=order,
mode=mode)
spline_filter_axis_1 = ndimage.spline_filter1d(eye, axis=1, order=order,
mode=mode)
matrix = make_spline_knot_matrix(xp, n, order, mode=mode)
assert_almost_equal(eye, spline_filter_axis_0 @ matrix)
assert_almost_equal(eye, spline_filter_axis_1 @ matrix.T)