Skip to content

multi_stop_search crashes on dask+cupy input and returns numpy-backed output for cupy input #3630

Description

@brendancol

Describe the bug

multi_stop_search() mishandles GPU-backed inputs in its segment-stitching loop:

seg_data = seg.data
if hasattr(seg_data, 'get'):
    seg_vals = seg_data.get()  # cupy -> numpy
else:
    seg_vals = np.asarray(seg.values)
  1. dask+cupy input crashes. For a dask-of-cupy array, seg.data is a dask.array.Array (no .get), so the code falls into np.asarray(seg.values). Computing .values yields a cupy array and numpy raises TypeError: Implicit conversion to a NumPy array is not allowed. a_star_search itself handles dask+cupy, so the wrapper breaks a backend the underlying function supports. _optimize_waypoint_order has the same pattern, so optimize_order=True hits it too.

  2. cupy input returns a numpy-backed result. The stitched output is assembled in np.full(...) and never converted back, so a cupy (or dask) input comes back as a numpy-backed DataArray. a_star_search documents "DataArray of the same type as surface" and honors it; multi_stop_search quietly downgrades the backend. The existing test_multi_stop_cupy_matches_numpy doesn't catch this because its conversion expression is a no-op (x if not hasattr(x, 'get') else x).

Reproduction (run on this host, CUDA available):

import numpy as np, xarray as xr
import dask.array as da, cupy
from xrspatial import multi_stop_search

def make(backend):
    h = w = 8
    r = xr.DataArray(np.ones((h, w)), dims=['y', 'x'], attrs={'res': (1.0, 1.0)})
    r['y'] = np.linspace(h - 1, 0, h); r['x'] = np.linspace(0, w - 1, w)
    if 'dask' in backend:
        r.data = da.from_array(r.data, chunks=(4, 4))
    if 'cupy' in backend:
        r.data = r.data.map_blocks(cupy.asarray) if isinstance(r.data, da.Array) else cupy.asarray(r.data)
    return r

wps = [(7.0, 0.0), (4.0, 3.0), (0.0, 7.0)]

print(type(multi_stop_search(make('cupy'), wps).data))
# -> <class 'numpy.ndarray'>   (input was cupy)

multi_stop_search(make('dask+cupy'), wps)
# -> TypeError: Implicit conversion to a NumPy array is not allowed.

Expected behavior

  • dask+cupy input routes each segment through the already-working dask+cupy a_star_search path and returns a result instead of raising.
  • The returned DataArray is backed by the same array type as the input, matching a_star_search.

Additional context

Found by the accuracy sweep (Cat 5, backend inconsistency). The crash is rated HIGH (public API errors on a supported backend), the output-type downgrade MEDIUM. There is currently no dask+cupy test for multi_stop_search.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backend-coverageAdding missing dask/cupy/dask+cupy backend supportbugSomething isn't workinggpuCuPy / CUDA GPU support

    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