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 module_path: module_path!(),
24 description: "2-color edges so that no triangle is monochromatic",
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)]
60#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
61pub struct MonochromaticTriangle<G> {
62 graph: G,
64 triangles: Vec<[usize; 3]>,
66 edge_list: Vec<(usize, usize)>,
68}
69
70impl<G: Graph> MonochromaticTriangle<G> {
71 pub fn new(graph: G) -> Self {
73 let edge_list = graph.edges();
74 let mut edge_index: HashMap<(usize, usize), usize> = HashMap::new();
76 for (idx, &(u, v)) in edge_list.iter().enumerate() {
77 let key = if u < v { (u, v) } else { (v, u) };
78 edge_index.insert(key, idx);
79 }
80
81 let n = graph.num_vertices();
84 let mut triangles = Vec::new();
85 for u in 0..n {
86 for v in (u + 1)..n {
87 if !graph.has_edge(u, v) {
88 continue;
89 }
90 for w in (v + 1)..n {
91 if graph.has_edge(u, w) && graph.has_edge(v, w) {
92 let e_uv = edge_index[&(u, v)];
93 let e_uw = edge_index[&(u, w)];
94 let e_vw = edge_index[&(v, w)];
95 triangles.push([e_uv, e_uw, e_vw]);
96 }
97 }
98 }
99 }
100
101 Self {
102 graph,
103 triangles,
104 edge_list,
105 }
106 }
107
108 pub fn graph(&self) -> &G {
110 &self.graph
111 }
112
113 pub fn num_vertices(&self) -> usize {
115 self.graph.num_vertices()
116 }
117
118 pub fn num_edges(&self) -> usize {
120 self.graph.num_edges()
121 }
122
123 pub fn triangles(&self) -> &[[usize; 3]] {
125 &self.triangles
126 }
127
128 pub fn num_triangles(&self) -> usize {
130 self.triangles.len()
131 }
132
133 pub fn edge_list(&self) -> &[(usize, usize)] {
135 &self.edge_list
136 }
137}
138
139impl<G> Problem for MonochromaticTriangle<G>
140where
141 G: Graph + VariantParam,
142{
143 const NAME: &'static str = "MonochromaticTriangle";
144 type Value = crate::types::Or;
145
146 fn variant() -> Vec<(&'static str, &'static str)> {
147 crate::variant_params![G]
148 }
149
150 fn dims(&self) -> Vec<usize> {
151 vec![2; self.edge_list.len()]
152 }
153
154 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
155 crate::types::Or({
156 if config.len() != self.edge_list.len() {
157 return crate::types::Or(false);
158 }
159
160 for tri in &self.triangles {
163 let c0 = config[tri[0]];
164 let c1 = config[tri[1]];
165 let c2 = config[tri[2]];
166 if c0 == c1 && c1 == c2 {
167 return crate::types::Or(false);
168 }
169 }
170
171 true
172 })
173 }
174}
175
176crate::declare_variants! {
177 default MonochromaticTriangle<SimpleGraph> => "2^num_edges",
178}
179
180#[cfg(feature = "example-db")]
181pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
182 vec![crate::example_db::specs::ModelExampleSpec {
190 id: "monochromatic_triangle_simplegraph",
191 instance: Box::new(MonochromaticTriangle::new(SimpleGraph::new(
192 4,
193 vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)],
194 ))),
195 optimal_config: vec![0, 0, 1, 1, 0, 1],
196 optimal_value: serde_json::json!(true),
197 }]
198}
199
200#[cfg(test)]
201#[path = "../../unit_tests/models/graph/monochromatic_triangle.rs"]
202mod tests;