Skip to content

perf(grid): fill a fixed buffer of neighbours instead of a vector per vertex - #825

Merged
samueltardieu merged 2 commits into
evenfurther:mainfrom
tachsin:perf/grid-neighbour-buffer
Sep 11, 2026
Merged

samueltardieu merged 2 commits into
evenfurther:mainfrom
tachsin:perf/grid-neighbour-buffer

Conversation

@tachsin

@tachsin tachsin commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Closes #824.

Moves the body of neighbours into a private neighbours_into that writes into a fixed [(usize, usize); 8], and lets bfs_reachable and dfs_reachable use it directly, handing the search an array iterator rather than a vector.

neighbours keeps 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, 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 — together with the results of bfs_reachable and dfs_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:

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.

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
tachsin force-pushed the perf/grid-neighbour-buffer branch from b98b301 to 40e5f24 Compare September 10, 2026 19:05
@samueltardieu
samueltardieu added this pull request to the merge queue Sep 11, 2026
Merged via the queue into evenfurther:main with commit 2f02dc9 Sep 11, 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.

Grid allocates a vector of neighbours for every vertex it visits

2 participants