1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
11use crate::models::graph::KColoring;
12use crate::reduction;
13use crate::rules::ilp_helpers::one_hot_decode_rows;
14use crate::rules::traits::{ReduceTo, ReductionResult};
15use crate::topology::{Graph, SimpleGraph};
16use crate::variant::{KValue, K1, K2, K3, K4, KN};
17
18#[derive(Debug, Clone)]
25pub struct ReductionKColoringToILP<K: KValue, G> {
26 target: ILP<bool>,
27 num_vertices: usize,
28 num_colors: usize,
29 _phantom: std::marker::PhantomData<(K, G)>,
30}
31
32impl<K: KValue, G> ReductionResult for ReductionKColoringToILP<K, G>
33where
34 G: Graph + crate::variant::VariantParam,
35{
36 type Source = KColoring<K, G>;
37 type Target = ILP<bool>;
38
39 fn target_problem(&self) -> &ILP<bool> {
40 &self.target
41 }
42
43 fn extract_solution(
48 &self,
49 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
50 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
51 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
52
53 one_hot_decode_rows(target_solution, self.num_vertices, self.num_colors, 0)
54 }
55}
56
57fn reduce_kcoloring_to_ilp<K: KValue, G: Graph>(
59 problem: &KColoring<K, G>,
60) -> Result<ReductionKColoringToILP<K, G>, crate::registry::ConstructionError> {
61 let k = problem.num_colors();
62 let num_vertices = problem.graph().num_vertices();
63 let num_vars = num_vertices * k;
64
65 let var_index = |v: usize, c: usize| -> usize { v * k + c };
67
68 let mut constraints = Vec::new();
69
70 for v in 0..num_vertices {
73 let terms: Vec<(usize, i64)> = (0..k).map(|c| (var_index(v, c), 1)).collect();
74 constraints.push(LinearConstraint::eq(terms, 1));
75 }
76
77 for (u, v) in problem.graph().edges() {
80 for c in 0..k {
81 constraints.push(LinearConstraint::le(
82 vec![(var_index(u, c), 1), (var_index(v, c), 1)],
83 1,
84 ));
85 }
86 }
87
88 let objective: Vec<(usize, i64)> = vec![];
91
92 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize)?;
93
94 Ok(ReductionKColoringToILP {
95 target,
96 num_vertices,
97 num_colors: k,
98 _phantom: std::marker::PhantomData,
99 })
100}
101
102#[reduction(
104 transform = exact {
105 num_vars = "num_vertices * num_colors",
106 num_constraints = "num_vertices + num_edges * num_colors",
107 num_nonzeros = "num_colors * (num_vertices + 2 * num_edges)",
108 }
109)]
110impl ReduceTo<ILP<bool>> for KColoring<KN, SimpleGraph> {
111 type Result = ReductionKColoringToILP<KN, SimpleGraph>;
112
113 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
114 reduce_kcoloring_to_ilp(self).map_err(<Self as ReduceTo<ILP<bool>>>::target_construction)
115 }
116}
117
118macro_rules! impl_kcoloring_to_ilp {
120 ($($ktype:ty),+) => {$(
121 impl ReduceTo<ILP<bool>> for KColoring<$ktype, SimpleGraph> {
122 type Result = ReductionKColoringToILP<$ktype, SimpleGraph>;
123 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
124 reduce_kcoloring_to_ilp(self)
125 .map_err(<Self as ReduceTo<ILP<bool>>>::target_construction)
126 }
127 }
128 )+};
129}
130
131impl_kcoloring_to_ilp!(K1, K2, K3, K4);
132
133#[cfg(feature = "example-db")]
134pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
135 use crate::export::SolutionPair;
136 use crate::topology::SimpleGraph;
137
138 vec![crate::example_db::specs::RuleExampleSpec {
139 id: "kcoloring_to_ilp",
140 build: || {
141 let (n, edges) = crate::topology::small_graphs::petersen();
142 let source = KColoring::<KN, _>::with_k(SimpleGraph::new(n, edges), 3);
143 crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
144 source,
145 SolutionPair {
146 source_config: serde_json::json!(vec![0, 2, 0, 1, 2, 1, 1, 2, 0, 0]),
147 target_config: serde_json::json!(vec![
148 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1,
149 0, 0, 1, 0, 0,
150 ]),
151 },
152 )
153 },
154 }]
155}
156
157#[cfg(test)]
158#[path = "../unit_tests/rules/coloring_ilp.rs"]
159mod tests;