problemreductions/models/graph/
minimum_covering_by_cliques.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::Problem;
9use crate::types::Min;
10use serde::{Deserialize, Serialize};
11use std::collections::HashSet;
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MinimumCoveringByCliques",
16 display_name: "Minimum Covering by Cliques",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 module_path: module_path!(),
22 description: "Find minimum number of cliques covering all edges",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
25 ],
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct MinimumCoveringByCliques<G> {
60 graph: G,
62}
63
64impl<G: Graph> MinimumCoveringByCliques<G> {
65 pub fn new(graph: G) -> Self {
67 Self { graph }
68 }
69
70 pub fn graph(&self) -> &G {
72 &self.graph
73 }
74
75 pub fn num_vertices(&self) -> usize {
77 self.graph.num_vertices()
78 }
79
80 pub fn num_edges(&self) -> usize {
82 self.graph.num_edges()
83 }
84
85 pub fn is_valid_cover(&self, config: &[usize]) -> bool {
90 let edges = self.graph.edges();
91 let num_edges = edges.len();
92
93 if config.len() != num_edges {
94 return false;
95 }
96
97 let max_group = match config.iter().max() {
99 Some(&m) => m,
100 None => return true, };
102
103 let mut groups: Vec<HashSet<usize>> = vec![HashSet::new(); max_group + 1];
104 for (idx, &group) in config.iter().enumerate() {
105 let (u, v) = edges[idx];
106 groups[group].insert(u);
107 groups[group].insert(v);
108 }
109
110 for vertices in &groups {
112 let verts: Vec<usize> = vertices.iter().copied().collect();
113 for i in 0..verts.len() {
114 for j in (i + 1)..verts.len() {
115 if !self.graph.has_edge(verts[i], verts[j]) {
116 return false;
117 }
118 }
119 }
120 }
121
122 true
123 }
124}
125
126impl<G> Problem for MinimumCoveringByCliques<G>
127where
128 G: Graph + crate::variant::VariantParam,
129{
130 const NAME: &'static str = "MinimumCoveringByCliques";
131 type Value = Min<usize>;
132
133 fn variant() -> Vec<(&'static str, &'static str)> {
134 crate::variant_params![G]
135 }
136
137 fn dims(&self) -> Vec<usize> {
138 vec![self.graph.num_edges(); self.graph.num_edges()]
139 }
140
141 fn evaluate(&self, config: &[usize]) -> Min<usize> {
142 if config.len() != self.graph.num_edges() {
143 return Min(None);
144 }
145 if self.graph.num_edges() == 0 {
146 return Min(Some(0));
147 }
148 if !self.is_valid_cover(config) {
149 return Min(None);
150 }
151 let distinct_groups: HashSet<usize> = config.iter().copied().collect();
152 Min(Some(distinct_groups.len()))
153 }
154}
155
156crate::declare_variants! {
157 default MinimumCoveringByCliques<SimpleGraph> => "2^num_edges",
158}
159
160#[cfg(feature = "example-db")]
161pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
162 vec![crate::example_db::specs::ModelExampleSpec {
171 id: "minimum_covering_by_cliques_simplegraph",
172 instance: Box::new(MinimumCoveringByCliques::new(SimpleGraph::new(
173 6,
174 vec![
175 (0, 1),
176 (1, 2),
177 (2, 3),
178 (3, 0),
179 (0, 2),
180 (4, 0),
181 (4, 1),
182 (5, 2),
183 (5, 3),
184 ],
185 ))),
186 optimal_config: vec![0, 0, 1, 1, 0, 2, 2, 3, 3],
187 optimal_value: serde_json::json!(4),
188 }]
189}
190
191#[cfg(test)]
192#[path = "../../unit_tests/models/graph/minimum_covering_by_cliques.rs"]
193mod tests;