problemreductions/models/graph/
monochromatic_triangle.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
9use crate::topology::{Graph, SimpleGraph};
10use crate::traits::Problem;
11use crate::variant::VariantParam;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15inventory::submit! {
16 ProblemSchemaEntry {
17 name: "MonochromaticTriangle",
18 display_name: "Monochromatic Triangle",
19 aliases: &[],
20 dimensions: &[
21 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
22 ],
23 category: crate::registry::ProblemCategory::Graph,
24 module_path: module_path!(),
25 description: "2-color edges so that no triangle is monochromatic",
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)]
61#[serde(try_from = "MonochromaticTriangleData<G>")]
62#[serde(bound(deserialize = "G: Graph + Deserialize<'de>"))]
63pub struct MonochromaticTriangle<G> {
64 graph: G,
66 triangles: Vec<[usize; 3]>,
68 edge_list: Vec<(usize, usize)>,
70}
71
72#[derive(Deserialize)]
74#[serde(bound(deserialize = "G: Graph + Deserialize<'de>"))]
75struct MonochromaticTriangleData<G> {
76 graph: G,
77}
78
79impl<G> TryFrom<MonochromaticTriangleData<G>> for MonochromaticTriangle<G>
80where
81 G: Graph,
82{
83 type Error = crate::registry::ConstructionError;
84
85 fn try_from(data: MonochromaticTriangleData<G>) -> Result<Self, Self::Error> {
86 Ok(Self::new(data.graph))
87 }
88}
89
90impl<G: Graph> MonochromaticTriangle<G> {
91 pub fn new(graph: G) -> Self {
93 let edge_list = graph.edges();
94 let mut edge_index: HashMap<(usize, usize), usize> = HashMap::new();
96 for (idx, &(u, v)) in edge_list.iter().enumerate() {
97 let key = if u < v { (u, v) } else { (v, u) };
98 edge_index.insert(key, idx);
99 }
100
101 let n = graph.num_vertices();
104 let mut triangles = Vec::new();
105 for u in 0..n {
106 for v in (u + 1)..n {
107 if !graph.has_edge(u, v) {
108 continue;
109 }
110 for w in (v + 1)..n {
111 if graph.has_edge(u, w) && graph.has_edge(v, w) {
112 let e_uv = edge_index[&(u, v)];
113 let e_uw = edge_index[&(u, w)];
114 let e_vw = edge_index[&(v, w)];
115 triangles.push([e_uv, e_uw, e_vw]);
116 }
117 }
118 }
119 }
120
121 Self {
122 graph,
123 triangles,
124 edge_list,
125 }
126 }
127
128 pub fn graph(&self) -> &G {
130 &self.graph
131 }
132
133 pub fn num_vertices(&self) -> usize {
135 self.graph.num_vertices()
136 }
137
138 pub fn num_edges(&self) -> usize {
140 self.graph.num_edges()
141 }
142
143 pub fn triangles(&self) -> &[[usize; 3]] {
145 &self.triangles
146 }
147
148 pub fn num_triangles(&self) -> usize {
150 self.triangles.len()
151 }
152
153 pub fn edge_list(&self) -> &[(usize, usize)] {
155 &self.edge_list
156 }
157}
158
159impl<G> Problem for MonochromaticTriangle<G>
160where
161 G: Graph + VariantParam,
162{
163 const NAME: &'static str = "MonochromaticTriangle";
164 type Solution = Vec<bool>;
165 type Value = crate::types::Or;
166
167 crate::problem_parameters![
168 ("num_edges", num_edges),
169 ("num_triangles", num_triangles),
170 ("num_vertices", num_vertices),
171 ];
172
173 fn variant() -> Vec<(&'static str, &'static str)> {
174 crate::variant_params![G]
175 }
176
177 fn evaluate(
178 &self,
179 config: &Self::Solution,
180 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
181 Ok({
182 crate::types::Or({
183 if config.len() != self.edge_list.len() {
184 return Err(crate::traits::EvaluationError::InvalidConfiguration(
185 "edge-coloring length does not match the graph".into(),
186 ));
187 }
188
189 for tri in &self.triangles {
192 let c0 = config[tri[0]];
193 let c1 = config[tri[1]];
194 let c2 = config[tri[2]];
195 if c0 == c1 && c1 == c2 {
196 return Ok(crate::types::Or(false));
197 }
198 }
199
200 true
201 })
202 })
203 }
204}
205
206impl<G> crate::solvers::BruteForceProblem for MonochromaticTriangle<G>
207where
208 G: Graph + VariantParam,
209{
210 fn dimensions(&self) -> Vec<usize> {
211 vec![2; self.edge_list.len()]
212 }
213}
214
215crate::declare_variants! {
216 default MonochromaticTriangle<SimpleGraph> => "2^num_edges",
217}
218
219crate::register_brute_force! {
220 MonochromaticTriangle<SimpleGraph> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
221}
222
223#[cfg(feature = "example-db")]
224pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
225 vec![crate::example_db::specs::ModelExampleSpec {
233 id: "monochromatic_triangle_simplegraph",
234 instance: Box::new(MonochromaticTriangle::new(SimpleGraph::new(
235 4,
236 vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)],
237 ))),
238 optimal_config: serde_json::json!(vec![false, false, true, true, false, true]),
239 optimal_value: serde_json::json!(true),
240 }]
241}
242
243#[cfg(test)]
244#[path = "../../unit_tests/models/graph/monochromatic_triangle.rs"]
245mod tests;