problemreductions/models/set/
maximum_set_packing.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::traits::Problem;
8use crate::types::{Max, One, WeightElement};
9use num_traits::Zero;
10use serde::{Deserialize, Serialize};
11use std::collections::HashSet;
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MaximumSetPacking",
16 display_name: "Maximum Set Packing",
17 aliases: &[],
18 dimensions: &[VariantDimension::new("weight", "One", &["One", "i32", "f64"])],
19 module_path: module_path!(),
20 description: "Find maximum weight collection of disjoint sets",
21 fields: &[
22 FieldInfo { name: "sets", type_name: "Vec<Vec<usize>>", description: "Collection of sets over a universe" },
23 FieldInfo { name: "weights", type_name: "Vec<W>", description: "Weight for each set" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct MaximumSetPacking<W = i32> {
58 sets: Vec<Vec<usize>>,
60 weights: Vec<W>,
62}
63
64impl<W: Clone + Default> MaximumSetPacking<W> {
65 pub fn new(sets: Vec<Vec<usize>>) -> Self
67 where
68 W: From<i32>,
69 {
70 let num_sets = sets.len();
71 let weights = vec![W::from(1); num_sets];
72 Self { sets, weights }
73 }
74
75 pub fn with_weights(sets: Vec<Vec<usize>>, weights: Vec<W>) -> Self {
77 assert_eq!(sets.len(), weights.len());
78 Self { sets, weights }
79 }
80
81 pub fn num_sets(&self) -> usize {
83 self.sets.len()
84 }
85
86 pub fn sets(&self) -> &[Vec<usize>] {
88 &self.sets
89 }
90
91 pub fn get_set(&self, index: usize) -> Option<&Vec<usize>> {
93 self.sets.get(index)
94 }
95
96 pub fn sets_overlap(&self, i: usize, j: usize) -> bool {
98 if let (Some(set_i), Some(set_j)) = (self.sets.get(i), self.sets.get(j)) {
99 let set_i: HashSet<_> = set_i.iter().collect();
100 set_j.iter().any(|e| set_i.contains(e))
101 } else {
102 false
103 }
104 }
105
106 pub fn overlapping_pairs(&self) -> Vec<(usize, usize)> {
108 let mut pairs = Vec::new();
109 for i in 0..self.sets.len() {
110 for j in (i + 1)..self.sets.len() {
111 if self.sets_overlap(i, j) {
112 pairs.push((i, j));
113 }
114 }
115 }
116 pairs
117 }
118
119 pub fn universe_size(&self) -> usize {
121 self.sets()
122 .iter()
123 .flat_map(|s| s.iter())
124 .max()
125 .map_or(0, |&m| m + 1)
126 }
127
128 pub fn weights_ref(&self) -> &Vec<W> {
130 &self.weights
131 }
132
133 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
135 is_valid_packing(&self.sets, config)
136 }
137}
138
139impl<W> Problem for MaximumSetPacking<W>
140where
141 W: WeightElement + crate::variant::VariantParam,
142{
143 const NAME: &'static str = "MaximumSetPacking";
144 type Value = Max<W::Sum>;
145
146 fn dims(&self) -> Vec<usize> {
147 vec![2; self.sets.len()]
148 }
149
150 fn evaluate(&self, config: &[usize]) -> Max<W::Sum> {
151 if !is_valid_packing(&self.sets, config) {
152 return Max(None);
153 }
154 let mut total = W::Sum::zero();
155 for (i, &selected) in config.iter().enumerate() {
156 if selected == 1 {
157 total += self.weights[i].to_sum();
158 }
159 }
160 Max(Some(total))
161 }
162
163 fn variant() -> Vec<(&'static str, &'static str)> {
164 crate::variant_params![W]
165 }
166}
167
168crate::declare_variants! {
169 default MaximumSetPacking<One> => "2^num_sets",
170 MaximumSetPacking<i32> => "2^num_sets",
171 MaximumSetPacking<f64> => "2^num_sets",
172}
173
174fn is_valid_packing(sets: &[Vec<usize>], config: &[usize]) -> bool {
176 let selected_sets: Vec<_> = config
177 .iter()
178 .enumerate()
179 .filter(|(_, &s)| s == 1)
180 .map(|(i, _)| i)
181 .collect();
182
183 for i in 0..selected_sets.len() {
185 for j in (i + 1)..selected_sets.len() {
186 let set_i: HashSet<_> = sets[selected_sets[i]].iter().collect();
187 if sets[selected_sets[j]].iter().any(|e| set_i.contains(e)) {
188 return false;
189 }
190 }
191 }
192 true
193}
194
195#[cfg(test)]
197pub(crate) fn is_set_packing(sets: &[Vec<usize>], selected: &[bool]) -> bool {
198 if selected.len() != sets.len() {
199 return false;
200 }
201
202 let config: Vec<usize> = selected.iter().map(|&b| if b { 1 } else { 0 }).collect();
203 is_valid_packing(sets, &config)
204}
205
206#[cfg(feature = "example-db")]
207pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
208 vec![crate::example_db::specs::ModelExampleSpec {
209 id: "maximum_set_packing_i32",
210 instance: Box::new(MaximumSetPacking::<i32>::new(vec![
211 vec![0, 1],
212 vec![1, 2],
213 vec![2, 3],
214 vec![3, 4],
215 ])),
216 optimal_config: vec![0, 1, 0, 1],
217 optimal_value: serde_json::json!(2),
218 }]
219}
220
221#[cfg(test)]
222#[path = "../../unit_tests/models/set/maximum_set_packing.rs"]
223mod tests;