Describe the bug
bilateral() accepts boundary='nan' | 'nearest' | 'reflect' | 'wrap'. The numpy backend pads via _pad_array, and both dask backends forward the mode to map_overlap. The cupy backend drops it: in the _bilateral dispatcher, cupy_func=_bilateral_cupy is the only entry not wrapped in partial(..., boundary=boundary), and _bilateral_cupy has no boundary handling at all. Every mode behaves like boundary='nan' on cupy, with no warning or error.
import numpy as np
import xarray as xr
import cupy
from xrspatial import bilateral
rng = np.random.default_rng(7)
data = rng.standard_normal((12, 16)) * 10 + 100
for boundary in ('nan', 'nearest', 'reflect', 'wrap'):
r_np = bilateral(xr.DataArray(data), sigma_spatial=1.0, sigma_range=25.0,
boundary=boundary).data
r_cp = bilateral(xr.DataArray(cupy.asarray(data)), sigma_spatial=1.0,
sigma_range=25.0, boundary=boundary).data.get()
print(boundary, np.nanmax(np.abs(r_np - r_cp)))
Output:
nan 4.26e-14
nearest 2.90
reflect 1.45
wrap 3.08
The data has std ~10, so the edge-ring error for the non-default modes is around 30% of a standard deviation. Comparing cupy boundary='nearest' against numpy boundary='nan' gives max diff 4.26e-14: the parameter is ignored, not applied differently.
Expected behavior
cupy matches numpy for every boundary mode, the same way dask+cupy already does (it forwards the mode through _boundary_to_dask in map_overlap).
The existing boundary test (assert_boundary_mode_correctness) only compares numpy against dask+numpy, which is why this never showed up. A cupy boundary parity test should land with the fix.
Additional context
Found during an accuracy sweep of xrspatial/bilateral.py. _pad_array in xrspatial/utils.py already handles cupy arrays via cupy.pad, so the fix can mirror _bilateral_numpy_boundary.
Describe the bug
bilateral()acceptsboundary='nan' | 'nearest' | 'reflect' | 'wrap'. The numpy backend pads via_pad_array, and both dask backends forward the mode tomap_overlap. The cupy backend drops it: in the_bilateraldispatcher,cupy_func=_bilateral_cupyis the only entry not wrapped inpartial(..., boundary=boundary), and_bilateral_cupyhas no boundary handling at all. Every mode behaves likeboundary='nan'on cupy, with no warning or error.Output:
The data has std ~10, so the edge-ring error for the non-default modes is around 30% of a standard deviation. Comparing cupy
boundary='nearest'against numpyboundary='nan'gives max diff 4.26e-14: the parameter is ignored, not applied differently.Expected behavior
cupy matches numpy for every boundary mode, the same way dask+cupy already does (it forwards the mode through
_boundary_to_daskinmap_overlap).The existing boundary test (
assert_boundary_mode_correctness) only compares numpy against dask+numpy, which is why this never showed up. A cupy boundary parity test should land with the fix.Additional context
Found during an accuracy sweep of
xrspatial/bilateral.py._pad_arrayinxrspatial/utils.pyalready handles cupy arrays viacupy.pad, so the fix can mirror_bilateral_numpy_boundary.