Skip to content

Run the restarts to the hard deadline and give FlowCutter the reserve - #52

Merged
guyvdbroeck merged 5 commits into
mainfrom
whole-wall-exp
Sep 4, 2026
Merged

Run the restarts to the hard deadline and give FlowCutter the reserve#52
guyvdbroeck merged 5 commits into
mainfrom
whole-wall-exp

Conversation

@guyvdbroeck

@guyvdbroeck guyvdbroeck commented Sep 4, 2026

Copy link
Copy Markdown
Member

On a residual at or under the threshold for the expensive orders, the restart
phase now runs to the hard deadline less a reserve for the trailing FlowCutter
candidate, not to the soft budget. The reserve is two estimated restarts scaled
by the rate the run has actually been going, so a loaded machine gets a bigger
reserve. The library also has a process-wide stop flag: once set, the deadline
checks answer as though the hard deadline had passed, and the separator loop and
the vendored backend read it too, the backend before its "we have a
decomposition" guard, so a run holding nothing is dropped. The command-line
tool sets the flag from a SIGTERM handler, so goatd writes its incumbent when
the harness stops it.

The reserve used to come from a fixed work-rate constant, the rate of an
unloaded machine, and the trailing candidate overran its window every time: on a
1,728 vertex primal graph, 206 ms over alone and 700 ms or more under load,
against a modelled restart of 172 ms. Under sixteen-way load, eleven of sixteen
runs of that graph were killed with nothing written; after the fix, ten returned
inside the deadline and two more wrote on the signal.

The only new public item is stop_flag() -> &'static AtomicBool: store true to
stop a solve, false before the next. No new builder methods.
PortfolioConfig::with_restarts_to_deadline and --capped-restarts keep their
signatures, but the restarts now end at the restart deadline rather than the
soft one. The handler adds a Unix-only libc dependency the binary alone uses.

Both arms on the field where each baseline runs at the setting its documentation
recommends:

Arm Nontrivial Exact best Within +1 Within +4
main 9,344 8,205 8,915 9,138
this branch 9,347 8,410 8,996 9,170

Over the 9,413 selected graphs, against main: 876 narrower, 8,387 equal, 81
wider; coverage gained 3, lost none; total bag size at equal width 1,857 better
against 1 worse, and under width 100, 768 better against 6. The
identical-binary repeat moves 46 views one way and 75 the other, so the
direction is far outside it. Against the branch's previous revision the width is
a wash inside that spread, 60 narrower and 99 wider; what it buys is the two
recovered graphs and a wall edge falling from 373 to 322 at or past 9,500 ms.

#53 has merged; both tables here are measured on its corrected field. #50 and
#51 are still open and will each regenerate their table after this one merges.

guyvdbroeck and others added 3 commits September 3, 2026 19:56
…eserve

The portfolio's soft deadline stopped the sampled restarts and the hedge's
weighted stages, and the trailing FlowCutter candidate then had the whole
second stage of the window to itself. On residuals small enough for the
expensive orders, more restart time lowers width on far more graphs than a
longer FlowCutter tail does, so the restart phase now runs to the hard
deadline less a 1.5 second reserve and FlowCutter runs in the reserve.

The initial candidates keep the soft deadline. So do the restarts on a
residual above the 10,000 vertex cutoff, and on any run with no hard
deadline; the soft deadline also stands where the reserve would fall before
it, on a hard window shorter than the reserve.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two candidates could end past the hard deadline, which left the caller no
time to write the decomposition. On a 1,728-vertex primal graph under a
4.75-second budget the restarts ran to their 8-second stop, the trailing
FlowCutter candidate returned at 9,626 ms against a 9,500 ms hard deadline,
and the result was lost.

The backend tests its deadline between restarts, so it returns up to one
restart after the timeout it was handed. The candidate now takes what is left
of the hard window less one estimated restart, from the same work-unit model
the metered path charges the backend with, and both the too-short window check
and the too-large graph check are made against that window.

The restart loop starts one more restart only while what the previous one
cost still fits before the restart deadline and the hard deadline. A restart
that runs into its deadline is stopped part-way and leaves nothing behind, so
the time is better left to the FlowCutter candidate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…er SIGTERM

The trailing FlowCutter candidate was given the hard window less one restart at
the work model's own rate. On a machine running one solve per core a restart
costs several times that, so the candidate returned after the deadline it was
sized for and the caller had no time to write the result. On a 1,728-vertex
primal graph under a 4.75-second budget, 11 of 16 copies run side by side on a
32-core box were killed at the ten-second wall with nothing written; the one
copy run alone returned 206 ms past its window.

The reserve is now two estimated restarts, which covers the restart the backend
can return late plus copying the result out of it a bag at a time, and it is
taken at the rate the run has actually been going: the wall time spent divided
by the graph work charged, never below the model's own rate. Under an armed
meter both numbers come from the same clock and the reserve is unchanged.

`stop_flag` ends a run from outside it. Once set, every deadline check answers
as an expired hard deadline does, in the vendored backend as well as in the
Rust code, and the caller gets the best decomposition found so far. The
command-line tool sets it from a SIGTERM handler that stores one byte and does
nothing else, so a caller running the tool under a wall clock of its own still
gets a decomposition rather than an empty file. That needs `libc` on Unix for
`sigaction`; the library itself makes no platform call.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every solver's row is remeasured on the field where each baseline runs at
its documented best setting.
@guyvdbroeck
guyvdbroeck marked this pull request as ready for review September 4, 2026 16:29
@guyvdbroeck
guyvdbroeck merged commit f1fccd2 into main Sep 4, 2026
15 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.

1 participant