Replace hardcoded canonical rule examples with ILPSolver calls#775
Replace hardcoded canonical rule examples with ILPSolver calls#775
Conversation
Convert 46 ILP reduction rules from hardcoded SolutionPair to dynamic ILPSolver::new().solve() calls, ensuring canonical examples actually verify the ILP solver can solve the reduction. Also adds a z upper bound constraint in MinMaxMulticenter ILP formulation to prevent HiGHS from stalling on unbounded [0, 2^31) domain. Closes #772 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…plate Add `rule_example_via_ilp<S, V>()` to `example_db::specs` that performs reduce → ILP solve → extract → assemble in one call. This replaces the 8-line block that was copy-pasted across 60 ILP rule files, and also eliminates the double `reduce_to()` call (once explicit, once inside `rule_example_with_witness`). Also fixes stale docstring on `build_example_db()` which incorrectly claimed no solver is called. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Canonical rule example convention changeAfter this PR, the standard pattern for #[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
vec![crate::example_db::specs::RuleExampleSpec {
id: "<source>_to_ilp",
build: || {
let source = /* construct instance */;
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source) // or i32
},
}]
}What changed:
For new ILP rules: just use |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #775 +/- ##
==========================================
- Coverage 97.80% 97.79% -0.01%
==========================================
Files 580 580
Lines 65742 65250 -492
==========================================
- Hits 64297 63811 -486
+ Misses 1445 1439 -6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR updates the example database infrastructure so canonical ILP reduction rule examples are computed dynamically by running the ILP solver (instead of relying on hardcoded SolutionPair witnesses), and it adds an explicit upper bound constraint in the MinMaxMulticenter→ILP formulation to improve HiGHS performance.
Changes:
- Introduce
rule_example_via_ilp<S, V>()helper to reduce→solve→extract and assemble canonical ILP rule examples in a single pass. - Replace hardcoded canonical
SolutionPairwitnesses across many ILP rule example specs with calls torule_example_via_ilp. - Add a
z <= z_upperconstraint to MinMaxMulticenter→ILP and update related unit tests.
Reviewed changes
Copilot reviewed 64 out of 64 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/example_db/specs.rs | Adds rule_example_via_ilp helper for dynamic ILP-based canonical rule examples. |
| src/example_db/mod.rs | Updates docs to reflect ILP examples are solved at build time (feature-gated). |
| src/rules/minmaxmulticenter_ilp.rs | Adds z upper-bound constraint and switches canonical example to rule_example_via_ilp. |
| src/unit_tests/rules/minmaxmulticenter_ilp.rs | Updates constraint-count expectation to include the new z bound. |
| src/unit_tests/example_db.rs | Relaxes IntegralFlowBundles→ILP example assertions (now solver-produced). |
| src/rules/undirectedflowlowerbounds_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/travelingsalesman_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/timetabledesign_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/sumofsquarespartition_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/subgraphisomorphism_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/steinertreeingraphs_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/steinertree_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/stackercrane_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/shortestweightconstrainedpath_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/sequencingwithreleasetimesanddeadlines_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/sequencingtominimizeweightedtardiness_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/sequencingtominimizeweightedcompletiontime_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/sequencingtominimizemaximumcumulativecost_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/schedulingwithindividualdeadlines_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/ruralpostman_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/resourceconstrainedscheduling_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/rectilinearpicturecompression_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/qubo_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/quadraticassignment_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/precedenceconstrainedscheduling_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/pathconstrainednetworkflow_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/partitionintotriangles_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/partitionintopathsoflength2_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/partiallyorderedknapsack_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/optimallineararrangement_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/naesatisfiability_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/multiprocessorscheduling_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/multiplecopyfileallocation_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/mixedchinesepostman_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumtardinesssequencing_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumsummulticenter_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumsetcovering_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimummultiwaycut_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumhittingset_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumfeedbackvertexset_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumfeedbackarcset_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/minimumdominatingset_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/maximumsetpacking_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/maximummatching_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/maximumclique_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/maximalis_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/longestpath_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/longestcommonsubsequence_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/longestcircuit_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/lengthboundeddisjointpaths_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/integralflowwithmultipliers_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/integralflowhomologousarcs_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/integralflowbundles_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/hamiltonianpath_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/flowshopscheduling_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/factoring_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/disjointconnectingpaths_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/directedtwocommodityintegralflow_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/consistencyofdatabasefrequencytables_ilp.rs | Uses rule_example_via_ilp for canonical example; adjusts dead-code gating on encoder helper. |
| src/rules/consecutiveblockminimization_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/capacityassignment_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/bottlenecktravelingsalesman_ilp.rs | Switches canonical example to rule_example_via_ilp. |
| src/rules/bmf_ilp.rs | Switches canonical example to rule_example_via_ilp. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/rules/mixedchinesepostman_ilp.rs
Outdated
| use crate::rules::ReduceTo as _; | ||
| use crate::topology::MixedGraph; |
There was a problem hiding this comment.
The use crate::rules::ReduceTo as _; import is no longer needed here (the example now uses rule_example_via_ilp) and will be unused under --features example-db. Please remove it to avoid warnings.
src/rules/ruralpostman_ilp.rs
Outdated
| #[cfg(feature = "example-db")] | ||
| pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> { | ||
| use crate::export::SolutionPair; | ||
| use crate::rules::ReduceTo as _; |
There was a problem hiding this comment.
use crate::rules::ReduceTo as _; is unused now that the canonical example calls rule_example_via_ilp and no longer calls reduce_to() directly. Please drop the import to avoid warnings when building the example DB.
src/rules/steinertreeingraphs_ilp.rs
Outdated
| use crate::rules::ReduceTo as _; | ||
|
|
There was a problem hiding this comment.
use crate::rules::ReduceTo as _; is unused in this example-spec function after moving to rule_example_via_ilp. Please remove it to avoid unused-import warnings under --features example-db.
| assert!(!example.solutions[0].source_config.is_empty()); | ||
| assert!(!example.solutions[0].target_config.is_empty()); |
There was a problem hiding this comment.
These assertions are very weak now: a non-empty config could still have the wrong length (which would make it invalid for the source problem / ILP). Consider asserting source_config.len() equals the number of arcs in the exported graph.arcs (for IntegralFlowBundles) and target_config.len() equals target.instance["num_vars"], which keeps the test solver-agnostic while still catching regressions in solution extraction/serialization.
src/rules/stackercrane_ilp.rs
Outdated
| #[cfg(feature = "example-db")] | ||
| pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> { | ||
| use crate::export::SolutionPair; | ||
| use crate::rules::ReduceTo as _; |
There was a problem hiding this comment.
use crate::rules::ReduceTo as _; is no longer needed here (the example now delegates to rule_example_via_ilp), so this import becomes unused when example-db is enabled. Please remove it to avoid warning noise in cargo test --features "example-db ilp-highs".
| use crate::rules::ReduceTo as _; | ||
|
|
There was a problem hiding this comment.
use crate::rules::ReduceTo as _; appears unused now that this canonical example uses rule_example_via_ilp instead of calling reduce_to() directly. Removing it will avoid an unused-import warning under --features example-db.
| use crate::rules::ReduceTo as _; |
| use crate::rules::ReduceTo as _; | ||
|
|
There was a problem hiding this comment.
use crate::rules::ReduceTo as _; is unused in this function after switching the example to rule_example_via_ilp. Please remove it to keep example-db builds warning-free.
| use crate::rules::ReduceTo as _; |
Agentic Review ReportStructural Check
Issue 1 (Medium): Formatting — ~32 files fail Issue 2 (Medium): Incorrect overhead expression in
Issue 3 (Low): 6 unused Copilot comment on Quality CheckDRY — Improvement with incomplete coverage. The KISS — OK. The helper is 15 lines, clear, does one thing. No over-engineering. HC/LC — OK. Helper lives in Issues:
Agentic Feature Tests
7/7 feature tests pass. Minor: 7 compiler warnings (unused imports/variables). Generated by review-pipeline |
- Fix indentation in ~32 canonical_rule_example_specs functions (cargo fmt) - Fix incorrect overhead in minmaxmulticenter_ilp: num_constraints formula was 2n²+4n+2, correct is 2n²+3n+2 (matching actual constraint count: 1 cardinality + n assignment + n² link + n x-bounds + n² y-bounds + 1 z-bound + n minimax) - Fix Vec::with_capacity hint to match corrected formula - Remove 6 unused `use crate::rules::ReduceTo as _;` imports in files that switched to rule_example_via_ilp Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
All review findings addressed in 49fc30f:
All CI checks pass. |
zazabap
left a comment
There was a problem hiding this comment.
Reviewed: all review findings addressed, CI green, overhead formula corrected.
Summary
SolutionPairto dynamicILPSolver::new().solve()via newrule_example_via_ilp<S, V>()helperexample_db::specs, eliminating ~700 lines of boilerplateConvention change
New ILP rule examples should use:
instead of hardcoding
SolutionPair. See PR comment for details.Test plan
cargo build --features example-db,ilpcompiles cleanlycargo test --features example-db,ilp— 3530 tests passrule_specs_solution_pairs_are_consistentvalidates all canonical examplesCloses #772
🤖 Generated with Claude Code