Skip to content

Commit 1abc32b

Browse files
GiggleLiuclaude
andcommitted
Drop dominated MaxClique cast; add <One> closed-loop tests
The `MaximumClique<SG,One> → MaximumClique<SG,i32>` direct cast is dominated by the existing `MC<SG,One> → MIS<SG,One> → MIS<SG,i32> → MC<SG,i32>` path, which the redundancy-sanity test flags in `rules::analysis::tests::test_find_dominated_rules_returns_known_set`. Remove the cast entirely (and its now-empty `maximumclique_casts.rs`); the cast-less `<One> → <i32>` path is still reachable via MIS, so `pred path MaximumIndependentSet MaximumClique` stays on `One` without the `i32` detour. Also: - add `<One>` closed-loop tests for both MC↔MIS reduction directions and a `MaximumClique<SG,One>` model-level evaluate/solve test, - drop the redundant `Clone + Default` bounds on `reduce_clique_to_is`/`reduce_is_to_clique` (already implied by `WeightElement`), - move the stray `use super::graph_helpers::complement_edges;` in `kcoloring_partitionintocliques.rs` up with the other imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1e17e9d commit 1abc32b

8 files changed

Lines changed: 70 additions & 24 deletions

src/rules/kcoloring_partitionintocliques.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
use crate::models::graph::{KColoring, PartitionIntoCliques};
77
use crate::reduction;
8+
use crate::rules::graph_helpers::complement_edges;
89
use crate::rules::traits::{ReduceTo, ReductionResult};
910
use crate::topology::{Graph, SimpleGraph};
1011
use crate::variant::KN;
@@ -29,8 +30,6 @@ impl ReductionResult for ReductionKColoringToPartitionIntoCliques {
2930
}
3031
}
3132

32-
use super::graph_helpers::complement_edges;
33-
3433
#[reduction(
3534
overhead = {
3635
num_vertices = "num_vertices",

src/rules/maximumclique_casts.rs

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/rules/maximumclique_maximumindependentset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ where
3333
}
3434
}
3535

36-
fn reduce_clique_to_is<W: WeightElement + Clone + Default>(
36+
fn reduce_clique_to_is<W: WeightElement>(
3737
src: &MaximumClique<SimpleGraph, W>,
3838
) -> ReductionCliqueToIS<W> {
3939
let comp_edges = super::graph_helpers::complement_edges(src.graph());

src/rules/maximumindependentset_maximumclique.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ where
3333
}
3434
}
3535

