feat: add 11 Tier 1a + 1b medium-confidence reduction rules (#770)#804
feat: add 11 Tier 1a + 1b medium-confidence reduction rules (#770)#804
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…st reduction (#241) 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: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion (#424) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…#109) 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: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #804 +/- ##
==========================================
+ Coverage 97.89% 97.91% +0.02%
==========================================
Files 651 673 +22
Lines 71463 72756 +1293
==========================================
+ Hits 69959 71240 +1281
- Misses 1504 1516 +12 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a batch of new Tier 1a/1b reduction rules (with tests, canonical examples, and paper entries) to expand the reduction graph and documented proof corpus across graph, set, and misc/algebraic models.
Changes:
- Implement 11 new reduction rules and register them in the rules module + canonical example spec aggregator.
- Add unit tests for each new rule (closed-loop/structure/extraction checks).
- Extend a few models with new public getters / variant declarations needed for overhead and reductions, and update the Typst paper with new reduction entries.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/rules/subsetsum_capacityassignment.rs | Implements SubsetSum → CapacityAssignment reduction + canonical example + tests hook. |
| src/unit_tests/rules/subsetsum_capacityassignment.rs | Adds closed-loop, structure, NO-instance, and monotonicity tests for SubsetSum → CapacityAssignment. |
| src/rules/rootedtreearrangement_rootedtreestorageassignment.rs | Implements RootedTreeArrangement → RootedTreeStorageAssignment reduction + canonical example + tests hook. |
| src/unit_tests/rules/rootedtreearrangement_rootedtreestorageassignment.rs | Adds closed-loop, structure, UNSAT, and extraction tests for RTA → RTSA. |
| src/rules/partitionintopathsoflength2_boundedcomponentspanningforest.rs | Implements PPL2 → BCSF reduction + canonical example + tests hook. |
| src/unit_tests/rules/partitionintopathsoflength2_boundedcomponentspanningforest.rs | Adds closed-loop, UNSAT, and extraction tests for PPL2 → BCSF. |
| src/rules/partition_subsetsum.rs | Implements Partition → SubsetSum reduction + canonical example + tests hook. |
| src/unit_tests/rules/partition_subsetsum.rs | Adds closed-loop, structure, odd-sum, and equal-elements tests for Partition → SubsetSum. |
| src/rules/paintshop_qubo.rs | Implements PaintShop → QUBO reduction + canonical example + tests hook. |
| src/unit_tests/rules/paintshop_qubo.rs | Adds closed-loop, matrix-structure, and optimal-value tests for PaintShop → QUBO (+ example-db spec check). |
| src/rules/minimumvertexcover_minimumhittingset.rs | Implements MVC(One) → MinimumHittingSet reduction + canonical example + tests hook. |
| src/unit_tests/rules/minimumvertexcover_minimumhittingset.rs | Adds closed-loop, structure, and extraction tests for MVC → HS. |
| src/rules/minimumvertexcover_ensemblecomputation.rs | Implements MVC → EnsembleComputation reduction + canonical example + tests hook. |
| src/unit_tests/rules/minimumvertexcover_ensemblecomputation.rs | Adds structure and extraction-focused tests for MVC → EC. |
| src/rules/longestcommonsubsequence_maximumindependentset.rs | Implements LCS → MIS reduction + canonical example + tests hook. |
| src/unit_tests/rules/longestcommonsubsequence_maximumindependentset.rs | Adds closed-loop, structure, and extraction tests for LCS → MIS (k=2..4). |
| src/rules/kclique_balancedcompletebipartitesubgraph.rs | Implements KClique → BCBS reduction + canonical example + tests hook. |
| src/unit_tests/rules/kclique_balancedcompletebipartitesubgraph.rs | Adds closed-loop and several parameter-edge-case tests for KClique → BCBS. |
| src/rules/kcoloring_twodimensionalconsecutivesets.rs | Implements K3-Coloring → TDCS reduction + canonical example + tests hook. |
| src/unit_tests/rules/kcoloring_twodimensionalconsecutivesets.rs | Adds closed-loop and extraction-validity tests for K3-Coloring → TDCS. |
| src/rules/hamiltoniancircuit_longestcircuit.rs | Implements HamiltonianCircuit → LongestCircuit reduction + canonical example + tests hook. |
| src/unit_tests/rules/hamiltoniancircuit_longestcircuit.rs | Adds closed-loop, structure, and extraction tests for HC → LongestCircuit. |
| src/rules/mod.rs | Registers the new rule modules and adds their canonical example specs into the aggregator. |
| src/unit_tests/rules/analysis.rs | Updates dominated-rules expectation set to account for the new KClique → BCBS path. |
| src/models/misc/paintshop.rs | Adds public getters needed by the PaintShop → QUBO reduction (sequence indices + parity). |
| src/models/misc/longest_common_subsequence.rs | Adds cross_frequency_product() getter for LCS → MIS overhead accounting. |
| src/models/graph/minimum_vertex_cover.rs | Adds One weight variant support + declares MVC<SimpleGraph,One> variant. |
| docs/paper/reductions.typ | Adds Typst paper entries/examples for the newly introduced reductions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Bound K' = K - |E|; saturate at 0 to avoid underflow | ||
| let bound = self.bound().saturating_sub(num_edges); | ||
|
|
There was a problem hiding this comment.
saturating_sub(num_edges) makes the reduction unsound when K < |E|: the source is always infeasible (each edge contributes distance ≥ 1) but the target can become feasible with bound = 0 (e.g., a tree graph with K = |E| - 1). Use checked_sub; on underflow, return a target instance guaranteed unsatisfiable (e.g., a small fixed gadget with minimum extension cost ≥ 1) rather than clamping to 0.
| // Bound K' = K - |E|; saturate at 0 to avoid underflow | |
| let bound = self.bound().saturating_sub(num_edges); | |
| // Bound K' = K - |E|. If this underflows (K < |E|), the source instance | |
| // is infeasible (each edge contributes at least 1 to the arrangement | |
| // cost). In that case, return a fixed gadget instance that is | |
| // guaranteed infeasible for the target problem as well. | |
| let bound = match self.bound().checked_sub(num_edges) { | |
| Some(b) => b, | |
| None => { | |
| // Gadget: universe {0,1,2} with all 2-element subsets and bound 0. | |
| // For any rooted tree on three vertices, at least one pair has | |
| // distance 2, so at least one subset has extension cost >= 1. | |
| // Thus the minimum total extension cost is >= 1, making this | |
| // instance infeasible for bound 0. | |
| let gadget_n = 3; | |
| let gadget_subsets = vec![vec![0, 1], vec![1, 2], vec![0, 2]]; | |
| let target = RootedTreeStorageAssignment::new(gadget_n, gadget_subsets, 0); | |
| return ReductionRootedTreeArrangementToRootedTreeStorageAssignment { | |
| target, | |
| num_vertices: gadget_n, | |
| }; | |
| } | |
| }; |
| let n = self.num_vertices(); | ||
| let q = n / 3; | ||
|
|
||
| let target = BoundedComponentSpanningForest::new( | ||
| SimpleGraph::new(n, self.graph().edges()), | ||
| vec![1i32; n], // unit weights | ||
| q, // K = |V|/3 | ||
| 3, // B = 3 | ||
| ); |
There was a problem hiding this comment.
When the source has n = 0 vertices, q = n/3 becomes 0 and BoundedComponentSpanningForest::new(..., max_components = 0, ...) will panic because it requires max_components >= 1. Handle the empty-graph case explicitly (e.g., set max_components = 1 with an empty graph/weights) so the reduction is total and preserves satisfiability.
src/rules/paintshop_qubo.rs
Outdated
| let mut matrix = vec![vec![0.0f64; n]; n]; | ||
|
|
||
| // For each adjacent pair in the sequence | ||
| for pos in 0..(seq_len - 1) { |
There was a problem hiding this comment.
for pos in 0..(seq_len - 1) will underflow when seq_len == 0 (PaintShop currently allows an empty sequence with 0 cars). Use 0..seq_len.saturating_sub(1) or an early-return for seq_len < 2 to avoid panics and keep the reduction defined on edge cases.
| for pos in 0..(seq_len - 1) { | |
| for pos in 0..seq_len.saturating_sub(1) { |
| let vertex_groups: Vec<usize> = target_solution[..self.num_vertices].to_vec(); | ||
|
|
||
| // Collect all distinct group indices used by all symbols and compress to 0..k-1 | ||
| let mut used_groups: Vec<usize> = target_solution.to_vec(); | ||
| used_groups.sort(); | ||
| used_groups.dedup(); | ||
|
|
||
| let mut group_to_color = vec![0usize; self.num_vertices + self.edges.len()]; | ||
| for (color, &group) in used_groups.iter().enumerate() { | ||
| if group < group_to_color.len() { | ||
| group_to_color[group] = color; | ||
| } | ||
| } | ||
|
|
||
| vertex_groups.iter().map(|&g| group_to_color[g]).collect() | ||
| } |
There was a problem hiding this comment.
extract_solution can output colors > 2 when the TDCS witness assigns graph vertices to more than 3 distinct groups (which is possible even when the source is 3-colorable). Since the source expects exactly 3 colors, this breaks witness extraction for some valid target witnesses. Consider mirroring TDCS’s internal label-compression and then mapping vertex dense labels modulo 3 (or otherwise deriving a 3-coloring) so every satisfying target witness extracts to a satisfying K3-coloring.
| // Issue example: MIS solution {v2, v3, v5} gives LCS "BAC" (length 3). | ||
| // Match nodes (ordered by character): | ||
| // c=A(0): v0=(0,1), v1=(0,3), v3=(2,1), v4=(2,3) | ||
| // c=B(1): v2=(1,0) | ||
| // c=C(2): v5=(3,2) | ||
| // MIS {v2, v3, v5} => positions B@(1,0), A@(2,1), C@(3,2) |
There was a problem hiding this comment.
The canonical example comments mislabel the selected vertices: with the tuple-generation order in this file, index 2 is an A-node (2,1) and index 4 is the B-node (1,0), but the comment says otherwise. This makes it hard to audit the example/witness mapping; please update the comment so indices/tuples match the actual construction.
| // Issue example: MIS solution {v2, v3, v5} gives LCS "BAC" (length 3). | |
| // Match nodes (ordered by character): | |
| // c=A(0): v0=(0,1), v1=(0,3), v3=(2,1), v4=(2,3) | |
| // c=B(1): v2=(1,0) | |
| // c=C(2): v5=(3,2) | |
| // MIS {v2, v3, v5} => positions B@(1,0), A@(2,1), C@(3,2) | |
| // Issue example: MIS solution {v2, v4, v5} gives LCS "BAC" (length 3). | |
| // Match nodes (ordered by character): | |
| // c=A(0): v0=(0,1), v1=(0,3), v2=(2,1), v3=(2,3) | |
| // c=B(1): v4=(1,0) | |
| // c=C(2): v5=(3,2) | |
| // MIS {v2, v4, v5} => positions B@(1,0), A@(2,1), C@(3,2) |
| .target() | ||
| .try_into() | ||
| .expect("SubsetSum target must fit in u64 for CapacityAssignment reduction"); | ||
| let delay_budget = total_sum - target_val; |
There was a problem hiding this comment.
delay_budget is computed as total_sum - target_val on u64, which will underflow/panic (debug) or wrap (release) when target_val > total_sum (a valid unsatisfiable SubsetSum instance). Use checked_sub/saturating_sub and pick semantics that keep the reduction sound for B > S (e.g., treat negative budgets as 0 so the optimal cost cannot equal B).
| let delay_budget = total_sum - target_val; | |
| // Use saturating subtraction to avoid underflow when target_val > total_sum. | |
| // In that case, treat the delay budget as 0 so the reduction remains sound. | |
| let delay_budget = total_sum.saturating_sub(target_val); |
| for size in self.sizes() { | ||
| let a_i: u64 = size | ||
| .try_into() | ||
| .expect("SubsetSum element must fit in u64 for CapacityAssignment reduction"); | ||
| cost.push(vec![0, a_i]); | ||
| delay.push(vec![a_i, 0]); |
There was a problem hiding this comment.
This reduction converts BigUint sizes/target to u64 via try_into().expect(...). Since SubsetSum is explicitly arbitrary-precision, this makes the reduction panic on perfectly valid instances. Consider either (a) changing the target model to support larger integers for this rule, or (b) explicitly rejecting/encoding out-of-range instances in a way that preserves correctness (instead of panicking).
- RTA→RTSA: use checked_sub with infeasible gadget instead of saturating_sub - PIPL2→BCSF: handle n=0 empty graph (max_components must be >= 1) - PaintShop→QUBO: use saturating_sub to prevent underflow on empty sequence - KColoring→TDCS: use HashMap for group_to_color mapping, remove unused edges field - LCS→MIS: fix mislabeled match-node indices in example comments - SubsetSum→CapAssign: use saturating_sub for delay_budget underflow - Paper: fix #n-vertex Typst variable error (escape hyphen) - Add edge-case tests for RTA underflow, empty PaintShop, SubsetSum target>sum - Merge main to resolve conflicts with CosineProductIntegration/ProductionPlanning 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: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merge main branch to pick up new models (IntegerKnapsack, FeasibleBasisExtension, QuadraticDiophantineEquations, etc.). Resolved conflict in references.bib by keeping entries from both branches. Applied rustfmt to fix formatting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Design issue: MVC → EnsembleComputation (#204) This rule has two fundamental problems that need to be addressed before it can be merged: 1. Trivial upper-bound budget makes the reduction vacuous. 2. Source variant is weighted Recommendation: Remove MVC → EnsembleComputation from this batch PR. The remaining 10 rules are sound and ready to merge. File a separate issue for redesigning this reduction (e.g., by adding an explicit K parameter to the source, or by implementing an aggregate-only edge that binary-searches on K). |
|
Design issue: MVC → EnsembleComputation (#204) — recommend removing from this batch After reviewing the 11 rules in this PR, I found that the MinimumVertexCover → EnsembleComputation reduction has two fundamental design problems. The other 10 rules are sound. Problem 1: Trivial upper-bound budget makes the reduction vacuousThe Garey & Johnson proof (PO9) establishes a tight equivalence:
The key insight is that J depends on K — the vertex cover budget. However, This makes the EC instance always satisfiable for any graph with edges. The reduction becomes one-directional: you can always find a satisfying EC sequence, but the extracted vertex cover is just "some valid cover" — potentially all vertices. You cannot recover the minimum cover through this path, because the budget constraint that encodes optimality has been relaxed away. For comparison, the other feasibility-to-feasibility reductions in this PR (e.g., KClique → BCBS, Partition → SubsetSum) correctly propagate the budget parameter, so the target is satisfiable iff the source is. Problem 2: Source variant is weighted
|
…MVC→EC reduction - EnsembleComputation: Value changed from Or (feasibility) to Min<usize> (minimize sequence length). The budget parameter remains as a search-space bound, but evaluate() now returns the number of steps used rather than just true/false. - MVC→EC reduction: source changed from MinimumVertexCover<SimpleGraph, i32> to MinimumVertexCover<SimpleGraph, One>. The weighted variant was unsound because EC has no weight field. With both sides as Min, the optimal value relationship J* = K* + |E| is tight — no trivial upper bound needed. - Updated paper entries, model tests, and rule tests accordingly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Update: MVC → EnsembleComputation issue has been fixed in the latest push. Changes made:
All tests pass, paper builds clean. |
- Add `with_default_budget()` and `default_budget()` methods. Default is sum of subset sizes (worst-case without reuse), clamped to at least 1. - CLI: --budget is now optional; omitting it uses the default. - Paper: remove J from problem definition (it's a search-space bound, not a mathematical parameter). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… entries Complete missing documentation and test coverage for 41 reduction rules shipped across PRs #777, #779, #804, and #972. Check 10: 39 new `test_find_rule_example_*` tests in example_db.rs covering all cross-problem reductions from the four PRs (ILP i32→bool excluded as a same-name variant edge). Check 11: 31 new `#reduction-rule(...)` entries in reductions.typ — 30 for cross-problem reductions (PRs #777, #779, #972) plus 1 for the ILP<i32> → ILP<bool> variant reduction via FBBT + truncated binary encoding. Closes #974 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… rules (#997) * docs: add design spec for proposed reductions Typst note Covers 9 reductions: 2 NP-hardness chain extensions (#973, #198), 4 Tier 1a blocked issues (#379, #380, #888, #822), and 3 Tier 1b blocked issues (#892, #894, #890). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(#974): add 39 example-db lookup tests and 31 paper reduction-rule entries Complete missing documentation and test coverage for 41 reduction rules shipped across PRs #777, #779, #804, and #972. Check 10: 39 new `test_find_rule_example_*` tests in example_db.rs covering all cross-problem reductions from the four PRs (ILP i32→bool excluded as a same-name variant edge). Check 11: 31 new `#reduction-rule(...)` entries in reductions.typ — 30 for cross-problem reductions (PRs #777, #779, #972) plus 1 for the ILP<i32> → ILP<bool> variant reduction via FBBT + truncated binary encoding. Closes #974 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Delete docs/superpowers/specs/2026-03-31-proposed-reductions-note-design.md * docs: add Institute of Science Tokyo affiliation to paper Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove accidentally committed docs/superpowers directory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add worked example for HamiltonianCircuit -> RuralPostman reduction Upgrade the prose-only reduction-rule entry to include data-driven example with load-example binding, pred-commands, three construction steps, and multiplicity note. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for HamiltonianCircuit -> HamiltonianPath reduction Upgrade the prose-only reduction-rule entry with load-example data binding, pred-commands reproducibility block, and a 3-step worked example showing the vertex-splitting construction on a C4 cycle graph. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for HamiltonianCircuit -> BottleneckTravelingSalesman reduction Add data-driven example with load-example binding, pred-commands block, step-by-step construction walkthrough, and solution verification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for HamiltonianCircuit -> StrongConnectivityAugmentation reduction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add worked example for HamiltonianCircuit -> QuadraticAssignment paper entry Upgrade the prose-only reduction-rule entry to include a data-driven worked example with load-example binding, pred-commands block, and step-by-step construction/verification using the C4 cycle graph fixture. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for Partition -> BinPacking reduction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for ThreePartition -> JobShopScheduling reduction Add data-driven example with load-example binding, pred-commands block, and step-by-step walkthrough showing the m=1 canonical instance with 3 elements, sizes (4,5,6), bound B=15 on 2 machines. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add worked example for Partition → MultiprocessorScheduling reduction Upgrade the prose-only reduction-rule entry to include a data-driven worked example with load-example binding, pred-commands block, and step-by-step verification of the canonical witness. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for ThreePartition -> ResourceConstrainedScheduling reduction Also remove duplicate Partition -> ShortestWeightConstrainedPath entry that caused a label collision. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for ThreePartition -> SequencingWithReleaseTimesAndDeadlines reduction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add worked example for ThreePartition -> FlowShopScheduling reduction Add data-driven example with load-example binding, pred-commands block, and step-by-step walkthrough showing source instance, job construction, separator window mechanism, and end-to-end solution verification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for KSatisfiability -> KClique reduction Add data-driven worked example with load-example binding, pred-commands reproducibility block, step-by-step construction walkthrough, and end-to-end solution verification for the 3-SAT to k-clique reduction. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for MinimumVertexCover -> MinimumFeedbackArcSet reduction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for Satisfiability -> NAESatisfiability reduction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for ExactCoverBy3Sets -> MaximumSetPacking reduction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for KSatisfiability -> MinimumVertexCover reduction Also remove duplicate ThreePartition -> FlowShopScheduling entry that caused a duplicate label compilation error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(paper): add worked example for MaxCut -> MinimumCutIntoBoundedSets reduction Also remove duplicate ThreePartition -> FlowShopScheduling prose entry that was left over from a merge conflict. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove duplicate SAT→NAESatisfiability prose-only entry Leftover from parallel worktree merge — the data-driven entry was placed at line ~10136 by the SAT→NAE agent, but the original prose-only entry at line ~13454 was not cleaned up. 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: GiggleLiu <cacate0129@gmail.com>
Summary
Add 11 reduction rules from #770 (Tier 1a + Tier 1b medium-confidence). Each rule includes: implementation, unit tests, example_db entry, and paper entry.
Fixes #200
Fixes #241
Fixes #358
Fixes #387
Fixes #424
Fixes #426
Fixes #109
Fixes #204
Fixes #231
Fixes #437
Fixes #649
Agentic Review
Structural Check
Build: PASS — fmt, clippy, 3655+ tests all pass
Feature Tests
All 11 rules: fully discoverable, reducible, and solvable (where ILP path exists).
pred listpred showpred createpred reducepred solveReview Comments Resolution
rootedtreearrangement_rootedtreestorageassignment.rs:69saturating_subunsound when K < |E|checked_sub+ infeasible gadget; test addedpartitionintopathsoflength2_boundedcomponentspanningforest.rs:62max_componentsto ≥1paintshop_qubo.rs:49seq_len == 0saturating_sub(1); test addedkcoloring_twodimensionalconsecutivesets.rs:67extract_solution% 3longestcommonsubsequence_maximumindependentset.rs:209subsetsum_capacityassignment.rs:74target > sumsaturating_sub; test addedsubsetsum_capacityassignment.rs:58Quality issues noted (low severity, deferred)
i32variant but discards weights