Summary
bilateral() validates sigma_spatial > 0 but does not guard against values so small that 2 * sigma_spatial ** 2 underflows to a denormal or to zero. The Gaussian normalisation inv_2_ss = 1.0 / (2.0 * sigma_spatial * sigma_spatial) then becomes inf (or raises ZeroDivisionError under numba), and exp(-dist2 * inv_2_ss) evaluated at the center pixel produces 0.0 * inf = NaN. The whole output becomes NaN.
This is the MEDIUM-severity Cat 3 finding deferred from PR #1238 (the HIGH fix for #1236).
Reproducer
import numpy as np
import xarray as xr
from xrspatial import bilateral
raster = xr.DataArray(np.ones((10, 10)))
# sigma_spatial=1e-160 -> 2*sigma**2 = 2e-320 (denormal), inv_2_ss = inf
out = bilateral(raster, sigma_spatial=1e-160, sigma_range=1.0)
assert np.isnan(out.values).all()
# sigma_spatial=1e-200 -> 2*sigma**2 underflows to 0.0 -> ZeroDivisionError under numba
bilateral(raster, sigma_spatial=1e-200, sigma_range=1.0)
# ZeroDivisionError: division by zero
The same underflow pattern applies to sigma_range.
Threshold
2 * sigma**2 >= np.finfo(float64).tiny requires
sigma >= np.sqrt(np.finfo(float64).tiny / 2) ~= 1.05e-154. The cleanest
defensible bound is np.sqrt(np.finfo(float64).tiny) ~= 1.49e-154, which
keeps the squared term safely above the smallest normal float.
Proposed fix
Tighten the _validate_scalar bound on sigma_spatial and sigma_range from > 0 to >= sqrt(np.finfo(float64).tiny) and raise ValueError with a clear message naming the parameter and the minimum.
Context
Summary
bilateral()validatessigma_spatial > 0but does not guard against values so small that2 * sigma_spatial ** 2underflows to a denormal or to zero. The Gaussian normalisationinv_2_ss = 1.0 / (2.0 * sigma_spatial * sigma_spatial)then becomesinf(or raisesZeroDivisionErrorunder numba), andexp(-dist2 * inv_2_ss)evaluated at the center pixel produces0.0 * inf = NaN. The whole output becomesNaN.This is the MEDIUM-severity Cat 3 finding deferred from PR #1238 (the HIGH fix for #1236).
Reproducer
The same underflow pattern applies to
sigma_range.Threshold
2 * sigma**2 >= np.finfo(float64).tinyrequiressigma >= np.sqrt(np.finfo(float64).tiny / 2) ~= 1.05e-154. The cleanestdefensible bound is
np.sqrt(np.finfo(float64).tiny) ~= 1.49e-154, whichkeeps the squared term safely above the smallest normal float.
Proposed fix
Tighten the
_validate_scalarbound onsigma_spatialandsigma_rangefrom> 0to>= sqrt(np.finfo(float64).tiny)and raiseValueErrorwith a clear message naming the parameter and the minimum.Context