Skip to content

feat: Decision wrapper for optimization→decision conversion#1014

Open
GiggleLiu wants to merge 15 commits intomainfrom
feat/decision-wrapper
Open

feat: Decision wrapper for optimization→decision conversion#1014
GiggleLiu wants to merge 15 commits intomainfrom
feat/decision-wrapper

Conversation

@GiggleLiu
Copy link
Copy Markdown
Contributor

Summary

  • Add generic Decision<P> wrapper that converts optimization problems (Min/Max valued) to decision problems (Or valued) via a bound parameter
  • Add OptimizationValue trait abstracting over Min<V>/Max<V> with meets_bound() semantics
  • Add ReduceToAggregate impl for Decision<P> → P (solve optimization, compare to bound)
  • Add golden-section search solver that recovers optima by querying Decision<P> instances
  • Replace hand-written VertexCover with Decision<MinimumVertexCover> (aliases VertexCover/VC preserved)
  • Fix proc macro extract_type_name() to handle Decision<T> nested generics
  • Register concrete variants for Decision<MinimumVertexCover> and Decision<MinimumDominatingSet>

Closes #998

Test plan

  • cargo test optimization_value — 8 tests for OptimizationValue trait
  • cargo test test_decision — 9 tests for Decision<P> struct, solver, serialization, aggregate reduction
  • cargo test test_golden_section — 3 tests for golden-section search solver
  • make check — full suite (fmt + clippy + test)
  • Verify pred show VertexCover and pred show VC still resolve (alias migration)

🤖 Generated with Claude Code

GiggleLiu and others added 10 commits April 6, 2026 23:11
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the aggregate reduction from Decision<P> to P that
extracts the optimization value by comparing against the threshold.
This is Task 3 of the decision-wrapper plan.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

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 introduces a generic Decision<P> wrapper to convert optimization problems (Min/Max) into decision problems (Or) via a bound, migrates the VertexCover decision model to this wrapper while preserving CLI aliases, and adds a decision-query-based search utility plus registry/docs updates to reflect the new decision types.

Changes:

  • Add OptimizationValue + Decision<P> (with ReduceToAggregate) to support generic optimization→decision conversion and aggregate edges back to the inner optimization problem.
  • Register concrete decision variants/schemas for Decision<MinimumVertexCover<SimpleGraph,i32>> and Decision<MinimumDominatingSet<SimpleGraph,i32>>, removing the bespoke VertexCover model while preserving VertexCover/VC CLI aliases.
  • Add a decision-query-based solver utility (named “golden section”) and update CLI/docs/tests to validate registry, examples, and alias resolution.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/types.rs Adds OptimizationValue trait + Min/Max implementations; wires new unit test module.
src/models/decision.rs Introduces generic Decision<P> wrapper, DecisionProblemMeta, and aggregate reduction Decision<P> → P.
src/models/mod.rs Exposes decision module and re-exports Decision; removes VertexCover re-export.
src/models/graph/minimum_vertex_cover.rs Registers DecisionMinimumVertexCover schema/variant + aggregate edge; adds example-db spec.
src/models/graph/minimum_dominating_set.rs Registers DecisionMinimumDominatingSet schema/variant + aggregate edge.
src/models/graph/maximum_independent_set.rs Registers DecisionProblemMeta for MIS (for decision-query tooling/tests).
src/models/graph/mod.rs Removes vertex_cover module export; adds decision-MVC example specs into example-db aggregation.
src/models/graph/vertex_cover.rs Removes bespoke VertexCover decision model implementation.
src/solvers/golden_section.rs Adds decision-query search helper (implemented as integer binary search).
src/solvers/mod.rs Exposes the new golden_section solver module.
src/unit_tests/types_optimization_value.rs Adds tests for OptimizationValue::meets_bound semantics.
src/unit_tests/models/decision.rs Adds tests for Decision<P> evaluation, serde roundtrip, and aggregate reduction.
src/unit_tests/solvers/golden_section.rs Adds tests validating decision-query search recovers optima and handles invalid intervals.
src/unit_tests/registry/schema.rs Adds tests asserting decision schemas/variants are registered and VertexCover legacy schema removed.
src/unit_tests/reduction_graph.rs Adds tests asserting direct aggregate edges from decision wrappers to optimization problems.
src/unit_tests/models/graph/vertex_cover.rs Removes tests for the deleted bespoke VertexCover model.
src/unit_tests/example_db.rs Adds example-db test coverage for DecisionMinimumVertexCover example instance.
problemreductions-macros/src/lib.rs Fixes proc-macro type-name extraction to handle Decision<T> nested generics; adds tests.
problemreductions-cli/src/problem_name.rs Updates alias resolution tests so VertexCover/VC resolve to DecisionMinimumVertexCover.
problemreductions-cli/src/mcp/prompts.rs Updates default prompt example to use DecisionMinimumVertexCover.
problemreductions-cli/src/commands/create/schema_support.rs Updates help-example fallback strings to include DecisionMinimumVertexCover.
problemreductions-cli/src/commands/create.rs Adds random generation path for DecisionMinimumVertexCover; removes VertexCover random generation.
problemreductions-cli/src/cli.rs Updates “Flags by problem type” help text to list DecisionMinimumVertexCover.
docs/paper/reductions.typ Updates paper definitions and helper logic to support nested inner for decision-wrapped instances.
docs/plans/2026-04-06-decision-wrapper-plan.md Adds implementation plan documenting steps/tests for the decision wrapper work.
docs/plans/2026-04-06-decision-wrapper-design.md Adds design spec documenting rationale, architecture, and migration details.

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

