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