Skip to main content

problemreductions/models/graph/
maximum_achromatic_number.rs

1//! Maximum Achromatic Number problem implementation.
2//!
3//! Given a graph G = (V, E), find a proper coloring that uses the maximum
4//! number of colors such that the coloring is also complete: for every pair
5//! of distinct colors, there exists an edge connecting a vertex of one color
6//! to a vertex of the other.
7
8use 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/// The Maximum Achromatic Number problem.
32///
33/// Given a graph G = (V, E), find a proper coloring of the vertices using the
34/// maximum number of colors such that the coloring is *complete*: for every
35/// pair of distinct colors used, there exists at least one edge between a
36/// vertex of one color and a vertex of the other.
37///
38/// Variables: one per vertex, each selecting a color class (0..n-1).
39///
40/// # Type Parameters
41///
42/// * `G` - The graph type (e.g., `SimpleGraph`)
43///
44/// # Example
45///
46/// ```
47/// use problemreductions::models::graph::MaximumAchromaticNumber;
48/// use problemreductions::topology::SimpleGraph;
49/// use problemreductions::{Problem, Solver, BruteForce};
50///
51/// // C6: achromatic number is 3
52/// let graph = SimpleGraph::new(6, vec![(0,1),(1,2),(2,3),(3,4),(4,5),(5,0)]);
53/// let problem = MaximumAchromaticNumber::new(graph);
54///
55/// let solver = BruteForce::new();
56/// let solution = solver.find_witness(&problem).unwrap();
57/// let value = problem.evaluate(&solution);
58/// assert_eq!(value, problemreductions::types::Max(Some(3)));
59/// ```
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct MaximumAchromaticNumber<G> {
62    /// The underlying graph.
63    graph: G,
64}
65
66impl<G: Graph> MaximumAchromaticNumber<G> {
67    /// Create a MaximumAchromaticNumber problem from a graph.
68    pub fn new(graph: G) -> Self {
69        Self { graph }
70    }
71
72    /// Get a reference to the underlying graph.
73    pub fn graph(&self) -> &G {
74        &self.graph
75    }
76
77    /// Get the number of vertices in the underlying graph.
78    pub fn num_vertices(&self) -> usize {
79        self.graph.num_vertices()
80    }
81
82    /// Get the number of edges in the underlying graph.
83    pub fn num_edges(&self) -> usize {
84        self.graph.num_edges()
85    }
86
87    /// Check whether a configuration is a proper coloring.
88    ///
89    /// A proper coloring assigns colors to vertices such that no two adjacent
90    /// vertices share the same color.
91    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    /// Check whether a proper coloring is complete.
101    ///
102    /// A coloring is complete if for every pair of distinct colors used,
103    /// there exists an edge between a vertex of one color and a vertex
104    /// of the other.
105    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    // C6: 6-cycle, achromatic number = 3
165    // Coloring [0, 1, 2, 0, 1, 2] uses 3 colors and is both proper and complete.
166    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;