1use crate::graph_types::SimpleGraph;
7use crate::traits::{ConstraintSatisfactionProblem, Problem};
8use crate::types::{EnergyMode, LocalConstraint, LocalSolutionSize, ProblemSize, SolutionSize};
9use serde::{Deserialize, Serialize};
10use std::collections::HashSet;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct SetPacking<W = i32> {
42 sets: Vec<Vec<usize>>,
44 weights: Vec<W>,
46}
47
48impl<W: Clone + Default> SetPacking<W> {
49 pub fn new(sets: Vec<Vec<usize>>) -> Self
51 where
52 W: From<i32>,
53 {
54 let num_sets = sets.len();
55 let weights = vec![W::from(1); num_sets];
56 Self { sets, weights }
57 }
58
59 pub fn with_weights(sets: Vec<Vec<usize>>, weights: Vec<W>) -> Self {
61 assert_eq!(sets.len(), weights.len());
62 Self { sets, weights }
63 }
64
65 pub fn num_sets(&self) -> usize {
67 self.sets.len()
68 }
69
70 pub fn sets(&self) -> &[Vec<usize>] {
72 &self.sets
73 }
74
75 pub fn get_set(&self, index: usize) -> Option<&Vec<usize>> {
77 self.sets.get(index)
78 }
79
80 pub fn sets_overlap(&self, i: usize, j: usize) -> bool {
82 if let (Some(set_i), Some(set_j)) = (self.sets.get(i), self.sets.get(j)) {
83 let set_i: HashSet<_> = set_i.iter().collect();
84 set_j.iter().any(|e| set_i.contains(e))
85 } else {
86 false
87 }
88 }
89
90 pub fn overlapping_pairs(&self) -> Vec<(usize, usize)> {
92 let mut pairs = Vec::new();
93 for i in 0..self.sets.len() {
94 for j in (i + 1)..self.sets.len() {
95 if self.sets_overlap(i, j) {
96 pairs.push((i, j));
97 }
98 }
99 }
100 pairs
101 }
102
103 pub fn weights_ref(&self) -> &Vec<W> {
105 &self.weights
106 }
107}
108
109impl<W> Problem for SetPacking<W>
110where
111 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
112{
113 const NAME: &'static str = "SetPacking";
114 type GraphType = SimpleGraph;
115 type Weight = W;
116 type Size = W;
117
118 fn num_variables(&self) -> usize {
119 self.sets.len()
120 }
121
122 fn num_flavors(&self) -> usize {
123 2
124 }
125
126 fn problem_size(&self) -> ProblemSize {
127 ProblemSize::new(vec![("num_sets", self.sets.len())])
128 }
129
130 fn energy_mode(&self) -> EnergyMode {
131 EnergyMode::LargerSizeIsBetter }
133
134 fn solution_size(&self, config: &[usize]) -> SolutionSize<Self::Size> {
135 let is_valid = is_valid_packing(&self.sets, config);
136 let mut total = W::zero();
137 for (i, &selected) in config.iter().enumerate() {
138 if selected == 1 {
139 total += self.weights[i].clone();
140 }
141 }
142 SolutionSize::new(total, is_valid)
143 }
144}
145
146impl<W> ConstraintSatisfactionProblem for SetPacking<W>
147where
148 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
149{
150 fn constraints(&self) -> Vec<LocalConstraint> {
151 self.overlapping_pairs()
153 .into_iter()
154 .map(|(i, j)| {
155 LocalConstraint::new(
156 2,
157 vec![i, j],
158 vec![true, true, true, false], )
160 })
161 .collect()
162 }
163
164 fn objectives(&self) -> Vec<LocalSolutionSize<Self::Size>> {
165 self.weights
166 .iter()
167 .enumerate()
168 .map(|(i, w)| LocalSolutionSize::new(2, vec![i], vec![W::zero(), w.clone()]))
169 .collect()
170 }
171
172 fn weights(&self) -> Vec<Self::Size> {
173 self.weights.clone()
174 }
175
176 fn set_weights(&mut self, weights: Vec<Self::Size>) {
177 assert_eq!(weights.len(), self.num_variables());
178 self.weights = weights;
179 }
180
181 fn is_weighted(&self) -> bool {
182 if self.weights.is_empty() {
183 return false;
184 }
185 let first = &self.weights[0];
186 !self.weights.iter().all(|w| w == first)
187 }
188}
189
190fn is_valid_packing(sets: &[Vec<usize>], config: &[usize]) -> bool {
192 let selected_sets: Vec<_> = config
193 .iter()
194 .enumerate()
195 .filter(|(_, &s)| s == 1)
196 .map(|(i, _)| i)
197 .collect();
198
199 for i in 0..selected_sets.len() {
201 for j in (i + 1)..selected_sets.len() {
202 let set_i: HashSet<_> = sets[selected_sets[i]].iter().collect();
203 if sets[selected_sets[j]].iter().any(|e| set_i.contains(e)) {
204 return false;
205 }
206 }
207 }
208 true
209}
210
211pub fn is_set_packing(sets: &[Vec<usize>], selected: &[bool]) -> bool {
213 if selected.len() != sets.len() {
214 return false;
215 }
216
217 let config: Vec<usize> = selected.iter().map(|&b| if b { 1 } else { 0 }).collect();
218 is_valid_packing(sets, &config)
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224 use crate::solvers::{BruteForce, Solver};
225
226 #[test]
227 fn test_set_packing_creation() {
228 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![3, 4]]);
229 assert_eq!(problem.num_sets(), 3);
230 assert_eq!(problem.num_variables(), 3);
231 }
232
233 #[test]
234 fn test_set_packing_with_weights() {
235 let problem = SetPacking::with_weights(vec![vec![0, 1], vec![2, 3]], vec![5, 10]);
236 assert_eq!(problem.weights(), vec![5, 10]);
237 assert!(problem.is_weighted());
238 }
239
240 #[test]
241 fn test_sets_overlap() {
242 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![3, 4]]);
243
244 assert!(problem.sets_overlap(0, 1)); assert!(!problem.sets_overlap(0, 2)); assert!(!problem.sets_overlap(1, 2)); }
248
249 #[test]
250 fn test_overlapping_pairs() {
251 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![2, 3]]);
252
253 let pairs = problem.overlapping_pairs();
254 assert_eq!(pairs.len(), 2);
255 assert!(pairs.contains(&(0, 1)));
256 assert!(pairs.contains(&(1, 2)));
257 }
258
259 #[test]
260 fn test_solution_size_valid() {
261 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![2, 3], vec![4, 5]]);
262
263 let sol = problem.solution_size(&[1, 1, 1]);
265 assert!(sol.is_valid);
266 assert_eq!(sol.size, 3);
267
268 let sol = problem.solution_size(&[0, 0, 0]);
270 assert!(sol.is_valid);
271 assert_eq!(sol.size, 0);
272 }
273
274 #[test]
275 fn test_solution_size_invalid() {
276 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![3, 4]]);
277
278 let sol = problem.solution_size(&[1, 1, 0]);
280 assert!(!sol.is_valid);
281 }
282
283 #[test]
284 fn test_brute_force_chain() {
285 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![2, 3]]);
287 let solver = BruteForce::new();
288
289 let solutions = solver.find_best(&problem);
290 for sol in &solutions {
292 assert_eq!(sol.iter().sum::<usize>(), 2);
293 assert!(problem.solution_size(sol).is_valid);
294 }
295 }
296
297 #[test]
298 fn test_brute_force_weighted() {
299 let problem = SetPacking::with_weights(
301 vec![vec![0, 1, 2, 3], vec![0, 1], vec![2, 3]],
302 vec![5, 3, 3],
303 );
304 let solver = BruteForce::new();
305
306 let solutions = solver.find_best(&problem);
307 assert_eq!(solutions.len(), 1);
309 assert_eq!(solutions[0], vec![0, 1, 1]);
310 }
311
312 #[test]
313 fn test_is_set_packing_function() {
314 let sets = vec![vec![0, 1], vec![1, 2], vec![3, 4]];
315
316 assert!(is_set_packing(&sets, &[true, false, true])); assert!(is_set_packing(&sets, &[false, true, true])); assert!(!is_set_packing(&sets, &[true, true, false])); assert!(is_set_packing(&sets, &[false, false, false])); }
321
322 #[test]
323 fn test_constraints() {
324 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![3, 4]]);
325 let constraints = problem.constraints();
326 assert_eq!(constraints.len(), 1);
328 }
329
330 #[test]
331 fn test_energy_mode() {
332 let problem = SetPacking::<i32>::new(vec![vec![0, 1]]);
333 assert!(problem.energy_mode().is_maximization());
334 }
335
336 #[test]
337 fn test_disjoint_sets() {
338 let problem = SetPacking::<i32>::new(vec![vec![0], vec![1], vec![2], vec![3]]);
339 let solver = BruteForce::new();
340
341 let solutions = solver.find_best(&problem);
342 assert_eq!(solutions.len(), 1);
344 assert_eq!(solutions[0], vec![1, 1, 1, 1]);
345 }
346
347 #[test]
348 fn test_all_overlapping() {
349 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![0, 2], vec![0, 3]]);
351 let solver = BruteForce::new();
352
353 let solutions = solver.find_best(&problem);
354 for sol in &solutions {
356 assert_eq!(sol.iter().sum::<usize>(), 1);
357 }
358 }
359
360 #[test]
361 fn test_is_satisfied() {
362 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![3, 4]]);
363
364 assert!(problem.is_satisfied(&[1, 0, 1])); assert!(problem.is_satisfied(&[0, 1, 1])); assert!(!problem.is_satisfied(&[1, 1, 0])); }
368
369 #[test]
370 fn test_empty_sets() {
371 let problem = SetPacking::<i32>::new(vec![]);
372 let sol = problem.solution_size(&[]);
373 assert!(sol.is_valid);
374 assert_eq!(sol.size, 0);
375 }
376
377 #[test]
378 fn test_get_set() {
379 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![2, 3]]);
380 assert_eq!(problem.get_set(0), Some(&vec![0, 1]));
381 assert_eq!(problem.get_set(1), Some(&vec![2, 3]));
382 assert_eq!(problem.get_set(2), None);
383 }
384
385 #[test]
386 fn test_relationship_to_independent_set() {
387 use crate::models::graph::IndependentSet;
389
390 let sets = vec![vec![0, 1], vec![1, 2], vec![2, 3], vec![3, 4]];
391 let sp_problem = SetPacking::<i32>::new(sets.clone());
392
393 let edges = sp_problem.overlapping_pairs();
395 let is_problem = IndependentSet::<i32>::new(sets.len(), edges);
396
397 let solver = BruteForce::new();
398
399 let sp_solutions = solver.find_best(&sp_problem);
400 let is_solutions = solver.find_best(&is_problem);
401
402 let sp_size: usize = sp_solutions[0].iter().sum();
404 let is_size: usize = is_solutions[0].iter().sum();
405 assert_eq!(sp_size, is_size);
406 }
407
408 #[test]
409 fn test_objectives() {
410 let problem = SetPacking::with_weights(vec![vec![0, 1], vec![1, 2]], vec![5, 10]);
411 let objectives = problem.objectives();
412 assert_eq!(objectives.len(), 2);
413 }
414
415 #[test]
416 fn test_set_weights() {
417 let mut problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2]]);
418 assert!(!problem.is_weighted()); problem.set_weights(vec![1, 2]);
420 assert!(problem.is_weighted());
421 assert_eq!(problem.weights(), vec![1, 2]);
422 }
423
424 #[test]
425 fn test_is_weighted_empty() {
426 let problem = SetPacking::<i32>::new(vec![]);
427 assert!(!problem.is_weighted());
428 }
429
430 #[test]
431 fn test_is_set_packing_wrong_len() {
432 let sets = vec![vec![0, 1], vec![1, 2]];
433 assert!(!is_set_packing(&sets, &[true])); }
435
436 #[test]
437 fn test_problem_size() {
438 let problem = SetPacking::<i32>::new(vec![vec![0, 1], vec![1, 2], vec![3, 4]]);
439 let size = problem.problem_size();
440 assert_eq!(size.get("num_sets"), Some(3));
441 }
442}