Conversation
Ties matter: on an open 120x120 grid with an exact heuristic, the order chosen between nodes of equal estimated cost is the difference between expanding 238 nodes and 14399, for the same path. With a fifth of the grid blocked it is 1046 against 7016. `astar` already lets the caller decide, and needed only to say so. It takes ties in order of decreasing cost from the start, which is the usual recommendation, and any other preference can be folded into the heuristic: express costs in units with room beneath a single step and put the tie-break in that room, where it can reorder the queue but never outweigh a real difference in cost. The documentation now shows that, since it is not something a reader would guess. `idastar` explored successors of equal estimated cost in whatever order an unstable sort left them. That happens to preserve the caller's order today, because the sort falls back to insertion sort on short slices, but nothing promises it. A stable sort makes the caller's order the tie-break by contract rather than by accident. It costs nothing measurable: 0.011 ms per run either way on a 65x65 grid, since both sorts are insertion sort at these lengths. No public API changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #681.
You asked in that thread how tie-breaking could be supported without modifying the public API of
astar/idastar. It turns out it can be, and mostly already is — this makes it real and documented rather than accidental. No public API changes.Ties are worth caring about
Expansion counts on a 120x120 grid, with the same optimal path returned every time:
h * (1 + 1/1024)So @cwoodhayes is right that the choice is significant — up to 60x here. Worth saying plainly, though: the current behaviour is already the one usually recommended, and it beat every alternative I tried. The value of choosing is in the unusual case, not the common one.
astaralready lets the caller decideEvery row of that table was produced without touching the library, purely through
heuristic. The queue orders by estimated cost and then prefers the larger cost from the start; the caller controls both the cost type'sOrdandh, so any preference that is a function ofg,hor the node can be folded into the heuristic by giving costs room beneath a single step:A term smaller than a step reorders the queue but can never outweigh a real difference in cost, so the path stays optimal. That is not something a reader would guess, so it is now a
# Tie-breakingsection onastarwith a runnable example.idastarneeded one wordIt sorted successors of equal estimated cost with
sort_unstable_by_key. The caller's order does survive that today — but only because the sort falls back to insertion sort on short slices, which happens to be stable. Nothing promises it.Now the order
successorsyields them in is the tie-break by contract. I measured it: 0.011 ms per run either way on a 65x65 grid, because both are insertion sort at these lengths.Tests
tests/tiebreak.rs: a sub-step term selects between equal-cost paths without changing their cost; the tie-break measurably changes how much of the graph is expanded while the path stays optimal; and reversing the orderidastaris given its successors reverses the path it returns.295 tests pass, clippy and rustfmt clean.
Worth your judgement
This answers the request by documenting a technique rather than adding a parameter. If you would rather have an explicit tie-break argument, that needs either a new function or a breaking change, and I did not want to presume either. @cwoodhayes offered to write a PR — if the documented approach does not cover the case that prompted the issue, it would be useful to hear what does.