Skip to content

Commit 5320302

Browse files
GiggleLiuclaude
andauthored
Fix #73: Refactor graph problem constructors to take graph as input (#74)
* Add plan for #73: Refactor graph problem constructors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * save issue templates * refactor: replace MaximumIndependentSet SimpleGraph-only constructors with generic new(graph, weights) Remove the `impl<W> MaximumIndependentSet<SimpleGraph, W>` block containing `new(num_vertices, edges)` and `with_weights(num_vertices, edges, weights)`. Rename `from_graph` to `new` in the generic impl block, making all graph types use the same `MaximumIndependentSet::new(graph, weights)` constructor. Update all call sites across rules, unit tests, integration tests, examples, benchmarks, and doc comments to use the new pattern: - `MaximumIndependentSet::<SimpleGraph, i32>::new(n, edges)` becomes `MaximumIndependentSet::new(SimpleGraph::new(n, edges), vec![1i32; n])` - `MaximumIndependentSet::with_weights(n, edges, w)` becomes `MaximumIndependentSet::new(SimpleGraph::new(n, edges), w)` - `MaximumIndependentSet::from_graph(g, w)` becomes `MaximumIndependentSet::new(g, w)` Part of #73 (graph constructor refactoring). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace SimpleGraph-only constructors for MVC, MDS, MaxClique, MaximalIS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace KColoring SimpleGraph-only constructors, rename from_graph -> new - Delete `impl<K: KValue> KColoring<K, SimpleGraph>` block with `new(num_vertices, edges)` - Rename `from_graph(graph)` -> `new(graph)` in generic `impl<K: KValue, G: Graph>` - Rename `from_graph_with_k(graph, k)` -> `with_k(graph, k)` in `impl<G: Graph> KColoring<KN, G>` - Update all call sites: wrap edges in `SimpleGraph::new(n, edges)` and use `KColoring::<K3, _>::new(...)` - Update doc example, rules, unit tests, integration tests, examples, and benchmarks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace SimpleGraph-only constructors for MaxCut, MaximumMatching, TravelingSalesman Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: type-based is_weighted via WeightElement::IS_UNIT Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: public helper functions take graph reference instead of raw vertices/edges Update 8 public helper functions (is_independent_set, is_vertex_cover, is_clique, is_maximal_independent_set, is_dominating_set, is_matching, is_hamiltonian_cycle, is_valid_coloring) to accept `&G where G: Graph` instead of `(num_vertices, edges)`. Size mismatches now panic via assert_eq! instead of returning false. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review comments, remove plan file - TravelingSalesman: guard against wrong-length config in private helper - is_dominating_set/is_maximal_independent_set: pre-build adjacency list to avoid per-vertex allocation in loop - Remove plan file Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 529114f commit 5320302

82 files changed

Lines changed: 884 additions & 1100 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.

.github/ISSUE_TEMPLATE/problem.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ assignees: ''
77

88
---
99

10+
## Motivation
11+
12+
<!-- One sentence: why is this problem useful to include? E.g. "Widely used in network design and has known reductions to QUBO." -->
13+
1014
## Definition
1115

1216
**Name:** <!-- e.g. MaximumIndependentSet. Use Maximum/Minimum prefix for optimization problems -->

.github/ISSUE_TEMPLATE/rule.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ assignees: ''
99

1010
**Source:** <!-- e.g. MaximumIndependentSet. Browse existing problems: https://codingthrust.github.io/problem-reductions/ -->
1111
**Target:** <!-- e.g. QUBO -->
12+
**Motivation:** <!-- One sentence: why is this reduction useful? E.g. "Enables solving MIS on quantum annealers via QUBO formulation." -->
1213
**Reference:** <!-- URL, paper, or textbook citation for this reduction -->
1314

1415
## Reduction Algorithm

