Skip to content

edge_detection tests never see Inf, boundary NaN, degenerate shapes, or multi-chunk dask #3682

Description

@brendancol

test_edge_detection.py measures well on paper (87 tests, 100% branch coverage of xrspatial/edge_detection.py with JIT disabled) but several input classes never appear in it. Found during a test-coverage audit of the module. Related sibling issues from the same audit: #3672 (benchmarks), #3674/#3676 (docstrings), #3675 (style), #3677 (scipy golden values). This one is about input-space gaps only.

Inf input: grep -ci inf xrspatial/tests/test_edge_detection.py returns 0. An inf cell propagates inf and NaN (from inf minus inf) through the 3x3 kernels. Verified all backends agree on this; nothing pins it.

NaN placement and NaN on GPU/dask: NaN input is only tested at an interior cell, only on the numpy backend. No test puts a NaN at the raster edge where it interacts with 'nearest'/'reflect'/'wrap' padding, and the cross-backend equivalence tests (cupy, dask+numpy, dask+cupy) all run on NaN-free ramp data. NaN-input backend divergence has shipped elsewhere in the library before (kde, #3628), so the parity tests should include NaN.

Degenerate shapes: the smallest raster tested is 3x3. 1x1, 1xN and Nx1 never appear. With boundary='nan' a 1x1 input comes back all-NaN; with 'reflect' it comes back 0. A (0, N) empty raster passes through and returns an empty result. None of this is asserted.

Invalid boundary: aspect, morphology, diffusion and bilateral each have a test that boundary='invalid' raises ValueError. edge_detection has none.

Dask chunking: both dask tests use a single chunk equal to the full array (chunks=(5, 6) on a 5x6 raster, chunks=(8, 10) on 8x10), so chunk-boundary stitching in the map_overlap path is never exercised from this module's tests, on dask+numpy or dask+cupy. The accuracy audit probed multi-chunk grids and found them correct, so this is a test gap, not a bug.

Dim names: outputs pass through agg.dims, but only the default y/x dims are tested. A regression that hardcoded dims=['y', 'x'] would pass today's suite.

I probed every case above on a CUDA host: numpy, cupy, dask+numpy and dask+cupy all agree, including NaN-at-corner under all four boundary modes and multi-chunk grids. So the source is fine today and this is test-only work: pin the current behavior so regressions in convolve_2d or the wrappers get caught here.

Probe excerpt (numpy vs dask+numpy chunks=(3, 4), NaN at corner and interior):

sobel_x boundary=nan: numpy==dask(multichunk) -> True
sobel_x boundary=nearest: numpy==dask(multichunk) -> True
... (all 20 func x mode combinations True, same for cupy and dask+cupy)
sobel_x 1x1 numpy: [[nan]]
sobel_x 1x1 boundary=reflect: [[0.]]
sobel_x boundary='bogus': ValueError: boundary must be one of ('nan', 'nearest', 'reflect', 'wrap'), got 'bogus'

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttestsTest coverage and parity

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions