Skip to content

Commit faaff15

Browse files
ggkoganlucascolley
andauthored
ENH: ndimage: log(n) implementation for 1D rank filter (scipy#20543)
* ENH: rank filter for 1D cases log(n) complexity implementation Reviewed at scipy#20543 --------- Co-authored-by: Lucas Colley <[email protected]>
1 parent 4ffe88d commit faaff15

File tree

5 files changed

+414
-35
lines changed

5 files changed

+414
-35
lines changed

scipy/ndimage/_filters.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from . import _ni_support
3939
from . import _nd_image
4040
from . import _ni_docstrings
41+
from . import _rank_filter_1d
4142

4243
__all__ = ['correlate1d', 'convolve1d', 'gaussian_filter1d', 'gaussian_filter',
4344
'prewitt', 'sobel', 'generic_laplace', 'laplace',
@@ -1553,9 +1554,30 @@ def _rank_filter(input, rank, size=None, footprint=None, output=None,
15531554
raise RuntimeError(
15541555
"A sequence of modes is not supported by non-separable rank "
15551556
"filters")
1556-
mode = _ni_support._extend_mode_to_code(mode)
1557-
_nd_image.rank_filter(input, rank, footprint, output, mode, cval,
1558-
origins)
1557+
mode = _ni_support._extend_mode_to_code(mode, is_filter=True)
1558+
if input.ndim == 1:
1559+
if input.dtype in (np.int64, np.float64, np.float32):
1560+
x = input
1561+
x_out = output
1562+
elif input.dtype == np.float16:
1563+
x = input.astype('float32')
1564+
x_out = np.empty(x.shape, dtype='float32')
1565+
elif np.result_type(input, np.int64) == np.int64:
1566+
x = input.astype('int64')
1567+
x_out = np.empty(x.shape, dtype='int64')
1568+
elif input.dtype.kind in 'biu':
1569+
# cast any other boolean, integer or unsigned type to int64
1570+
x = input.astype('int64')
1571+
x_out = np.empty(x.shape, dtype='int64')
1572+
else:
1573+
raise RuntimeError('Unsupported array type')
1574+
cval = x.dtype.type(cval)
1575+
_rank_filter_1d.rank_filter(x, rank, footprint.size, x_out, mode, cval,
1576+
origin)
1577+
if input.dtype not in (np.int64, np.float64, np.float32):
1578+
np.copyto(output, x_out, casting='unsafe')
1579+
else:
1580+
_nd_image.rank_filter(input, rank, footprint, output, mode, cval, origins)
15591581
if temp_needed:
15601582
temp[...] = output
15611583
output = temp

scipy/ndimage/_ni_support.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import numpy as np
3535

3636

37-
def _extend_mode_to_code(mode):
37+
def _extend_mode_to_code(mode, is_filter=False):
3838
"""Convert an extension mode to the corresponding integer code.
3939
"""
4040
if mode == 'nearest':
@@ -47,8 +47,12 @@ def _extend_mode_to_code(mode):
4747
return 3
4848
elif mode == 'constant':
4949
return 4
50+
elif mode == 'grid-wrap' and is_filter:
51+
return 1
5052
elif mode == 'grid-wrap':
5153
return 5
54+
elif mode == 'grid-constant' and is_filter:
55+
return 4
5256
elif mode == 'grid-constant':
5357
return 6
5458
else:
@@ -121,7 +125,6 @@ def _check_axes(axes, ndim):
121125
raise ValueError("axes must be unique")
122126
return axes
123127

124-
125128
def _skip_if_dtype(arg):
126129
"""'array or dtype' polymorphism.
127130
@@ -138,4 +141,3 @@ def _skip_if_dtype(arg):
138141

139142
def _skip_if_int(arg):
140143
return None if (arg is None or isinstance(arg, int)) else arg
141-

scipy/ndimage/meson.build

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ py3.extension_module('_ni_label',
2525
subdir: 'scipy/ndimage'
2626
)
2727

28+
py3.extension_module('_rank_filter_1d',
29+
'src/_rank_filter_1d.cpp',
30+
link_args: version_link_args,
31+
install: true,
32+
dependencies: np_dep,
33+
subdir: 'scipy/ndimage'
34+
)
35+
2836
py3.extension_module('_ctest',
2937
'src/_ctest.c',
3038
dependencies: np_dep,

0 commit comments

Comments
 (0)