Comment on lines +198 to +199
FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

ProblemSchemaEntry for DecisionMinimumVertexCover declares top-level fields graph/weights/bound, but the actual serde shape of Decision<MinimumVertexCover<...>> is { inner: { graph, weights }, bound }. This mismatch will break schema-driven CLI creation (pred create DecisionMinimumVertexCover --graph ... --weights ... --bound ...) because the variant factory will fail to deserialize the generated JSON. Consider either (a) teaching Decision<P> to deserialize from the flattened form used by the schema/CLI, or (b) changing schema-driven creation/schema fields to match the nested inner structure (or special-casing this canonical in the CLI create path).

Suggested change
FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
FieldInfo {
name: "inner",
type_name: "MinimumVertexCover<G, W>",
description: "The optimization problem payload containing the graph G=(V,E) and vertex weights w: V -> R",
},

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +212
FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
FieldInfo { name: "bound", type_name: "i32", description: "Decision bound (maximum allowed dominating-set cost)" },
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

Same issue as DecisionMinimumVertexCover: this schema declares graph/weights/bound as top-level fields, but Decision<MinimumDominatingSet<...>> serializes as { inner: { ... }, bound }. As a result, schema-driven CLI creation for DecisionMinimumDominatingSet will generate the wrong JSON shape and the variant factory will reject it. Align the schema/CLI creation with the actual serde structure, or make Decision<P> accept both shapes on deserialization.

Suggested change
FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
FieldInfo { name: "bound", type_name: "i32", description: "Decision bound (maximum allowed dominating-set cost)" },
FieldInfo {
name: "inner",
type_name: "MinimumDominatingSet<SimpleGraph, i32>",
description: "The underlying minimum dominating set instance",
},
FieldInfo {
name: "bound",
type_name: "i32",
description: "Decision bound (maximum allowed dominating-set cost)",
},

Copilot uses AI. Check for mistakes.
KColoring --graph, --k
KClique --graph, --k
VertexCover (VC) --graph, --k
DecisionMinimumVertexCover --graph, --weights, --bound
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The CLI help now advertises DecisionMinimumVertexCover --graph, --weights, --bound, but schema-driven creation currently constructs JSON using the schema field names (top-level graph/weights/bound). Since Decision<...> deserializes from { inner: {...}, bound }, pred create DecisionMinimumVertexCover --graph ... --weights ... --bound ... will fail unless the model/serde or CLI creation path is updated to match.