benches/solver_benchmarks.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn bench_independent_set(c: &mut Criterion) {
1818
for n in [4, 6, 8, 10].iter() {
1919
// Create a path graph with n vertices
2020
let edges: Vec<(usize, usize)> = (0..*n - 1).map(|i| (i, i + 1)).collect();
21-
let problem = MaximumIndependentSet::<SimpleGraph, i32>::new(*n, edges);
21+
let problem = MaximumIndependentSet::new(SimpleGraph::new(*n, edges), vec![1i32; *n]);
2222
let solver = BruteForce::new();
2323

2424
group.bench_with_input(BenchmarkId::new("path", n), n, |b, _| {
@@ -35,7 +35,7 @@ fn bench_vertex_covering(c: &mut Criterion) {
3535

3636
for n in [4, 6, 8, 10].iter() {
3737
let edges: Vec<(usize, usize)> = (0..*n - 1).map(|i| (i, i + 1)).collect();
38-
let problem = MinimumVertexCover::<SimpleGraph, i32>::new(*n, edges);
38+
let problem = MinimumVertexCover::new(SimpleGraph::new(*n, edges), vec![1i32; *n]);
3939
let solver = BruteForce::new();
4040

4141
group.bench_with_input(BenchmarkId::new("path", n), n, |b, _| {
@@ -51,8 +51,9 @@ fn bench_max_cut(c: &mut Criterion) {
5151
let mut group = c.benchmark_group("MaxCut");
5252

5353
for n in [4, 6, 8, 10].iter() {
54-
let edges: Vec<(usize, usize, i32)> = (0..*n - 1).map(|i| (i, i + 1, 1)).collect();
55-
let problem = MaxCut::new(*n, edges);
54+
let edges: Vec<(usize, usize)> = (0..*n - 1).map(|i| (i, i + 1)).collect();
55+
let weights = vec![1i32; edges.len()];
56+
let problem = MaxCut::new(SimpleGraph::new(*n, edges), weights);
5657
let solver = BruteForce::new();
5758

5859
group.bench_with_input(BenchmarkId::new("path", n), n, |b, _| {
@@ -139,7 +140,7 @@ fn bench_coloring(c: &mut Criterion) {
139140

140141
for n in [3, 4, 5, 6].iter() {
141142
let edges: Vec<(usize, usize)> = (0..*n - 1).map(|i| (i, i + 1)).collect();
142-
let problem = KColoring::<K3, SimpleGraph>::new(*n, edges);
143+
let problem = KColoring::<K3, _>::new(SimpleGraph::new(*n, edges));
143144
let solver = BruteForce::new();
144145

145146
group.bench_with_input(BenchmarkId::new("path_3colors", n), n, |b, _| {
@@ -155,8 +156,9 @@ fn bench_matching(c: &mut Criterion) {
155156
let mut group = c.benchmark_group("Matching");
156157

157158
for n in [4, 6, 8, 10].iter() {
158-
let edges: Vec<(usize, usize, i32)> = (0..*n - 1).map(|i| (i, i + 1, 1)).collect();
159-
let problem = MaximumMatching::new(*n, edges);
159+
let edges: Vec<(usize, usize)> = (0..*n - 1).map(|i| (i, i + 1)).collect();
160+
let weights = vec![1i32; edges.len()];
161+
let problem = MaximumMatching::new(SimpleGraph::new(*n, edges), weights);
160162
let solver = BruteForce::new();
161163

162164
group.bench_with_input(BenchmarkId::new("path", n), n, |b, _| {
@@ -196,7 +198,7 @@ fn bench_comparison(c: &mut Criterion) {
196198

197199
// MaximumIndependentSet with 8 vertices
198200
let is_problem =
199-
MaximumIndependentSet::<SimpleGraph, i32>::new(8, vec![(0, 1), (2, 3), (4, 5), (6, 7)]);
201+
MaximumIndependentSet::new(SimpleGraph::new(8, vec![(0, 1), (2, 3), (4, 5), (6, 7)]), vec![1i32; 8]);
200202
group.bench_function("MaximumIndependentSet", |b| {
201203
b.iter(|| solver.find_best(black_box(&is_problem)))
202204
});
@@ -226,7 +228,7 @@ fn bench_comparison(c: &mut Criterion) {
226228
});
227229

228230
// MaxCut with 8 vertices
229-
let mc_problem = MaxCut::new(8, vec![(0, 1, 1), (2, 3, 1), (4, 5, 1), (6, 7, 1)]);
231+
let mc_problem = MaxCut::new(SimpleGraph::new(8, vec![(0, 1), (2, 3), (4, 5), (6, 7)]), vec![1, 1, 1, 1]);
230232
group.bench_function("MaxCut", |b| {
231233
b.iter(|| solver.find_best(black_box(&mc_problem)))
232234
});

docs/src/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use problemreductions::prelude::*;
3535
use problemreductions::topology::SimpleGraph;
3636

3737
// 1. Create: Independent Set on a path graph (4 vertices)
38-
let problem = MaximumIndependentSet::<SimpleGraph, i32>::new(4, vec![(0, 1), (1, 2), (2, 3)]);
38+
let problem = MaximumIndependentSet::new(SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]), vec![1i32; 4]);
3939

4040
// 2. Reduce: Transform to Minimum Vertex Cover
4141
let reduction = ReduceTo::<MinimumVertexCover<SimpleGraph, i32>>::reduce_to(&problem);

examples/reduction_kcoloring_to_ilp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use problemreductions::topology::{Graph, SimpleGraph};
2424
pub fn run() {
2525
// 1. Create KColoring instance: Petersen graph (10 vertices, 15 edges) with 3 colors, χ=3
2626
let (num_vertices, edges) = petersen();
27-
let coloring = KColoring::<K3, SimpleGraph>::new(num_vertices, edges.clone());
27+
let coloring = KColoring::<K3, _>::new(SimpleGraph::new(num_vertices, edges.clone()));
2828

2929
// 2. Reduce to ILP
3030
let reduction = ReduceTo::<ILP>::reduce_to(&coloring);

examples/reduction_kcoloring_to_qubo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn run() {
3838

3939
// House graph: 5 vertices, 6 edges (square base + triangle roof), χ=3
4040
let (num_vertices, edges) = house();
41-
let kc = KColoring::<K3, SimpleGraph>::new(num_vertices, edges.clone());
41+
let kc = KColoring::<K3, _>::new(SimpleGraph::new(num_vertices, edges.clone()));
4242

4343
// Reduce to QUBO
4444
let reduction = ReduceTo::<QUBO>::reduce_to(&kc);

examples/reduction_maxcut_to_spinglass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use problemreductions::topology::{Graph, SimpleGraph};
2222

2323
pub fn run() {
2424
let (num_vertices, edges) = petersen();
25-
let maxcut = MaxCut::<SimpleGraph, i32>::unweighted(num_vertices, edges.clone());
25+
let maxcut = MaxCut::<_, i32>::unweighted(SimpleGraph::new(num_vertices, edges.clone()));
2626

2727
let reduction = ReduceTo::<SpinGlass<SimpleGraph, i32>>::reduce_to(&maxcut);
2828
let sg = reduction.target_problem();

examples/reduction_maximumclique_to_ilp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use problemreductions::topology::{Graph, SimpleGraph};
2222
pub fn run() {
2323
// 1. Create MaximumClique instance: Octahedron (K_{2,2,2}), 6 vertices, 12 edges, clique number 3
2424
let (num_vertices, edges) = octahedral();
25-
let clique = MaximumClique::<SimpleGraph, i32>::new(num_vertices, edges.clone());
25+
let clique = MaximumClique::new(SimpleGraph::new(num_vertices, edges.clone()), vec![1i32; num_vertices]);
2626

2727
// 2. Reduce to ILP
2828
let reduction = ReduceTo::<ILP>::reduce_to(&clique);

examples/reduction_maximumindependentset_to_ilp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use problemreductions::topology::{Graph, SimpleGraph};
2121
pub fn run() {
2222
// 1. Create IS instance: Petersen graph
2323
let (num_vertices, edges) = petersen();
24-
let is = MaximumIndependentSet::<SimpleGraph, i32>::new(num_vertices, edges.clone());
24+
let is = MaximumIndependentSet::new(SimpleGraph::new(num_vertices, edges.clone()), vec![1i32; num_vertices]);
2525

2626
// 2. Reduce to ILP
2727
let reduction = ReduceTo::<ILP>::reduce_to(&is);

examples/reduction_maximumindependentset_to_maximumsetpacking.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn run() {
2525

2626
// Petersen graph: 10 vertices, 15 edges, 3-regular
2727
let (num_vertices, edges) = petersen();
28-
let source = MaximumIndependentSet::<SimpleGraph, i32>::new(num_vertices, edges.clone());
28+
let source = MaximumIndependentSet::new(SimpleGraph::new(num_vertices, edges.clone()), vec![1i32; num_vertices]);
2929

3030
println!("Source: MaximumIndependentSet on Petersen graph");
3131
println!(" Vertices: {}", num_vertices);

0 commit comments

Comments
 (0)