36-
fn reduce_is_to_clique<W: WeightElement + Clone + Default>(
36+
fn reduce_is_to_clique<W: WeightElement>(
3737
src: &MaximumIndependentSet<SimpleGraph, W>,
3838
) -> ReductionISToClique<W> {
3939
let comp_edges = super::graph_helpers::complement_edges(src.graph());

src/rules/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ 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;
7574
pub(crate) mod maximumclique_maximumindependentset;
7675
mod maximumindependentset_casts;
7776
mod maximumindependentset_gridgraph;

src/unit_tests/models/graph/maximum_clique.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22
use crate::solvers::BruteForce;
33
use crate::topology::SimpleGraph;
4-
use crate::types::Max;
4+
use crate::types::{Max, One};
55

66
#[test]
77
fn test_clique_creation() {
@@ -281,6 +281,29 @@ fn test_size_getters() {
281281
assert_eq!(problem.num_edges(), 2);
282282
}
283283

284+
#[test]
285+
fn test_clique_one_weights_evaluate_and_solve() {
286+
use crate::traits::Problem;
287+
288+
// Triangle with unit weights: max clique covers all 3 vertices.
289+
let problem = MaximumClique::new(
290+
SimpleGraph::new(3, vec![(0, 1), (1, 2), (0, 2)]),
291+
vec![One; 3],
292+
);
293+
assert!(!problem.is_weighted());
294+
assert_eq!(problem.evaluate(&[1, 1, 1]), Max(Some(3)));
295+
assert_eq!(problem.evaluate(&[1, 1, 0]), Max(Some(2)));
296+
// Invalid clique on this graph? K3 is complete, so every subset is a clique.
297+
// Re-verify invalidity on a path graph:
298+
let path = MaximumClique::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![One; 3]);
299+
assert_eq!(path.evaluate(&[1, 0, 1]), Max(None));
300+
301+
let solver = BruteForce::new();
302+
let solutions = solver.find_all_witnesses(&problem);
303+
assert_eq!(solutions.len(), 1);
304+
assert_eq!(solutions[0], vec![1, 1, 1]);
305+
}
306+
284307
#[test]
285308
fn test_clique_paper_example() {
286309
use crate::traits::Problem;

src/unit_tests/rules/maximumclique_maximumindependentset.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::rules::test_helpers::assert_optimization_round_trip_from_optimization
33
use crate::solvers::BruteForce;
44
use crate::topology::Graph;
55
use crate::traits::Problem;
6+
use crate::types::One;
67

78
#[test]
89
fn test_maximumclique_to_maximumindependentset_closed_loop() {
@@ -84,6 +85,27 @@ fn test_maximumclique_to_maximumindependentset_empty_graph() {
8485
.all(|s| s.iter().sum::<usize>() == 1));
8586
}
8687

88+
#[test]
89+
fn test_maximumclique_to_maximumindependentset_one_weights_closed_loop() {
90+
// Same P4 as the i32 closed-loop test, but with unit weights so the
91+
// reduction stays on the <SimpleGraph, One> endpoint (no i32 detour).
92+
let source = MaximumClique::new(
93+
SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]),
94+
vec![One; 4],
95+
);
96+
let reduction = ReduceTo::<MaximumIndependentSet<SimpleGraph, One>>::reduce_to(&source);
97+
let target = reduction.target_problem();
98+
99+
assert_eq!(target.graph().num_vertices(), 4);
100+
assert_eq!(target.graph().num_edges(), 3);
101+
102+
assert_optimization_round_trip_from_optimization_target(
103+
&source,
104+
&reduction,
105+
"MaximumClique<One>->MaximumIndependentSet<One> closed loop",
106+
);
107+
}
108+
87109
#[test]
88110
fn test_maximumclique_to_maximumindependentset_overhead() {
89111
// Verify overhead formula: complement edges = n*(n-1)/2 - m

src/unit_tests/rules/maximumindependentset_maximumclique.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::*;
22
use crate::rules::test_helpers::assert_optimization_round_trip_from_optimization_target;
33
use crate::solvers::BruteForce;
44
use crate::traits::Problem;
5+
use crate::types::One;
56

67
#[test]
78
fn test_maximumindependentset_to_maximumclique_closed_loop() {
@@ -66,6 +67,26 @@ fn test_maximumindependentset_to_maximumclique_empty_graph() {
6667
assert!(best_target.iter().all(|s| s.iter().sum::<usize>() == 4));
6768
}
6869

70+
#[test]
71+
fn test_maximumindependentset_to_maximumclique_one_weights_closed_loop() {
72+
// Unit-weight closed loop: <SimpleGraph, One> endpoint stays on One all the way.
73+
let source = MaximumIndependentSet::new(
74+
SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]),
75+
vec![One; 5],
76+
);
77+
let reduction = ReduceTo::<MaximumClique<SimpleGraph, One>>::reduce_to(&source);
78+
let target = reduction.target_problem();
79+
80+
assert_eq!(target.num_vertices(), 5);
81+
assert_eq!(target.num_edges(), 6);
82+
83+
assert_optimization_round_trip_from_optimization_target(
84+
&source,
85+
&reduction,
86+
"MaximumIndependentSet<One>->MaximumClique<One> closed loop",
87+
);
88+
}
89+
6990
#[test]
7091
fn test_maximumindependentset_to_maximumclique_complete_graph() {
7192
// Complete graph K4 - complement is empty graph

0 commit comments

Comments
 (0)