problemreductions/models/set/
set_splitting.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
7use crate::traits::Problem;
8use serde::{Deserialize, Serialize};
9
10inventory::submit! {
11 ProblemSchemaEntry {
12 name: "SetSplitting",
13 display_name: "Set Splitting",
14 aliases: &[],
15 dimensions: &[],
16 module_path: module_path!(),
17 description: "Partition a universe into two parts so that every subset is non-monochromatic",
18 fields: &[
19 FieldInfo { name: "universe_size", type_name: "usize", description: "universe_size" },
20 FieldInfo { name: "subsets", type_name: "Vec<Vec<usize>>", description: "Subsets that must each contain elements from both parts" },
21 ],
22 }
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
52#[serde(try_from = "SetSplittingDef")]
53pub struct SetSplitting {
54 universe_size: usize,
56 subsets: Vec<Vec<usize>>,
58}
59
60fn normalize_subsets(universe_size: usize, subsets: &[Vec<usize>]) -> (usize, Vec<Vec<usize>>) {
61 let mut next_element = universe_size;
62 let total_excess: usize = subsets
63 .iter()
64 .map(|subset| subset.len().saturating_sub(3))
65 .sum();
66 let mut normalized = Vec::with_capacity(subsets.len() + 2 * total_excess);
67
68 for subset in subsets {
69 let mut remainder = subset.clone();
70 while remainder.len() > 3 {
71 let positive_aux = next_element;
72 let negative_aux = next_element + 1;
73 next_element += 2;
74
75 normalized.push(vec![remainder[0], remainder[1], positive_aux]);
76 normalized.push(vec![positive_aux, negative_aux]);
77
78 let mut next_remainder = Vec::with_capacity(remainder.len() - 1);
79 next_remainder.push(negative_aux);
80 next_remainder.extend_from_slice(&remainder[2..]);
81 remainder = next_remainder;
82 }
83 normalized.push(remainder);
84 }
85
86 (next_element, normalized)
87}
88
89impl SetSplitting {
90 pub fn new(universe_size: usize, subsets: Vec<Vec<usize>>) -> Self {
97 Self::try_new(universe_size, subsets).unwrap_or_else(|err| panic!("{err}"))
98 }
99
100 pub fn try_new(universe_size: usize, subsets: Vec<Vec<usize>>) -> Result<Self, String> {
102 for (i, subset) in subsets.iter().enumerate() {
103 if subset.len() < 2 {
104 return Err(format!(
105 "Subset {} has {} element(s), expected at least 2",
106 i,
107 subset.len()
108 ));
109 }
110 for &elem in subset {
111 if elem >= universe_size {
112 return Err(format!(
113 "Subset {} contains element {} which is outside universe of size {}",
114 i, elem, universe_size
115 ));
116 }
117 }
118 }
119 Ok(Self {
120 universe_size,
121 subsets,
122 })
123 }
124
125 pub fn universe_size(&self) -> usize {
127 self.universe_size
128 }
129
130 pub fn num_subsets(&self) -> usize {
132 self.subsets.len()
133 }
134
135 pub fn subsets(&self) -> &[Vec<usize>] {
137 &self.subsets
138 }
139
140 pub(crate) fn normalized_instance(&self) -> (usize, Vec<Vec<usize>>) {
141 normalize_subsets(self.universe_size, &self.subsets)
142 }
143
144 fn normalized_stats(&self) -> (usize, usize, usize) {
145 let (universe_size, subsets) = self.normalized_instance();
146 let size2 = subsets.iter().filter(|s| s.len() == 2).count();
147 let size3 = subsets.iter().filter(|s| s.len() == 3).count();
148 (universe_size, size2, size3)
149 }
150
151 pub fn normalized_universe_size(&self) -> usize {
153 self.normalized_stats().0
154 }
155
156 pub fn normalized_num_size2_subsets(&self) -> usize {
158 self.normalized_stats().1
159 }
160
161 pub fn normalized_num_size3_subsets(&self) -> usize {
163 self.normalized_stats().2
164 }
165
166 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
168 self.evaluate(config).0
169 }
170}
171
172impl Problem for SetSplitting {
173 const NAME: &'static str = "SetSplitting";
174 type Value = crate::types::Or;
175
176 fn dims(&self) -> Vec<usize> {
177 vec![2; self.universe_size]
178 }
179
180 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
181 crate::types::Or(self.subsets.iter().all(|subset| {
182 let has_zero = subset.iter().any(|&e| config[e] == 0);
183 let has_one = subset.iter().any(|&e| config[e] == 1);
184 has_zero && has_one
185 }))
186 }
187
188 fn variant() -> Vec<(&'static str, &'static str)> {
189 crate::variant_params![]
190 }
191}
192
193crate::declare_variants! {
194 default SetSplitting => "2^universe_size",
195}
196
197#[derive(Debug, Clone, Deserialize)]
198struct SetSplittingDef {
199 universe_size: usize,
200 subsets: Vec<Vec<usize>>,
201}
202
203impl TryFrom<SetSplittingDef> for SetSplitting {
204 type Error = String;
205
206 fn try_from(value: SetSplittingDef) -> Result<Self, Self::Error> {
207 Self::try_new(value.universe_size, value.subsets)
208 }
209}
210
211#[cfg(feature = "example-db")]
212pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
213 vec![crate::example_db::specs::ModelExampleSpec {
214 id: "set_splitting",
215 instance: Box::new(SetSplitting::new(
216 6,
217 vec![vec![0, 1, 2], vec![2, 3, 4], vec![0, 4, 5], vec![1, 3, 5]],
218 )),
219 optimal_config: vec![1, 0, 1, 0, 0, 1],
222 optimal_value: serde_json::json!(true),
223 }]
224}
225
226#[cfg(test)]
227#[path = "../../unit_tests/models/set/set_splitting.rs"]
228mod tests;