problemreductions/models/graph/
maximum_achromatic_number.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
9use crate::topology::{Graph, SimpleGraph};
10use crate::traits::Problem;
11use crate::types::Max;
12use serde::{Deserialize, Serialize};
13use std::collections::HashSet;
14
15inventory::submit! {
16 ProblemSchemaEntry {
17 name: "MaximumAchromaticNumber",
18 display_name: "Maximum Achromatic Number",
19 aliases: &[],
20 dimensions: &[
21 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
22 ],
23 category: crate::registry::ProblemCategory::Graph,
24 module_path: module_path!(),
25 description: "Find a complete proper coloring maximizing the number of colors",
26 fields: &[
27 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
28 ],
29 }
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct MaximumAchromaticNumber<G> {
63 graph: G,
65}
66
67impl<G: Graph> MaximumAchromaticNumber<G> {
68 pub fn new(graph: G) -> Self {
70 Self { graph }
71 }
72
73 pub fn graph(&self) -> &G {
75 &self.graph
76 }
77
78 pub fn num_vertices(&self) -> usize {
80 self.graph.num_vertices()
81 }
82
83 pub fn num_edges(&self) -> usize {
85 self.graph.num_edges()
86 }
87
88 pub fn is_proper_coloring(&self, config: &[usize]) -> bool {
93 for (u, v) in self.graph.edges() {
94 if config[u] == config[v] {
95 return false;
96 }
97 }
98 true
99 }
100
101 pub fn is_complete_coloring(&self, config: &[usize]) -> bool {
107 let used_colors: HashSet<usize> = config.iter().copied().collect();
108 let colors: Vec<usize> = used_colors.into_iter().collect();
109
110 for i in 0..colors.len() {
111 for j in (i + 1)..colors.len() {
112 let c1 = colors[i];
113 let c2 = colors[j];
114 let has_edge = self.graph.edges().iter().any(|&(u, v)| {
115 (config[u] == c1 && config[v] == c2) || (config[u] == c2 && config[v] == c1)
116 });
117 if !has_edge {
118 return false;
119 }
120 }
121 }
122 true
123 }
124}
125
126impl<G> Problem for MaximumAchromaticNumber<G>
127where
128 G: Graph + crate::variant::VariantParam,
129{
130 const NAME: &'static str = "MaximumAchromaticNumber";
131 type Solution = Vec<usize>;
132 type Value = Max<i64>;
133
134 crate::problem_parameters![("num_edges", num_edges), ("num_vertices", num_vertices),];
135
136 fn variant() -> Vec<(&'static str, &'static str)> {
137 crate::variant_params![G]
138 }
139
140 fn evaluate(
141 &self,
142 config: &Self::Solution,
143 ) -> Result<Max<i64>, crate::traits::EvaluationError> {
144 Ok({
145 if config.len() != self.graph.num_vertices() {
146 return Err(crate::traits::EvaluationError::InvalidConfiguration(
147 "color assignment length does not match the graph vertices".into(),
148 ));
149 }
150 if self.graph.num_vertices() == 0 {
151 return Ok(Max(Some(0)));
152 }
153 if !self.is_proper_coloring(config) {
154 return Ok(Max(None));
155 }
156 if !self.is_complete_coloring(config) {
157 return Ok(Max(None));
158 }
159 let distinct_colors: HashSet<usize> = config.iter().copied().collect();
160 Max(Some(i64::try_from(distinct_colors.len()).map_err(
161 |_| {
162 crate::traits::EvaluationError::IntegerOverflow(
163 "converting achromatic color count to i64".to_string(),
164 )
165 },
166 )?))
167 })
168 }
169}
170
171impl<G> crate::solvers::BruteForceProblem for MaximumAchromaticNumber<G>
172where
173 G: Graph + crate::variant::VariantParam,
174{
175 fn dimensions(&self) -> Vec<usize> {
176 vec![self.graph.num_vertices(); self.graph.num_vertices()]
177 }
178}
179
180crate::impl_random_generate!(
181 MaximumAchromaticNumber<SimpleGraph>,
182 crate::random::SimpleGraphRandomSpec,
183 |spec| { Ok(MaximumAchromaticNumber::new(spec.graph()?)) }
184);
185
186crate::declare_variants! {
187 default MaximumAchromaticNumber<SimpleGraph> => "num_vertices^num_vertices" random,
188}
189
190crate::register_brute_force! {
191 MaximumAchromaticNumber<SimpleGraph>,
192}
193
194#[cfg(feature = "example-db")]
195pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
196 vec![crate::example_db::specs::ModelExampleSpec {
199 id: "maximum_achromatic_number_simplegraph",
200 instance: Box::new(MaximumAchromaticNumber::new(SimpleGraph::new(
201 6,
202 vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)],
203 ))),
204 optimal_config: serde_json::json!(vec![0, 1, 2, 0, 1, 2]),
205 optimal_value: serde_json::json!(3),
206 }]
207}
208
209#[cfg(test)]
210#[path = "../../unit_tests/models/graph/maximum_achromatic_number.rs"]
211mod tests;