Skip to content

Commit 1e17e9d

Browse files
GiggleLiuclaude
andcommitted
Add MaximumClique<SimpleGraph, One> variant with weight cast and reductions
Register the One (unit weight) variant for MaximumClique so reduction paths from MIS/SimpleGraph/One no longer require unnecessary weight promotion to i32 before reaching MaxClique. Consolidate complement_edges into graph_helpers to eliminate 3 duplicate copies (DRY). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ff8ae70 commit 1e17e9d

7 files changed

Lines changed: 91 additions & 51 deletions

src/models/graph/maximum_clique.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
77
use crate::topology::{Graph, SimpleGraph};
88
use crate::traits::Problem;
9-
use crate::types::{Max, WeightElement};
9+
use crate::types::{Max, One, WeightElement};
1010
use num_traits::Zero;
1111
use serde::{Deserialize, Serialize};
1212

@@ -17,7 +17,7 @@ inventory::submit! {
1717
aliases: &[],
1818
dimensions: &[
1919
VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20-
VariantDimension::new("weight", "i32", &["i32"]),
20+
VariantDimension::new("weight", "One", &["One", "i32"]),
2121
],
2222
module_path: module_path!(),
2323
description: "Find maximum weight clique in a graph",
@@ -165,7 +165,8 @@ fn is_clique_config<G: Graph>(graph: &G, config: &[usize]) -> bool {
165165
}
166166

167167
crate::declare_variants! {
168-
default MaximumClique<SimpleGraph, i32> => "1.1996^num_vertices",
168+
MaximumClique<SimpleGraph, i32> => "1.1996^num_vertices",
169+
default MaximumClique<SimpleGraph, One> => "1.1996^num_vertices",
169170
}
170171

171172
#[cfg(feature = "example-db")]

src/rules/graph_helpers.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Shared helpers for graph-based reductions.
22
3-
use crate::topology::Graph;
3+
use crate::topology::{Graph, SimpleGraph};
44

55
/// Extract a Hamiltonian cycle vertex ordering from edge-selection configs on complete graphs.
66
///
@@ -57,3 +57,17 @@ pub(crate) fn edges_to_cycle_order<G: Graph>(graph: &G, target_solution: &[usize
5757

5858
order
5959
}
60+
61+
/// Build the complement graph edges: edges between all non-adjacent vertex pairs.
62+
pub(crate) fn complement_edges(graph: &SimpleGraph) -> Vec<(usize, usize)> {
63+
let n = graph.num_vertices();
64+
let mut edges = Vec::new();
65+
for u in 0..n {
66+
for v in (u + 1)..n {
67+
if !graph.has_edge(u, v) {
68+
edges.push((u, v));
69+
}
70+
}
71+
}
72+
edges
73+
}

src/rules/kcoloring_partitionintocliques.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,7 @@ impl ReductionResult for ReductionKColoringToPartitionIntoCliques {
2929
}
3030
}
3131

32-
fn complement_edges(graph: &SimpleGraph) -> Vec<(usize, usize)> {
33-
let n = graph.num_vertices();
34-
let mut edges = Vec::new();
35-
for u in 0..n {
36-
for v in (u + 1)..n {
37-
if !graph.has_edge(u, v) {
38-
edges.push((u, v));
39-
}
40-
}
41-
}
42-
edges
43-
}
32+
use super::graph_helpers::complement_edges;
4433

4534
#[reduction(
4635
overhead = {

src/rules/maximumclique_casts.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! Variant cast reductions for MaximumClique.
2+
//!
3+
//! Weight-hierarchy cast converting MaximumClique between weight subtypes.
4+
5+
use crate::impl_variant_reduction;
6+
use crate::models::graph::MaximumClique;
7+
use crate::topology::SimpleGraph;
8+
use crate::types::One;
9+
use crate::variant::CastToParent;
10+
11+
// Weight-hierarchy cast (One → i32)
12+
impl_variant_reduction!(
13+
MaximumClique,
14+
<SimpleGraph, One> => <SimpleGraph, i32>,
15+
fields: [num_vertices, num_edges],
16+
|src| MaximumClique::new(
17+
src.graph().clone(), src.weights().iter().map(|w| w.cast_to_parent()).collect())
18+
);

src/rules/maximumclique_maximumindependentset.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::models::graph::{MaximumClique, MaximumIndependentSet};
77
use crate::reduction;
88
use crate::rules::traits::{ReduceTo, ReductionResult};
99
use crate::topology::{Graph, SimpleGraph};
10-
use crate::types::WeightElement;
10+
use crate::types::{One, WeightElement};
1111

1212
/// Result of reducing MaximumClique to MaximumIndependentSet.
1313
#[derive(Debug, Clone)]
@@ -33,18 +33,15 @@ where
3333
}
3434
}
3535

