Skip to content

Commit 52648df

Browse files
GiggleLiuclaude
andauthored
feat: redundant rule detection via polynomial overhead comparison (#193) (#194)
* docs: add design for redundant rule detection utility (#193) Detect primitive reduction rules dominated by composite paths using asymptotic growth rate classification of overhead expressions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add implementation plan for redundant rule detection (#193) 4 tasks: GrowthRate enum + Expr::growth_rate(), analysis.rs module with compare_overhead/find_dominated_rules, integration test with allow-list, clippy/fmt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add polynomial comparison for overhead analysis (#193) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add integration test for dominated rule detection (#193) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: clippy and format fixes (#193) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: remove redundant reduction rules (#193) Remove trusted-redundant primitive reductions where composed paths through existing canonical routes have equivalent or better overhead: - MinimumVertexCover → QUBO (use MVC → MIS → QUBO) - MinimumVertexCover → ILP (use MVC → MIS → ILP) - MaximumSetPacking → ILP (use MSP → MIS → ILP) - KSatisfiability K2/K3 → Satisfiability graph edges (use K2/K3 → KN → SAT) K2 and K3 retain their typed ReduceTo<Satisfiability> impls for direct use in code, but are no longer registered as primitive graph edges. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * save * feat: refactor ILP to ILP<V> with VariableDomain trait Remove bounds field. V=bool for binary (dims=2), V=i32 for general integer (dims=2^31-1). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: update 9 reductions to target ILP<bool> Remove VarBounds::binary() construction from all reductions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: update Factoring → ILP<i32> with carry bounds as constraints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: ILP<bool> → QUBO with compile-time binary guarantee Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add ILP<bool> → ILP<i32> cast reduction Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: update ILP solver for generic ILP<V> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: update all tests for ILP<V> refactor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: remove ILP→QUBO from untrusted edges ILP<bool>→QUBO overhead is now accurate (no slack ambiguity). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update paper and generated artifacts for ILP<V> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: rustfmt formatting fixes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * clean up rules * update * update * update * update * update * update docs * fix: address PR #194 review comments - Delete plan files introduced in this PR (2026-03-09-*) - Restore minimumvertexcover_to_qubo.json test data with new test_vc_to_qubo_ground_truth using MVC → MIS → SetPacking → QUBO path - Fix test_find_cheapest_path_is_to_qubo: use Minimize("num_vars") instead of MinimizeSteps for deterministic path selection Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: update CLI tests for changed reduction graph paths - test_path_overall_overhead_composition: 3SAT→MIS is now 3 steps (K3→KN variant cast adds a step), relax assertion to >= 2 - test_path_single_step_no_overall_text: MIS→QUBO is no longer single step (MIS→SP→QUBO), use MIS→MVC which is still 1 step Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 53c13f1 commit 52648df

90 files changed

Lines changed: 2806 additions & 2698 deletions

File tree

Some content is hidden

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

.claude/CLAUDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Rust library for NP-hard problem reductions. Implements computational problems w
1313
- [write-rule-in-paper](skills/write-rule-in-paper/SKILL.md) -- Write or improve a reduction-rule entry in the Typst paper. Covers complexity citation, self-contained proof, detailed example, and verification.
1414
- [release](skills/release/SKILL.md) -- Create a new crate release. Determines version bump from diff, verifies tests/clippy, then runs `make release`.
1515
- [check-issue](skills/check-issue/SKILL.md) -- Quality gate for `[Rule]` and `[Model]` issues. Checks usefulness, non-triviality, correctness of literature, and writing quality. Posts structured report and adds failure labels.
16+
- [check-rule-redundancy](skills/check-rule-redundancy/SKILL.md) -- Check if a reduction rule (source-target pair) is redundant, i.e., dominated by a composite path through other rules.
1617
- [meta-power](skills/meta-power/SKILL.md) -- Batch-resolve all open `[Model]` and `[Rule]` issues autonomously: plan, implement, review, fix CI, merge — in dependency order (models first).
1718

1819
## Commands
@@ -104,7 +105,7 @@ enum Direction { Maximize, Minimize }
104105
- `ReductionResult` provides `target_problem()` and `extract_solution()`
105106
- `Solver::find_best()``Option<Vec<usize>>` for optimization problems; `Solver::find_satisfying()``Option<Vec<usize>>` for `Metric = bool`
106107
- `BruteForce::find_all_best()` / `find_all_satisfying()` return `Vec<Vec<usize>>` for all optimal/satisfying solutions
107-
- Graph types: HyperGraph, SimpleGraph, PlanarGraph, BipartiteGraph, UnitDiskGraph, KingsSubgraph, TriangularSubgraph
108+
- Graph types: SimpleGraph, PlanarGraph, BipartiteGraph, UnitDiskGraph, KingsSubgraph, TriangularSubgraph
108109
- Weight types: `One` (unit weight marker), `i32`, `f64` — all implement `WeightElement` trait
109110
- `WeightElement` trait: `type Sum: NumericSize` + `fn to_sum(&self)` — converts weight to a summable numeric type
110111
- Weight management via inherent methods (`weights()`, `set_weights()`, `is_weighted()`), not traits

.claude/skills/check-issue/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Applies when the title contains `[Rule]`.
8989
Read the "Reduction Algorithm" section and flag as **Fail** if:
9090

9191
- **Variable substitution only:** The mapping is a 1-to-1 relabeling (e.g., `x_i → 1 - x_i` for complement problems). A valid reduction must construct new constraints, objectives, or graph structure.
92-
- **Subtype coercion:** The reduction merely casts to a more general type (e.g., SimpleGraphHyperGraph) with no structural change to the problem instance.
92+
- **Subtype coercion:** The reduction merely casts to a more general type within an existing variant hierarchy (e.g., UnitDiskGraphSimpleGraph) with no structural change to the problem instance.
9393
- **Same-problem identity:** Reducing between variants of the same problem with no insight (e.g., `MIS<SimpleGraph, One>``MIS<SimpleGraph, i32>` by setting all weights to 1).
9494
- **Insufficient detail:** The algorithm is a hand-wave ("map variables accordingly", "follows from the definition") — not a step-by-step procedure a programmer could implement. This is also a **Fail**.
9595

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
name: check-rule-redundancy
3+
description: Use when checking if a reduction rule (source-target pair) is redundant — i.e., dominated by a composite path through other rules in the reduction graph
4+
---
5+
6+
# Check Rule Redundancy
7+
8+
Determines whether reduction rules are redundant (dominated by composite paths through the reduction graph). Can check a single source-target pair or all primitive rules at once.
9+
10+
## Invocation
11+
12+
```
13+
/check-rule-redundancy # Check ALL primitive rules
14+
/check-rule-redundancy <source> <target> # Check a specific rule
15+
```
16+
17+
Examples:
18+
```
19+
/check-rule-redundancy
20+
/check-rule-redundancy MIS ILP
21+
/check-rule-redundancy MaximumIndependentSet QUBO
22+
```
23+
24+
## Mode 1: Check All Rules (no arguments)
25+
26+
When invoked without arguments, run the codebase's `find_dominated_rules` analysis test directly:
27+
28+
```bash
29+
cargo test test_find_dominated_rules_returns_known_set -- --nocapture 2>&1
30+
```
31+
32+
This runs the analysis from `src/rules/analysis.rs` which:
33+
1. Enumerates every primitive reduction rule (direct edge) in the graph
34+
2. For each, finds all alternative composite paths
35+
3. Uses polynomial normalization and monomial-dominance to compare overheads
36+
4. Reports dominated rules and unknown comparisons
37+
38+
Always report rules with full variant-qualified endpoints, not just base names.
39+
Use the same display style as `ReductionStep`, e.g.
40+
`MaximumIndependentSet {graph: "SimpleGraph", weight: "One"} -> MaximumIndependentSet {graph: "KingsSubgraph", weight: "i32"}`.
41+
Base-name-only summaries are ambiguous and can hide cast-only paths.
42+
43+
Parse the test output and report a summary:
44+
45+
```markdown
46+
## All Primitive Rules — Redundancy Report
47+
48+
### Dominated Rules (N)
49+
50+
| # | Rule | Dominating Path |
51+
|---|------|-----------------|
52+
| 1 | Source {variant...} -> Target {variant...} | A -> B -> C |
53+
54+
### Unknown Comparisons (N)
55+
56+
| # | Rule | Reason |
57+
|---|------|--------|
58+
| 1 | Source {variant...} -> Target {variant...} | expression comparison returned Unknown |
59+
60+
### Allowed (acknowledged) dominated rules
61+
62+
List the entries from the `allowed` set in `test_find_dominated_rules_returns_known_set`
63+
(file: `src/unit_tests/rules/analysis.rs`), and note when that allow-list is keyed only by base names while the reported dominated rule is variant-specific.
64+
65+
### Verdict
66+
67+
- If test passes: all dominated rules are acknowledged in the allow-list.
68+
- If test fails: report the unexpected dominated rule or stale allow-list entry.
69+
```
70+
71+
## Mode 2: Check Single Rule (source target arguments)
72+
73+
### Step 1: Resolve Problem Names
74+
75+
Use MCP tools (`show_problem`) to validate and resolve aliases (MIS = MaximumIndependentSet, MVC = MinimumVertexCover, SAT = Satisfiability, etc.).
76+
77+
### Step 2: Check if Rule Already Exists
78+
79+
Use `show_problem` on the source and check its `reduces_to` array for a direct edge to the target.
80+
81+
- **Direct edge exists**: Report "Direct rule `<source> -> <target>` already exists" and proceed to redundancy analysis (Step 3).
82+
- **No direct edge**: Report "No direct rule from `<source> -> <target>` exists yet." Then check if any path exists:
83+
- Use `find_path` MCP tool.
84+
- **Path exists**: Report the cheapest existing path and its overhead. This is the baseline the proposed new rule must beat to be non-redundant.
85+
- **No path exists**: Report "No path exists — a new rule would be novel (not redundant)." Stop here.
86+
87+
### Step 3: Find All Paths
88+
89+
Use `find_path` with `all: true` to get all paths between source and target.
90+
91+
### Step 4: Compare Overheads
92+
93+
For each composite path (length > 1 step):
94+
95+
1. Extract the **overall overhead** from the path result
96+
2. Extract the **direct rule's overhead** from the single-step path
97+
3. Compare field by field:
98+
- For polynomial expressions: compare degree — lower degree means the composite is better
99+
- For equal-degree polynomials: compare leading coefficients
100+
- For non-polynomial (exp, log): report as "Unknown — manual review needed"
101+
102+
**Dominance definition:** A composite path **dominates** the direct rule if, on every common overhead field, the composite's expression has equal or smaller asymptotic growth.
103+
104+
### Step 5: Report Results
105+
106+
Output a structured report:
107+
108+
```markdown
109+
## Redundancy Check: <Source> -> <Target>
110+
111+
### Direct Rule
112+
- Overhead: [field = expr, ...]
113+
- Rule: `Source {variant...} -> Target {variant...}`
114+
- Overhead: [field = expr, ...]
115+
116+
### Composite Paths Found: N
117+
118+
| # | Path | Steps | Overhead | Comparison |
119+
|---|------|-------|----------|------------|
120+
| 1 | A -> B -> C | 2 | field = expr | Dominates / Worse / Unknown |
121+
122+
### Verdict
123+
124+
- **Redundant**: At least one composite path dominates the direct rule
125+
- **Not Redundant**: No composite path dominates the direct rule
126+
- **Inconclusive**: Some paths have Unknown comparison (non-polynomial overhead)
127+
128+
### Recommendation
129+
130+
If redundant:
131+
> The direct rule `Source {variant...} -> Target {variant...}` is dominated by the composite path `[path]`.
132+
> Consider removing it unless it provides value for:
133+
> - Simpler solution extraction (fewer intermediate steps)
134+
> - Educational/documentation clarity
135+
> - Better numerical behavior in practice
136+
137+
If not redundant:
138+
> The direct rule `Source {variant...} -> Target {variant...}` is not dominated by any composite path.
139+
> It provides overhead that cannot be achieved through existing reductions.
140+
```
141+
142+
## Notes
143+
144+
- "Equal overhead" does not necessarily mean the rule should be removed — direct rules have practical advantages (simpler extraction, fewer steps)
145+
- The analysis uses asymptotic comparison (big-O), so constant factors are ignored
146+
- This means the check can produce false alarms, especially when overhead metadata keeps only leading terms or when a long composite path is asymptotically comparable but practically much worse
147+
- Treat "dominated" as "potentially redundant, requires manual review" unless the composite path is also clearly preferable structurally
148+
- When overhead expressions involve variables from different problems (e.g., `num_vertices` vs `num_clauses`), comparison may not be meaningful — report as Unknown
149+
- The ground truth for what the codebase considers dominated is `src/rules/analysis.rs` (`find_dominated_rules`) with the allow-list in `src/unit_tests/rules/analysis.rs` (`test_find_dominated_rules_returns_known_set`)

0 commit comments

Comments
 (0)