Skip to content

perf(yen): skip the deviations an ancestor has already produced - #812

Merged
samueltardieu merged 1 commit into
evenfurther:mainfrom
tachsin:perf/yen-lawler
Sep 9, 2026
Merged

perf(yen): skip the deviations an ancestor has already produced#812
samueltardieu merged 1 commit into
evenfurther:mainfrom
tachsin:perf/yen-lawler

Conversation

@tachsin

@tachsin tachsin commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Closes #808.

Records where each route deviated from its parent and starts spurring from there — Lawler's refinement of Yen's algorithm.

make_cost goes away with it. Filtering removes whole node pairs rather than individual parallel edges, so the cheapest edge between two surviving nodes is the same in the filtered graph as in the full one, which means the cost of the root path plus the cost the search reports for the spur is exactly the cost of the concatenation. Prefix costs are computed once per route rather than once per candidate.

Checking

Verified against a brute-force enumeration of every loopless path over 150 random graphs, comparing the k cheapest costs, so a skipped deviation that should have produced a candidate would show up as a missing or more expensive path.

About 39% off twenty shortest paths across a 60x60 weighted grid, measured against this branch's parent.


Built on #798, which is included here as the first commit because this replaces the cost calculation that fix corrects. Review that one first; once it lands I will rebase this so only the second commit remains.

All timings measured on Windows 11, Intel Core Ultra 7 265K, 64 GB RAM.

Every accepted route is spurred at each of its nodes in turn, but a route
coincides with the one it was derived from up to the point where it deviates.
For a spur index before that point the root path, and the set of edges banned
at it, are the same as they were for the parent, so the search runs again and
produces a candidate that was already generated and rejected. Record where each
route deviated and start from there, which is Lawler's refinement of Yen's
algorithm.

The candidate's cost also no longer needs `make_cost`. Filtering removes whole
node pairs rather than individual parallel edges, so the cheapest edge between
two surviving nodes is the same in the filtered graph as in the full one, and
the cost of the root path plus the cost the search reports for the spur is
exactly the cost of the concatenation. The prefix costs of the route being
explored are computed once per route rather than once per candidate.

Checked against a brute-force enumeration of every loopless path over 150 random
graphs, comparing the k cheapest costs.

About 39% off twenty shortest paths across a 60x60 weighted grid.
@samueltardieu
samueltardieu added this pull request to the merge queue Sep 9, 2026
Merged via the queue into evenfurther:main with commit f1b71f9 Sep 9, 2026
12 checks passed
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.

yen re-runs spur searches whose candidates an ancestor already produced

2 participants