problemreductions/rules/
graphpartitioning_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
9use crate::models::graph::GraphPartitioning;
10use crate::reduction;
11use crate::rules::traits::{ReduceTo, ReductionResult};
12use crate::topology::{Graph, SimpleGraph};
13
14#[derive(Debug, Clone)]
20pub struct ReductionGraphPartitioningToILP {
21 target: ILP<bool>,
22 num_vertices: usize,
23}
24
25impl ReductionResult for ReductionGraphPartitioningToILP {
26 type Source = GraphPartitioning<SimpleGraph>;
27 type Target = ILP<bool>;
28
29 fn target_problem(&self) -> &ILP<bool> {
30 &self.target
31 }
32
33 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
34 target_solution[..self.num_vertices].to_vec()
35 }
36}
37
38#[reduction(
39 overhead = {
40 num_vars = "num_vertices + num_edges",
41 num_constraints = "2 * num_edges + 1",
42 }
43)]
44impl ReduceTo<ILP<bool>> for GraphPartitioning<SimpleGraph> {
45 type Result = ReductionGraphPartitioningToILP;
46
47 fn reduce_to(&self) -> Self::Result {
48 let n = self.num_vertices();
49 let edges = self.graph().edges();
50 let m = edges.len();
51 let num_vars = n + m;
52
53 let mut constraints = Vec::with_capacity(2 * m + 1);
54
55 let balance_terms: Vec<(usize, f64)> = (0..n).map(|v| (v, 1.0)).collect();
56 constraints.push(LinearConstraint::eq(balance_terms, n as f64 / 2.0));
57
58 for (edge_idx, (u, v)) in edges.iter().enumerate() {
59 let y_var = n + edge_idx;
60 constraints.push(LinearConstraint::ge(
61 vec![(y_var, 1.0), (*u, -1.0), (*v, 1.0)],
62 0.0,
63 ));
64 constraints.push(LinearConstraint::ge(
65 vec![(y_var, 1.0), (*u, 1.0), (*v, -1.0)],
66 0.0,
67 ));
68 }
69
70 let objective: Vec<(usize, f64)> = (0..m).map(|edge_idx| (n + edge_idx, 1.0)).collect();
71 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize);
72
73 ReductionGraphPartitioningToILP {
74 target,
75 num_vertices: n,
76 }
77 }
78}
79
80#[cfg(feature = "example-db")]
81pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
82 use crate::export::SolutionPair;
83
84 vec![crate::example_db::specs::RuleExampleSpec {
85 id: "graphpartitioning_to_ilp",
86 build: || {
87 let source = GraphPartitioning::new(SimpleGraph::new(
88 6,
89 vec![
90 (0, 1),
91 (0, 2),
92 (1, 2),
93 (1, 3),
94 (2, 3),
95 (2, 4),
96 (3, 4),
97 (3, 5),
98 (4, 5),
99 ],
100 ));
101 crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
102 source,
103 SolutionPair {
104 source_config: vec![0, 0, 0, 1, 1, 1],
105 target_config: vec![0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0],
106 },
107 )
108 },
109 }]
110}
111
112#[cfg(test)]
113#[path = "../unit_tests/rules/graphpartitioning_ilp.rs"]
114mod tests;