problemreductions/rules/
graphpartitioning_maxcut.rs1use crate::models::graph::{GraphPartitioning, MaxCut};
4use crate::reduction;
5use crate::rules::traits::{ReduceTo, ReductionResult};
6use crate::topology::{Graph, SimpleGraph};
7
8#[derive(Debug, Clone)]
10pub struct ReductionGPToMaxCut {
11 target: MaxCut<SimpleGraph, i32>,
12}
13
14#[cfg(any(test, feature = "example-db"))]
15const ISSUE_EXAMPLE_WITNESS: [usize; 6] = [0, 0, 0, 1, 1, 1];
16
17impl ReductionResult for ReductionGPToMaxCut {
18 type Source = GraphPartitioning<SimpleGraph>;
19 type Target = MaxCut<SimpleGraph, i32>;
20
21 fn target_problem(&self) -> &Self::Target {
22 &self.target
23 }
24
25 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
26 target_solution.to_vec()
27 }
28}
29
30#[cfg(any(test, feature = "example-db"))]
31fn issue_example() -> GraphPartitioning<SimpleGraph> {
32 GraphPartitioning::new(SimpleGraph::new(
33 6,
34 vec![
35 (0, 1),
36 (0, 2),
37 (1, 2),
38 (1, 3),
39 (2, 3),
40 (2, 4),
41 (3, 4),
42 (3, 5),
43 (4, 5),
44 ],
45 ))
46}
47
48fn complete_graph_edges_and_weights(graph: &SimpleGraph) -> (Vec<(usize, usize)>, Vec<i32>) {
49 let num_vertices = graph.num_vertices();
50 let p = penalty_weight(graph.num_edges());
51 let mut edges = Vec::new();
52 let mut weights = Vec::new();
53
54 for u in 0..num_vertices {
55 for v in (u + 1)..num_vertices {
56 edges.push((u, v));
57 weights.push(if graph.has_edge(u, v) { p - 1 } else { p });
58 }
59 }
60
61 (edges, weights)
62}
63
64fn penalty_weight(num_edges: usize) -> i32 {
65 i32::try_from(num_edges)
66 .ok()
67 .and_then(|num_edges| num_edges.checked_add(1))
68 .expect("GraphPartitioning -> MaxCut penalty exceeds i32 range")
69}
70
71#[reduction(
72 overhead = {
73 num_vertices = "num_vertices",
74 num_edges = "num_vertices * (num_vertices - 1) / 2",
75 }
76)]
77impl ReduceTo<MaxCut<SimpleGraph, i32>> for GraphPartitioning<SimpleGraph> {
78 type Result = ReductionGPToMaxCut;
79
80 fn reduce_to(&self) -> Self::Result {
81 let (edges, weights) = complete_graph_edges_and_weights(self.graph());
82 let target = MaxCut::new(SimpleGraph::new(self.num_vertices(), edges), weights);
83
84 ReductionGPToMaxCut { target }
85 }
86}
87
88#[cfg(feature = "example-db")]
89pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
90 use crate::export::SolutionPair;
91
92 vec![crate::example_db::specs::RuleExampleSpec {
93 id: "graphpartitioning_to_maxcut",
94 build: || {
95 crate::example_db::specs::rule_example_with_witness::<_, MaxCut<SimpleGraph, i32>>(
96 issue_example(),
97 SolutionPair {
98 source_config: ISSUE_EXAMPLE_WITNESS.to_vec(),
99 target_config: ISSUE_EXAMPLE_WITNESS.to_vec(),
100 },
101 )
102 },
103 }]
104}
105
106#[cfg(test)]
107#[path = "../unit_tests/rules/graphpartitioning_maxcut.rs"]
108mod tests;