Suggested change
DecisionMinimumVertexCover --graph, --weights, --bound
DecisionMinimumVertexCover use JSON input ({\"inner\": {...}, \"bound\": ...})

Copilot uses AI. Check for mistakes.
Comment on lines 27 to 49
pub use graph::{
AcyclicPartition, BalancedCompleteBipartiteSubgraph, BicliqueCover, BiconnectivityAugmentation,
BottleneckTravelingSalesman, BoundedComponentSpanningForest, BoundedDiameterSpanningTree,
DegreeConstrainedSpanningTree, DirectedHamiltonianPath, DirectedTwoCommodityIntegralFlow,
DisjointConnectingPaths, GeneralizedHex, GraphPartitioning, HamiltonianCircuit,
HamiltonianPath, HamiltonianPathBetweenTwoVertices, IntegralFlowBundles,
IntegralFlowHomologousArcs, IntegralFlowWithMultipliers, IsomorphicSpanningTree, KClique,
KColoring, Kernel, KthBestSpanningTree, LengthBoundedDisjointPaths, LongestCircuit,
LongestPath, MaxCut, MaximalIS, MaximumAchromaticNumber, MaximumClique, MaximumDomaticNumber,
MaximumIndependentSet, MaximumLeafSpanningTree, MaximumMatching, MinMaxMulticenter,
MinimumCoveringByCliques, MinimumCutIntoBoundedSets, MinimumDominatingSet,
MinimumDummyActivitiesPert, MinimumEdgeCostFlow, MinimumFeedbackArcSet,
MinimumFeedbackVertexSet, MinimumGeometricConnectedDominatingSet, MinimumGraphBandwidth,
MinimumIntersectionGraphBasis, MinimumMaximalMatching, MinimumMultiwayCut,
MinimumSumMulticenter, MinimumVertexCover, MixedChinesePostman, MonochromaticTriangle,
MultipleChoiceBranching, MultipleCopyFileAllocation, OptimalLinearArrangement,
PartialFeedbackEdgeSet, PartitionIntoCliques, PartitionIntoForests,
PartitionIntoPathsOfLength2, PartitionIntoPerfectMatchings, PartitionIntoTriangles,
PathConstrainedNetworkFlow, RootedTreeArrangement, RuralPostman, ShortestWeightConstrainedPath,
SpinGlass, SteinerTree, SteinerTreeInGraphs, StrongConnectivityAugmentation,
SubgraphIsomorphism, TravelingSalesman, UndirectedFlowLowerBounds,
UndirectedTwoCommodityIntegralFlow, VertexCover,
UndirectedTwoCommodityIntegralFlow,
};
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

VertexCover was removed from the public Rust re-exports (and the model file was deleted), which is a breaking change for library users who construct problemreductions::models::graph::VertexCover. If you intend to preserve the Rust API as well as the CLI alias, consider adding a public type alias (e.g., pub type VertexCover<...> = Decision<MinimumVertexCover<...>>) or documenting this as a breaking change in release notes.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
//! Golden-section-style search for optimization via decision queries.

use crate::models::decision::{Decision, DecisionProblemMeta};
use crate::solvers::{BruteForce, Solver};
use crate::traits::Problem;
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

golden_section is implemented as a monotone binary search over integer bounds (midpoint halving), not golden-section search. This is likely fine functionally, but the module/function naming and top-level docstring are misleading and make the algorithm harder to reason about later. Consider renaming to binary_search_decision (or similar) or updating the docs to match the actual approach.

Copilot uses AI. Check for mistakes.
GiggleLiu and others added 2 commits April 7, 2026 09:20
- Add register_decision_variant! macro to reduce per-type boilerplate (~80 lines each for MVC/MDS)
- Add Decision<MinimumDominatingSet> behavioral tests (creation, evaluate, reduction, solver)
- Add boundary test for reduce_to_aggregate with infeasible bound
- Rename golden_section.rs to decision_search.rs (binary search, not golden section)
- Fix schema-driven CLI creation for Decision types (restructure flat JSON to nested {inner, bound})
- Add canonical rule example specs for Decision→Optimization aggregate edges
- Update example_db test to handle aggregate-only reduction paths
- Filter trivial Decision<P>↔P edges from paper completeness check
- Remove plan files
- Generalize DecisionProblemMeta to blanket impl per optimization model

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…lique)

The K4 graph with k=3 has both size-3 and size-4 valid cliques.
The ILP solver nondeterministically picks either, so assert >= k
instead of == k.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 7, 2026

Codecov Report

❌ Patch coverage is 93.25843% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.11%. Comparing base (90fcc85) to head (72c2d5d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/models/decision.rs 71.05% 22 Missing ⚠️
src/models/graph/minimum_dominating_set.rs 68.96% 9 Missing ⚠️
src/rules/registry.rs 50.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1014      +/-   ##
==========================================
- Coverage   98.14%   98.11%   -0.03%     
==========================================
  Files         920      923       +3     
  Lines       95494    95900     +406     
==========================================
+ Hits        93723    94094     +371     
- Misses       1771     1806      +35     

☔ 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 3 commits April 7, 2026 11:30
…ision

Registers P → Decision<P> as a Turing reduction edge — representing
that solving an optimization problem via its decision version requires
multiple adaptive queries (binary search over the bound).

- Add `turing` field to EdgeCapabilities and ReductionMode::Turing
- Register reverse Turing edges in register_decision_variant! macro
- Export turing flag in JSON graph
- Turing edges excluded from rule example coverage (no single-shot demo)
- Add tests for MVC→DecisionMVC and MDS→DecisionMDS Turing edges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The macro previously hardcoded num_vertices/num_edges as size getters,
which only works for graph problems. Now accepts dims, fields, and
size_getters as parameters so non-graph Decision variants can specify
their own problem-size fields (e.g., num_vars/num_clauses for SAT).

Callers define inherent methods on Decision<P> before invoking the macro.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document Decision<P> wrapper, OptimizationValue trait, decision_search solver
- Document EdgeCapabilities.turing field and ReductionMode::Turing
- Document register_decision_variant! macro with dims/fields/size_getters params
- Document Decision↔P completeness filter in paper section
- Add anti-pattern entry in add-model skill: use Decision<P> not hand-written models

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

[Design] Decision wrapper for converting optimization problems to decision problems

2 participants