Make solve deterministic with registered solver backends#1091
Open
isPANN wants to merge 3 commits into
Open
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1091 +/- ##
==========================================
- Coverage 98.00% 97.97% -0.04%
==========================================
Files 1044 1048 +4
Lines 107366 107945 +579
==========================================
+ Hits 105228 105755 +527
- Misses 2138 2190 +52 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
isPANN
marked this pull request as draft
July 21, 2026 06:22
isPANN
marked this pull request as ready for review
July 21, 2026 06:33
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.
This PR makes
solvedeterministic by separating registered solver execution from exploratory reduction-path search.1. Changed —
solveno longer searches for a reduction pathPreviously, solving a concrete problem could invoke reduction-path search at runtime. The selected route could therefore change when unrelated rules, search heuristics, or graph traversal order changed.
Now
solveonly executes a workflow registered for the exact source variant. Path discovery remains available through the separatepathcommand.This makes repeated calls operationally deterministic: the same exact variant selects the same workflow and reduction chain.
2. Added — an exact-variant solver registry
Registrations are keyed by the complete variant, not only by problem name. This prevents a capability registered for one representation from leaking into another representation.
For example, these are different registry keys:
A pipeline registered for the first key does not automatically claim support for either of the other two.
3. Added — seven native solver registrations
Existing dedicated algorithms are now registered as native solvers with stable implementation metadata. Native is a real source-problem solver: it does not mean “find a reduction path.”
Examples:
Native registrations derive their source variant from
Problem::variant, so the variant is not duplicated manually beside the problem type.4. Added — 151 fixed reduction-to-ILP workflows
The previously exported executable solve routes are registered as fixed pipelines. A pipeline may contain one or many reductions and may terminate at either directly supported ILP variant:
ILP<bool>orILP<i32>.Boolean-terminal example:
Integer-terminal example:
The second pipeline stops at
ILP<i32>. It does not continue through the availableILP<i32> -> ILP<bool>reduction merely to normalize the terminal type. Registry validation rejects a pipeline that continues after reaching the first directly supported ILP node.Direct ILP inputs require no reduction:
5. Changed — backend selection and fallback have fixed semantics
Default selection is:
Concrete examples:
TimetableDesignMaximumClique<SimpleGraph, i32>ILP<bool>, brute forceRootedTreeArrangement<SimpleGraph>ILP<i32>, brute forceMaxCut<SimpleGraph, i32>ILP<i32>--solver ilpexplicitly selects the registered reduction-to-ILP workflow. ForRootedTreeArrangement, this means reduce throughRootedTreeStorageAssignmenttoILP<i32>; it does not mean the source problem itself is an ILP.Fallback only selects an available workflow. It does not occur after execution begins. For example, if the selected ILP workflow reports an infeasible instance,
solvereturns the ILP no-solution result instead of silently rerunning brute force.--solver ilpalso fails when no pipeline is registered rather than searching for one.6. Added — structured execution metadata
CLI and MCP results now identify the workflow that actually executed.
Native example:
{ "kind": "native", "implementation": "rooted-tree-arrangement" }Reduction-to-ILP example:
{ "kind": "ilp", "reduction_path": [ "RootedTreeArrangement<SimpleGraph>", "RootedTreeStorageAssignment", "ILP<i32>" ] }Here
kind: "ilp"identifies the final backend;reduction_pathidentifies how the source reached that backend. Direct inputs use["ILP<bool>"]or["ILP<i32>"].Brute-force example:
{ "kind": "brute-force" }The execution object is returned under the top-level
solverfield alongsideproblem,evaluation, and the optionalsolution. Different backends must return an optimal source-problem solution, but this PR does not require them to choose the same lexicographically canonical witness.7. Added — exact solver capabilities in
inspectinspectexposes the same registry information without executing the problem. ForRootedTreeArrangement<SimpleGraph>, the relevant output has this shape:{ "solvers": ["native", "ilp", "brute-force"], "default_solver": "native", "solver_capabilities": { "native": { "implementation": "rooted-tree-arrangement" }, "ilp": { "reduction_path": [ "RootedTreeArrangement<SimpleGraph>", "RootedTreeStorageAssignment", "ILP<i32>" ] }, "brute_force": true } }Library, CLI, MCP, and reduction-bundle solving all read from the same resolver rather than maintaining separate capability rules.
8. Removed — search-based and ambiguous solver interfaces
Runtime path discovery and
CustomizedSolverare removed from solver dispatch. The public override accepts onlyilpandbrute-force;auto,customized,native, and internal implementation IDs are rejected.Native is not an override because a registered native solver is already the deterministic default. This avoids exposing implementation IDs such as
rooted-tree-arrangementas long-term CLI API.The old output field is also removed:
{ "reduced_to": "ILP" }It could not represent native or brute-force execution and did not say whether the source reduced to
ILP<bool>orILP<i32>. The structuredsolverobject in item 6 replaces it.9. Changed — shared dispatch code and shorter execution paths
CLI and MCP now share solver-selector parsing, capability rendering, and solve-result JSON rendering. Fixed pipeline edges are indexed once by exact source/target key instead of rescanning every registered reduction for every step.
Brute-force witness lookup now stops at the first optimal witness instead of collecting every optimal witness. An explicit brute-force request also returns before initializing the native/ILP registry.
The focused two-bit test demonstrates the traversal change when the first configuration is an optimal witness:
10. Added — registry validation and behavioral coverage
Registry construction now has direct tests for:
ILP<bool>orILP<i32>;Behavioral tests cover native-only, direct reduction to ILP, multi-hop reduction to ILP, native plus optional ILP workflow, brute-force-only, and direct
ILP<bool>/ILP<i32>cases. They also lock the threesolver.kindJSON forms, repeated-call determinism, explicit override behavior, and the rule that an infeasible selected ILP workflow does not fall back.Verification
cargo fmt --all -- --checkcargo clippy --all-targets --features ilp-highs -- -D warningscargo clippy -p problemreductions-cli --all-targets --features highs -- -D warningscargo test -p problemreductions solvers:: --features ilp-highs— 81 passedcargo test --test solver_routes_fixture --features 'ilp-highs example-db'— all 239 historical variants replayed (local-only fixture, intentionally not committed)make check— 5,402 library tests, 75 integration tests, 322 CLI tests, 17pred-symtests, and all doc tests passedCustomizedSolverCloses #1090