problemreductions/rules/
coloring_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
11use crate::models::graph::KColoring;
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14use crate::topology::{Graph, SimpleGraph};
15use crate::variant::{KValue, K1, K2, K3, K4, KN};
16
17#[derive(Debug, Clone)]
24pub struct ReductionKColoringToILP<K: KValue, G> {
25 target: ILP<bool>,
26 num_vertices: usize,
27 num_colors: usize,
28 _phantom: std::marker::PhantomData<(K, G)>,
29}
30
31impl<K: KValue, G> ReductionKColoringToILP<K, G> {
32 fn var_index(&self, vertex: usize, color: usize) -> usize {
34 vertex * self.num_colors + color
35 }
36}
37
38impl<K: KValue, G> ReductionResult for ReductionKColoringToILP<K, G>
39where
40 G: Graph + crate::variant::VariantParam,
41{
42 type Source = KColoring<K, G>;
43 type Target = ILP<bool>;
44
45 fn target_problem(&self) -> &ILP<bool> {
46 &self.target
47 }
48
49 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
54 let k = self.num_colors;
55 (0..self.num_vertices)
56 .map(|v| {
57 (0..k)
58 .find(|&c| {
59 let var_idx = self.var_index(v, c);
60 var_idx < target_solution.len() && target_solution[var_idx] == 1
61 })
62 .unwrap_or(0)
63 })
64 .collect()
65 }
66}
67
68fn reduce_kcoloring_to_ilp<K: KValue, G: Graph>(
70 problem: &KColoring<K, G>,
71) -> ReductionKColoringToILP<K, G> {
72 let k = problem.num_colors();
73 let num_vertices = problem.graph().num_vertices();
74 let num_vars = num_vertices * k;
75
76 let var_index = |v: usize, c: usize| -> usize { v * k + c };
78
79 let mut constraints = Vec::new();
80
81 for v in 0..num_vertices {
84 let terms: Vec<(usize, f64)> = (0..k).map(|c| (var_index(v, c), 1.0)).collect();
85 constraints.push(LinearConstraint::eq(terms, 1.0));
86 }
87
88 for (u, v) in problem.graph().edges() {
91 for c in 0..k {
92 constraints.push(LinearConstraint::le(
93 vec![(var_index(u, c), 1.0), (var_index(v, c), 1.0)],
94 1.0,
95 ));
96 }
97 }
98
99 let objective: Vec<(usize, f64)> = vec![];
102
103 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize);
104
105 ReductionKColoringToILP {
106 target,
107 num_vertices,
108 num_colors: k,
109 _phantom: std::marker::PhantomData,
110 }
111}
112
113#[reduction(
115 overhead = {
116 num_vars = "num_vertices^2",
117 num_constraints = "num_vertices + num_vertices * num_edges",
118 }
119)]
120impl ReduceTo<ILP<bool>> for KColoring<KN, SimpleGraph> {
121 type Result = ReductionKColoringToILP<KN, SimpleGraph>;
122
123 fn reduce_to(&self) -> Self::Result {
124 reduce_kcoloring_to_ilp(self)
125 }
126}
127
128macro_rules! impl_kcoloring_to_ilp {
130 ($($ktype:ty),+) => {$(
131 impl ReduceTo<ILP<bool>> for KColoring<$ktype, SimpleGraph> {
132 type Result = ReductionKColoringToILP<$ktype, SimpleGraph>;
133 fn reduce_to(&self) -> Self::Result { reduce_kcoloring_to_ilp(self) }
134 }
135 )+};
136}
137
138impl_kcoloring_to_ilp!(K1, K2, K3, K4);
139
140#[cfg(test)]
141#[path = "../unit_tests/rules/coloring_ilp.rs"]
142mod tests;