36-
/// Build the complement graph: edges between all non-adjacent vertex pairs.
37-
fn complement_edges(graph: &SimpleGraph) -> Vec<(usize, usize)> {
38-
let n = graph.num_vertices();
39-
let mut edges = Vec::new();
40-
for u in 0..n {
41-
for v in (u + 1)..n {
42-
if !graph.has_edge(u, v) {
43-
edges.push((u, v));
44-
}
45-
}
46-
}
47-
edges
36+
fn reduce_clique_to_is<W: WeightElement + Clone + Default>(
37+
src: &MaximumClique<SimpleGraph, W>,
38+
) -> ReductionCliqueToIS<W> {
39+
let comp_edges = super::graph_helpers::complement_edges(src.graph());
40+
let target = MaximumIndependentSet::new(
41+
SimpleGraph::new(src.graph().num_vertices(), comp_edges),
42+
src.weights().to_vec(),
43+
);
44+
ReductionCliqueToIS { target }
4845
}
4946

5047
#[reduction(
@@ -57,12 +54,21 @@ impl ReduceTo<MaximumIndependentSet<SimpleGraph, i32>> for MaximumClique<SimpleG
5754
type Result = ReductionCliqueToIS<i32>;
5855

5956
fn reduce_to(&self) -> Self::Result {
60-
let comp_edges = complement_edges(self.graph());
61-
let target = MaximumIndependentSet::new(
62-
SimpleGraph::new(self.graph().num_vertices(), comp_edges),
63-
self.weights().to_vec(),
64-
);
65-
ReductionCliqueToIS { target }
57+
reduce_clique_to_is(self)
58+
}
59+
}
60+
61+
#[reduction(
62+
overhead = {
63+
num_vertices = "num_vertices",
64+
num_edges = "num_vertices * (num_vertices - 1) / 2 - num_edges",
65+
}
66+
)]
67+
impl ReduceTo<MaximumIndependentSet<SimpleGraph, One>> for MaximumClique<SimpleGraph, One> {
68+
type Result = ReductionCliqueToIS<One>;
69+
70+
fn reduce_to(&self) -> Self::Result {
71+
reduce_clique_to_is(self)
6672
}
6773
}
6874

src/rules/maximumindependentset_maximumclique.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::models::graph::{MaximumClique, MaximumIndependentSet};
77
use crate::reduction;
88
use crate::rules::traits::{ReduceTo, ReductionResult};
99
use crate::topology::{Graph, SimpleGraph};
10-
use crate::types::WeightElement;
10+
use crate::types::{One, WeightElement};
1111

1212
/// Result of reducing MaximumIndependentSet to MaximumClique.
1313
#[derive(Debug, Clone)]
@@ -33,6 +33,17 @@ where
3333
}
3434
}
3535

36+
fn reduce_is_to_clique<W: WeightElement + Clone + Default>(
37+
src: &MaximumIndependentSet<SimpleGraph, W>,
38+
) -> ReductionISToClique<W> {
39+
let comp_edges = super::graph_helpers::complement_edges(src.graph());
40+
let target = MaximumClique::new(
41+
SimpleGraph::new(src.graph().num_vertices(), comp_edges),
42+
src.weights().to_vec(),
43+
);
44+
ReductionISToClique { target }
45+
}
46+
3647
#[reduction(
3748
overhead = {
3849
num_vertices = "num_vertices",
@@ -43,21 +54,21 @@ impl ReduceTo<MaximumClique<SimpleGraph, i32>> for MaximumIndependentSet<SimpleG
4354
type Result = ReductionISToClique<i32>;
4455

4556
fn reduce_to(&self) -> Self::Result {
46-
let n = self.graph().num_vertices();
47-
// Build complement graph edges
48-
let mut complement_edges = Vec::new();
49-
for u in 0..n {
50-
for v in (u + 1)..n {
51-
if !self.graph().has_edge(u, v) {
52-
complement_edges.push((u, v));
53-
}
54-
}
55-
}
56-
let target = MaximumClique::new(
57-
SimpleGraph::new(n, complement_edges),
58-
self.weights().to_vec(),
59-
);
60-
ReductionISToClique { target }
57+
reduce_is_to_clique(self)
58+
}
59+
}
60+
61+
#[reduction(
62+
overhead = {
63+
num_vertices = "num_vertices",
64+
num_edges = "num_vertices * (num_vertices - 1) / 2 - num_edges",
65+
}
66+
)]
67+
impl ReduceTo<MaximumClique<SimpleGraph, One>> for MaximumIndependentSet<SimpleGraph, One> {
68+
type Result = ReductionISToClique<One>;
69+
70+
fn reduce_to(&self) -> Self::Result {
71+
reduce_is_to_clique(self)
6172
}
6273
}
6374

src/rules/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub(crate) mod ksatisfiability_timetabledesign;
7171
pub(crate) mod longestcommonsubsequence_maximumindependentset;
7272
pub(crate) mod maxcut_minimumcutintoboundedsets;
7373
pub(crate) mod maximum2satisfiability_maxcut;
74+
mod maximumclique_casts;
7475
pub(crate) mod maximumclique_maximumindependentset;
7576
mod maximumindependentset_casts;
7677
mod maximumindependentset_gridgraph;

0 commit comments

Comments
 (0)