Skip to content

Commit 0f9db3c

Browse files
GiggleLiuclaude
andauthored
feat: batch add 14 reduction rules (hard rules phase 2) (#1028)
* feat: add PartitionIntoCliques to MinimumCoveringByCliques rule * feat: add 3SAT to RegisterSufficiency reduction (Sethi Reduction I) Implements Sethi's Reduction I / Theorem 3.11 for KSatisfiability<K3> → RegisterSufficiency with corrected extraction (stop at w[n], read x_pos[k], "at most one"). Also adds RegisterSufficiency → ILP companion rule. Closes #872 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add DecisionMinimumVertexCover to HamiltonianCircuit reduction * feat: add DecisionMinimumDominatingSet to MinMaxMulticenter * feat: add DecisionMinimumDominatingSet to MinimumSumMulticenter * style: fix rustfmt formatting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add KColoring to Clustering reduction * Add ExactCoverBy3Sets to MinimumAxiomSet reduction * Fix MaximumLikelihoodRanking constructor validation * fix: allow negative entries in MaximumLikelihoodRanking (c=0 skew-symmetric) The GJ definition uses "antisymmetric" which means a_ij + a_ji = c including c=0 (skew-symmetric with negative entries). Remove the non-negative constraint, keep constant-sum validation. Add test for c=0 encoding of a directed 3-cycle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add x3c to fault detection test set reduction * feat: add MinimumFeedbackArcSet to MaximumLikelihoodRanking reduction * feat: add fvs to unlimited-register codegen rule * feat: add mvc to minimum weight and/or graph reduction * Add 3-SAT to quadratic diophantine equations reduction * test: pin max2sat maxcut affine relation * fix: resolve clippy warnings and test assertion after new reductions - Fix manual_memcpy and needless_range_loop in FVS→CodeGen reduction - Fix manual_div_ceil in QuadraticDiophantineEquations - Allow too_many_arguments for bounded path search - Relax find_paths_up_to test assertion for bounded search behavior - Apply rustfmt to touched files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add B&B solver for RegisterSufficiency, avoid slow ILP in tests The KSat→RS canonical example builds a 70-vertex RegisterSufficiency instance. Solving it through the RS→ILP chain (17K vars, 52K constraints) took 50+ seconds locally and timed out CI at 56 minutes. Add solve_exact() to RegisterSufficiency: a branch-and-bound solver with heuristic candidate ordering (prefer vertices that free the most registers). YES instances resolve instantly on the first greedy path without backtracking. For NO instances the full search tree must be explored, so the ILP path is kept for infeasibility proofs. Test time for KSat→RS suite: 278s → 9s. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add Clustering→ILP and MinimumFaultDetectionTestSet→ILP reductions Clustering→ILP: binary assignment variables x[i,c], exact-one-cluster constraints per element, conflict constraints for violated distance pairs. Feasibility formulation (minimize 0). O(n·K) variables, O(n + n²·K) constraints. MinimumFaultDetectionTestSet→ILP: binary selection variables per input-output pair, covering constraints requiring each internal vertex appears in at least one selected pair's coverage set. Minimize total selected pairs. O(|I|·|O|) variables, O(internal vertices) constraints. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: structural review fixes — overheads, paper entries, test speedup - Fix Clustering→ILP overhead: use n*(n-1)/2 instead of n² for pair count - Fix MFDTS→ILP overhead: num_constraints covers internal vertices only - Add num_edges to Decision<MDS>→MinSumMulticenter overhead - Add 3 missing paper reduction-rule entries (KSat→QDE, FVS→CodeGen, MVC→AndOrGraph) - Rename DecisionMVC→HC test to include closed_loop - Replace slow KSat→RS UNSAT test (ILP on 17K vars) with BF + structural check - Add 5s test time limit rule to CLAUDE.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: speed up BMF→ILP closed-loop test (36s → 0.01s) Use ILP solver on target + brute force on source instead of brute-force enumerating all 2^24 ILP configurations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: model_specs_are_optimal stuck on DecisionMVC→HC→QA→ILP chain The new DecisionMVC→HamiltonianCircuit reduction created a path DecisionMVC → HC(50 verts) → QA(2500 vars) → ILP that HiGHS can't solve in reasonable time. Fix: try brute force first for small instances (≤2^20 configs) before falling back to ILP via reduction. DecisionMVC with 4 vertices has only 16 configs — instant via brute force. Also add CLAUDE.md note: overhead expressions describe scaling, not exact sizes — read reduce_to() code for actual sizes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add witness edge for Decision<P> → P, enabling cheaper ILP paths Previously Decision<P> → P was aggregate-only, forcing witness-mode path search through expensive chains (e.g., DecisionMVC → HC → QA → ILP). Now the edge supports both witness and aggregate modes — a P-witness meeting the bound is directly a Decision<P> witness (identity config). - Add DecisionToOptimizationWitnessResult and ReduceTo<P> for Decision<P> - Merge register_decision_variant! macro to emit single both() edge - Add witness edge + canonical example for Decision<MDS<SG,One>> variant - Update dominated rules allow-list (KSat→MVC now dominated via DecisionMVC) - Fix CLI truncation test (MIS→QUBO path count changed due to new edges) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: paper build errors — cast QDE strings to int, fix missing optimal_value keys - Cast a/b/c from JSON strings to int for QuadraticDiophantineEquations example - Compute MVC→AndOrGraph target weight from arc_weights instead of missing optimal_value - Compute FVS→CodeGen instruction count from target_config length instead of missing optimal_value Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add coverage for find_paths_up_to_mode_bounded Exercises the bounded path search with tight and zero intermediate-node limits, covering the previously-untested function body in graph.rs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8cd6ac1 commit 0f9db3c

File tree

60 files changed

+5660
-291
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+5660
-291
lines changed

.claude/CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ impl ReduceTo<Target> for Source { ... }
176176
- Expression strings are parsed at compile time by a Pratt parser in the proc macro crate
177177
- Variable names are validated against actual getter methods on the source type — typos cause compile errors
178178
- Each problem type provides inherent getter methods (e.g., `num_vertices()`, `num_edges()`) that the overhead expressions reference
179+
- **Overhead expressions describe scaling (asymptotic upper bounds), not exact sizes.** To determine the actual target problem size for a specific instance, read the `reduce_to()` construction code and count the actual variables/constraints/vertices built.
179180
- `ReductionOverhead` stores `Vec<(&'static str, Expr)>` — field name to symbolic expression mappings
180181
- `ReductionEntry` has both symbolic (`overhead_fn`) and compiled (`overhead_eval_fn`) evaluation — the compiled version calls getters directly
181182
- `VariantEntry` has both a complexity string and compiled `complexity_eval_fn` — same pattern
@@ -226,6 +227,8 @@ Reduction graph nodes use variant key-value pairs from `Problem::variant()`:
226227

227228
## Testing Requirements
228229

230+
**No single test should take more than 5 seconds.** If a test requires solving a large instance (e.g., ILP with thousands of variables), use a smaller test instance or a faster solver. Tests that exceed 5s block CI and must be refactored.
231+
229232
**Reference implementations — read these first:**
230233
- **Reduction test:** `src/unit_tests/rules/minimumvertexcover_maximumindependentset.rs` — closed-loop pattern
231234
- **Model test:** `src/unit_tests/models/graph/maximum_independent_set.rs` — evaluation, serialization

docs/paper/reductions.typ

Lines changed: 526 additions & 9 deletions
Large diffs are not rendered by default.

docs/paper/references.bib

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,17 @@ @article{brucker1977
164164
doi = {10.1016/S0167-5060(08)70743-X}
165165
}
166166

167+
@incollection{brucker1978clustering,
168+
author = {Peter Brucker},
169+
title = {On the Complexity of Clustering Problems},
170+
booktitle = {Optimization and Operations Research},
171+
series = {Lecture Notes in Economics and Mathematical Systems},
172+
volume = {157},
173+
pages = {45--54},
174+
publisher = {Springer},
175+
year = {1978}
176+
}
177+
167178
@article{lawler1977,
168179
author = {Eugene L. Lawler},
169180
title = {A pseudopolynomial algorithm for sequencing jobs to minimize total tardiness},
@@ -242,6 +253,28 @@ @book{garey1979
242253
year = {1979}
243254
}
244255

256+
@article{orlin1977,
257+
author = {James B. Orlin},
258+
title = {Contentment in Graph Theory: Covering Graphs with Cliques},
259+
journal = {Indagationes Mathematicae (Proceedings)},
260+
volume = {80},
261+
number = {5},
262+
pages = {406--424},
263+
year = {1977},
264+
doi = {10.1016/1385-7258(77)90055-5}
265+
}
266+
267+
@article{kouStockmeyerWong1978,
268+
author = {Lawrence T. Kou and Larry J. Stockmeyer and C. K. Wong},
269+
title = {Covering Edges by Cliques with Regard to Keyword Conflicts and Intersection Graphs},
270+
journal = {Communications of the ACM},
271+
volume = {21},
272+
number = {2},
273+
pages = {135--139},
274+
year = {1978},
275+
doi = {10.1145/359340.359346}
276+
}
277+
245278
@article{galilMegiddo1977,
246279
author = {Zvi Galil and Nimrod Megiddo},
247280
title = {Cyclic Ordering is NP-Complete},

problemreductions-cli/tests/cli_tests.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7642,7 +7642,15 @@ fn test_show_ksat_works() {
76427642
fn test_path_all_max_paths_truncates() {
76437643
// With --max-paths 3, should limit to 3 paths and indicate truncation
76447644
let output = pred()
7645-
.args(["path", "MIS", "QUBO", "--all", "--max-paths", "3", "--json"])
7645+
.args([
7646+
"path",
7647+
"KSat",
7648+
"QUBO",
7649+
"--all",
7650+
"--max-paths",
7651+
"3",
7652+
"--json",
7653+
])
76467654
.output()
76477655
.unwrap();
76487656
assert!(
@@ -7661,17 +7669,17 @@ fn test_path_all_max_paths_truncates() {
76617669
paths.len()
76627670
);
76637671
assert_eq!(envelope["max_paths"], 3);
7664-
// MIS -> QUBO has many paths, so truncation is expected
7672+
// KSat -> QUBO has many paths, so truncation is expected
76657673
assert_eq!(
76667674
envelope["truncated"], true,
7667-
"should be truncated since MIS->QUBO has many paths"
7675+
"should be truncated since KSat->QUBO has many paths"
76687676
);
76697677
}
76707678

76717679
#[test]
76727680
fn test_path_all_max_paths_text_truncation_note() {
76737681
let output = pred()
7674-
.args(["path", "MIS", "QUBO", "--all", "--max-paths", "2"])
7682+
.args(["path", "KSat", "QUBO", "--all", "--max-paths", "2"])
76757683
.output()
76767684
.unwrap();
76777685
assert!(output.status.success());

0 commit comments

Comments
 (0)