Skip to content

Raise on infeasible tours and honor snap in multi_stop_search optimize_order#3654

Open
brendancol wants to merge 2 commits into
mainfrom
deep-sweep-accuracy-pathfinding-2026-07-08-01
Open

Raise on infeasible tours and honor snap in multi_stop_search optimize_order#3654
brendancol wants to merge 2 commits into
mainfrom
deep-sweep-accuracy-pathfinding-2026-07-08-01

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Closes #3646

  • _optimize_waypoint_order now raises ValueError when Held-Karp's total cost is infinite. Previously best_last stayed -1, the reconstruction returned [start, end], and multi_stop_search(optimize_order=True) silently dropped every interior waypoint while returning a finite route. The optimize_order=False path already raises on the same input.
  • The pairwise distance matrix now reads each segment's cost at the true (snapped) goal pixel when snap=True, using the same max-finite-cost lookup as the segment loop. Before, a waypoint on an invalid cell got inf distance in every row even though snapping made it reachable, which fed the hole above.
  • The heuristic solver (_nearest_neighbor_2opt, N > 12) is untouched: it always returns a complete tour, and an infinite heuristic cost is not proof that no feasible tour exists, so the segment loop keeps raising no path between waypoints for that case.

Backends: the fix is in the ordering pass shared by all four backends (numpy, cupy, dask+numpy, dask+cupy); no backend-specific code changed.

Test plan:

  • test_optimize_order_unreachable_waypoint_raises (fails on main: returns a finite 2-waypoint route)
  • test_optimize_order_with_snap_keeps_waypoints (fails on main: drops the snapped waypoint)
  • pytest xrspatial/tests/test_pathfinding.py — 59 passed, including cupy and dask+cupy tests on a CUDA box
  • flake8 clean on changed lines

Also includes this sweep's state-CSV update.

https://claude.ai/code/session_0155N4QGamQVxgpAAPbpQNq4

…e_order (#3646)

_held_karp returned [start, end] when every full tour was infinite
(best_last stayed -1), so multi_stop_search(optimize_order=True)
silently dropped interior waypoints instead of raising like the
optimize_order=False path. Raise ValueError when the exact solver's
total cost is infinite.

The pairwise distance matrix also read each segment's cost at the
unsnapped goal pixel, so with snap=True any waypoint sitting on an
invalid cell got an infinite distance and fell into the same hole.
Use the max-finite-cost pixel as the true goal, matching the segment
loop.

Claude-Session: https://claude.ai/code/session_0155N4QGamQVxgpAAPbpQNq4

@brendancol brendancol left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Domain-aware review of the optimize_order fix.

Blockers

None.

Suggestions

  • The snap-relocation block (max-finite-cost pixel as the true goal) now exists twice: here and in the segment loop of multi_stop_search. Both copies are four lines and the loop variant also persists waypoint_pixels, so a shared helper is borderline; if a third caller shows up, extract one.
  • The raise is gated on the exact solver only. For N > 12 the heuristic tour can carry infinite legs and the failure surfaces later as no path between waypoints i and i+1 from the segment loop. That asymmetry is deliberate (an infinite heuristic cost does not prove infeasibility) and the PR body says so; worth keeping in mind if anyone later tightens the heuristic.

Nits

  • np.unravel_index returns numpy scalars for goal_py, goal_px; the subsequent dist[i][j] assignment and comparisons handle them fine, matching what the segment loop already does.

Verified locally: both new tests fail on main for the stated reasons (finite 2-waypoint route; dropped snapped waypoint) and pass with the fix; the full pathfinding suite (59) passes including cupy and dask+cupy on a CUDA box. The Held-Karp reconstruction path for feasible tours is untouched, and test_optimize_order_finds_better_route / test_optimize_order_preserves_endpoints still pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

multi_stop_search(optimize_order=True) silently drops waypoints when the distance matrix has no finite tour

1 participant