problemreductions/models/set/
three_dimensional_matching.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
8use crate::traits::Problem;
9use serde::{Deserialize, Serialize};
10use std::collections::HashSet;
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "ThreeDimensionalMatching",
15 display_name: "Three-Dimensional Matching",
16 aliases: &["3DM"],
17 dimensions: &[],
18 category: crate::registry::ProblemCategory::Set,
19 module_path: module_path!(),
20 description: "Find a perfect matching in a tripartite hypergraph",
21 fields: &[
22 FieldInfo { name: "universe_size", type_name: "usize", description: "Size of each set W, X, Y (q)" },
23 FieldInfo { name: "triples", type_name: "Vec<(usize, usize, usize)>", description: "Set M of triples (w, x, y)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ThreeDimensionalMatching {
60 universe_size: usize,
62 triples: Vec<(usize, usize, usize)>,
64}
65
66impl ThreeDimensionalMatching {
67 pub fn new(universe_size: usize, triples: Vec<(usize, usize, usize)>) -> Self {
73 for (i, &(w, x, y)) in triples.iter().enumerate() {
74 assert!(
75 w < universe_size,
76 "Triple {} has w-coordinate {} which is outside 0..{}",
77 i,
78 w,
79 universe_size
80 );
81 assert!(
82 x < universe_size,
83 "Triple {} has x-coordinate {} which is outside 0..{}",
84 i,
85 x,
86 universe_size
87 );
88 assert!(
89 y < universe_size,
90 "Triple {} has y-coordinate {} which is outside 0..{}",
91 i,
92 y,
93 universe_size
94 );
95 }
96 Self {
97 universe_size,
98 triples,
99 }
100 }
101
102 pub fn universe_size(&self) -> usize {
104 self.universe_size
105 }
106
107 pub fn num_triples(&self) -> usize {
109 self.triples.len()
110 }
111
112 pub fn triples(&self) -> &[(usize, usize, usize)] {
114 &self.triples
115 }
116
117 pub fn get_triple(&self, index: usize) -> Option<&(usize, usize, usize)> {
119 self.triples.get(index)
120 }
121}
122
123impl Problem for ThreeDimensionalMatching {
124 const NAME: &'static str = "ThreeDimensionalMatching";
125 type Solution = Vec<bool>;
126 type Value = crate::types::Or;
127
128 crate::problem_parameters![
129 ("num_triples", num_triples),
130 ("universe_size", universe_size),
131 ];
132
133 fn evaluate(
134 &self,
135 config: &Self::Solution,
136 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
137 Ok({
138 crate::types::Or({
139 if config.len() != self.triples.len() {
140 return Err(crate::traits::EvaluationError::InvalidConfiguration(
141 "triple-selection length does not match the instance".into(),
142 ));
143 }
144
145 let selected_count = config.iter().filter(|&&v| v).count();
147 if selected_count != self.universe_size {
148 return Ok(crate::types::Or(false));
149 }
150
151 let mut used_w = HashSet::with_capacity(self.universe_size);
153 let mut used_x = HashSet::with_capacity(self.universe_size);
154 let mut used_y = HashSet::with_capacity(self.universe_size);
155
156 for (i, &selected) in config.iter().enumerate() {
157 if selected {
158 let (w, x, y) = self.triples[i];
159 if !used_w.insert(w) {
160 return Ok(crate::types::Or(false));
161 }
162 if !used_x.insert(x) {
163 return Ok(crate::types::Or(false));
164 }
165 if !used_y.insert(y) {
166 return Ok(crate::types::Or(false));
167 }
168 }
169 }
170
171 true
172 })
173 })
174 }
175
176 fn variant() -> Vec<(&'static str, &'static str)> {
177 crate::variant_params![]
178 }
179}
180
181impl crate::solvers::BruteForceProblem for ThreeDimensionalMatching {
182 fn dimensions(&self) -> Vec<usize> {
183 vec![2; self.triples.len()]
184 }
185}
186
187crate::declare_variants! {
188 default ThreeDimensionalMatching => "2^num_triples",
189}
190
191crate::register_brute_force! {
192 ThreeDimensionalMatching decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
193}
194
195#[cfg(feature = "example-db")]
196pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
197 vec![crate::example_db::specs::ModelExampleSpec {
198 id: "three_dimensional_matching",
199 instance: Box::new(ThreeDimensionalMatching::new(
200 3,
201 vec![(0, 1, 2), (1, 0, 1), (2, 2, 0), (0, 0, 0), (1, 2, 2)],
202 )),
203 optimal_config: serde_json::json!(vec![true, true, true, false, false]),
204 optimal_value: serde_json::json!(true),
205 }]
206}
207
208#[cfg(test)]
209#[path = "../../unit_tests/models/set/three_dimensional_matching.rs"]
210mod tests;