perf(grid): fill a fixed buffer of neighbours instead of a vector per vertex - #825
Merged
samueltardieu merged 2 commits intoSep 11, 2026
Merged
Conversation
The augmenting search asks `residual_successors` for the successors of every
node it looks at, and that returns a freshly allocated `Vec`. For the dense
representation the vector holds one entry per outgoing residual edge, so the
allocation is proportional to the size of the graph, and the search performs
one of them per node visited per augmentation.
Add `residual_successors_into`, which writes into a caller-owned buffer, and
let the search hold one buffer for the whole run. Both representations override
it; the default implementation defers to `residual_successors`, so the trait
stays usable by implementations outside the crate and this is not a breaking
change.
The flows, the value and the cut are untouched. Beyond the existing tests, both
representations were checked against the previous code on a layered 122-node
network, comparing the total, the number of flows, the size of the cut and a
fingerprint over every flow triple: identical for both.
Measured against this commit's parent, six passes with the order of the two
binaries swapped on alternate passes:
edmonds_karp, dense, 122-node layered network: about 72% off
edmonds_karp, sparse, 122-node layered network: at least 58% off
Measured on Windows 11, Intel Core Ultra 7 265K, 64 GB RAM.
… vertex
A vertex has at most eight neighbours, but `neighbours` collects them into a
freshly allocated `Vec` on every call, and `bfs_reachable` and `dfs_reachable`
call it once per vertex they visit. Walking a grid therefore allocates and
frees once per vertex, which costs more than the work being done.
Move the body into a private `neighbours_into` that writes into a fixed
`[(usize, usize); 8]`, and let the two traversals use it directly and hand the
search an array iterator. `neighbours` keeps its signature and its behaviour,
now built on the same buffer, so there is no duplicated logic.
Output is unchanged. Besides the existing tests, `neighbours` was compared
against the previous code over 7237 probes across 40 random grids — covering
both diagonal modes, both internal representations, and coordinates outside the
grid — along with the results of both traversals: identical fingerprint.
Measured against this commit's parent, four passes with the order of the two
binaries swapped on alternate passes:
Grid::bfs_reachable, 400x400 with 20 000 holes: about 18% off
Grid::dfs_reachable, 400x400 with 20 000 holes: about 22% off
Measured on Windows 11, Intel Core Ultra 7 265K, 64 GB RAM.
tachsin
force-pushed
the
perf/grid-neighbour-buffer
branch
from
September 10, 2026 19:05
b98b301 to
40e5f24
Compare
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 #824.
Moves the body of
neighboursinto a privateneighbours_intothat writes into a fixed[(usize, usize); 8], and letsbfs_reachableanddfs_reachableuse it directly, handing the search an array iterator rather than a vector.neighbourskeeps its signature and its behaviour, now built on the same buffer, so the logic exists in one place.Checking
All tests pass, clippy and rustfmt clean.
Beyond those,
neighbourswas compared against the previous code over 7237 probes across 40 random grids — covering both diagonal modes, both internal representations, and coordinates outside the grid — together with the results ofbfs_reachableanddfs_reachable. Identical fingerprint over everything returned, so this is not "faster because it returns less".Measured against this branch's parent, four passes with the order of the two binaries swapped on alternate passes, consistent in both directions:
Measured on Windows 11, Intel Core Ultra 7 265K, 64 GB RAM.