problemreductions/models/graph/
kcoloring.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::{Problem, SatisfactionProblem};
9use crate::variant::{KValue, VariantParam, K2, K3, K4, K5, KN};
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "KColoring",
15 module_path: module_path!(),
16 description: "Find valid k-coloring of a graph",
17 fields: &[
18 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
19 ],
20 }
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
54#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
55pub struct KColoring<K: KValue, G> {
56 graph: G,
58 #[serde(default = "default_num_colors::<K>")]
60 num_colors: usize,
61 #[serde(skip)]
62 _phantom: std::marker::PhantomData<K>,
63}
64
65fn default_num_colors<K: KValue>() -> usize {
66 K::K.unwrap_or(0)
67}
68
69impl<K: KValue, G: Graph> KColoring<K, G> {
70 pub fn new(graph: G) -> Self {
75 Self {
76 graph,
77 num_colors: K::K.expect("KN requires with_k"),
78 _phantom: std::marker::PhantomData,
79 }
80 }
81
82 pub fn graph(&self) -> &G {
84 &self.graph
85 }
86
87 pub fn num_colors(&self) -> usize {
89 self.num_colors
90 }
91
92 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
94 is_valid_coloring(&self.graph, config, self.num_colors)
95 }
96
97 fn is_valid_coloring(&self, config: &[usize]) -> bool {
99 for (u, v) in self.graph.edges() {
100 let color_u = config.get(u).copied().unwrap_or(0);
101 let color_v = config.get(v).copied().unwrap_or(0);
102 if color_u == color_v {
103 return false;
104 }
105 }
106 true
107 }
108}
109
110impl<G: Graph> KColoring<KN, G> {
111 pub fn with_k(graph: G, num_colors: usize) -> Self {
117 Self {
118 graph,
119 num_colors,
120 _phantom: std::marker::PhantomData,
121 }
122 }
123}
124
125impl<K: KValue, G: Graph> KColoring<K, G> {
126 pub fn num_vertices(&self) -> usize {
128 self.graph().num_vertices()
129 }
130
131 pub fn num_edges(&self) -> usize {
133 self.graph().num_edges()
134 }
135}
136
137impl<K: KValue, G> Problem for KColoring<K, G>
138where
139 G: Graph + VariantParam,
140{
141 const NAME: &'static str = "KColoring";
142 type Metric = bool;
143
144 fn variant() -> Vec<(&'static str, &'static str)> {
145 crate::variant_params![K, G]
146 }
147
148 fn dims(&self) -> Vec<usize> {
149 vec![self.num_colors; self.graph.num_vertices()]
150 }
151
152 fn evaluate(&self, config: &[usize]) -> bool {
153 self.is_valid_coloring(config)
154 }
155}
156
157impl<K: KValue, G: Graph + VariantParam> SatisfactionProblem for KColoring<K, G> {}
158
159pub(crate) fn is_valid_coloring<G: Graph>(
164 graph: &G,
165 coloring: &[usize],
166 num_colors: usize,
167) -> bool {
168 assert_eq!(
169 coloring.len(),
170 graph.num_vertices(),
171 "coloring length must match num_vertices"
172 );
173 if coloring.iter().any(|&c| c >= num_colors) {
175 return false;
176 }
177 for (u, v) in graph.edges() {
179 if coloring[u] == coloring[v] {
180 return false;
181 }
182 }
183 true
184}
185
186crate::declare_variants! {
187 KColoring<KN, SimpleGraph> => "2^num_vertices",
188 KColoring<K2, SimpleGraph> => "num_vertices + num_edges",
189 KColoring<K3, SimpleGraph> => "1.3289^num_vertices",
190 KColoring<K4, SimpleGraph> => "1.7159^num_vertices",
191 KColoring<K5, SimpleGraph> => "2^num_vertices",
193}
194
195#[cfg(test)]
196#[path = "../../unit_tests/models/graph/kcoloring.rs"]
197mod tests;