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)
-
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.
-
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.
Describe the bug
multi_stop_search()mishandles GPU-backed inputs in its segment-stitching loop:dask+cupy input crashes. For a dask-of-cupy array,
seg.datais adask.array.Array(no.get), so the code falls intonp.asarray(seg.values). Computing.valuesyields a cupy array and numpy raisesTypeError: Implicit conversion to a NumPy array is not allowed.a_star_searchitself handles dask+cupy, so the wrapper breaks a backend the underlying function supports._optimize_waypoint_orderhas the same pattern, sooptimize_order=Truehits it too.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_searchdocuments "DataArray of the same type assurface" and honors it;multi_stop_searchquietly downgrades the backend. The existingtest_multi_stop_cupy_matches_numpydoesn'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):
Expected behavior
a_star_searchpath and returns a result instead of raising.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.