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 module_path: module_path!(),
24 description: "Find a complete proper coloring maximizing the number of colors",
25 fields: &[
26 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
27 ],
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct MaximumAchromaticNumber<G> {
62 graph: G,
64}
65
66impl<G: Graph> MaximumAchromaticNumber<G> {
67 pub fn new(graph: G) -> Self {
69 Self { graph }
70 }
71
72 pub fn graph(&self) -> &G {
74 &self.graph
75 }
76
77 pub fn num_vertices(&self) -> usize {
79 self.graph.num_vertices()
80 }
81
82 pub fn num_edges(&self) -> usize {
84 self.graph.num_edges()
85 }
86
87 pub fn is_proper_coloring(&self, config: &[usize]) -> bool {
92 for (u, v) in self.graph.edges() {
93 if config[u] == config[v] {
94 return false;
95 }
96 }
97 true
98 }
99
100 pub fn is_complete_coloring(&self, config: &[usize]) -> bool {
106 let used_colors: HashSet<usize> = config.iter().copied().collect();
107 let colors: Vec<usize> = used_colors.into_iter().collect();
108
109 for i in 0..colors.len() {
110 for j in (i + 1)..colors.len() {
111 let c1 = colors[i];
112 let c2 = colors[j];
113 let has_edge = self.graph.edges().iter().any(|&(u, v)| {
114 (config[u] == c1 && config[v] == c2) || (config[u] == c2 && config[v] == c1)
115 });
116 if !has_edge {
117 return false;
118 }
119 }
120 }
121 true
122 }
123}
124
125impl<G> Problem for MaximumAchromaticNumber<G>
126where
127 G: Graph + crate::variant::VariantParam,
128{
129 const NAME: &'static str = "MaximumAchromaticNumber";
130 type Value = Max<usize>;
131
132 fn variant() -> Vec<(&'static str, &'static str)> {
133 crate::variant_params![G]
134 }
135
136 fn dims(&self) -> Vec<usize> {
137 vec![self.graph.num_vertices(); self.graph.num_vertices()]
138 }
139
140 fn evaluate(&self, config: &[usize]) -> Max<usize> {
141 if config.len() != self.graph.num_vertices() {
142 return Max(None);
143 }
144 if self.graph.num_vertices() == 0 {
145 return Max(Some(0));
146 }
147 if !self.is_proper_coloring(config) {
148 return Max(None);
149 }
150 if !self.is_complete_coloring(config) {
151 return Max(None);
152 }
153 let distinct_colors: HashSet<usize> = config.iter().copied().collect();
154 Max(Some(distinct_colors.len()))
155 }
156}
157
158crate::declare_variants! {
159 default MaximumAchromaticNumber<SimpleGraph> => "num_vertices^num_vertices",
160}
161
162#[cfg(feature = "example-db")]
163pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
164 vec![crate::example_db::specs::ModelExampleSpec {
167 id: "maximum_achromatic_number_simplegraph",
168 instance: Box::new(MaximumAchromaticNumber::new(SimpleGraph::new(
169 6,
170 vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)],
171 ))),
172 optimal_config: vec![0, 1, 2, 0, 1, 2],
173 optimal_value: serde_json::json!(3),
174 }]
175}
176
177#[cfg(test)]
178#[path = "../../unit_tests/models/graph/maximum_achromatic_number.rs"]
179mod tests;