problemreductions/models/set/
three_matroid_intersection.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
7use crate::traits::Problem;
8use serde::{Deserialize, Serialize};
9
10inventory::submit! {
11 ProblemSchemaEntry {
12 name: "ThreeMatroidIntersection",
13 display_name: "Three-Matroid Intersection",
14 aliases: &[],
15 dimensions: &[],
16 module_path: module_path!(),
17 description: "Find a common independent set of size K in three partition matroids",
18 fields: &[
19 FieldInfo { name: "ground_set_size", type_name: "usize", description: "Number of elements in the ground set E" },
20 FieldInfo { name: "partitions", type_name: "Vec<Vec<Vec<usize>>>", description: "Three partition matroids, each as a list of groups" },
21 FieldInfo { name: "bound", type_name: "usize", description: "Required size K of the common independent set" },
22 ],
23 }
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct ThreeMatroidIntersection {
61 ground_set_size: usize,
63 partitions: Vec<Vec<Vec<usize>>>,
67 bound: usize,
69}
70
71impl ThreeMatroidIntersection {
72 pub fn new(ground_set_size: usize, partitions: Vec<Vec<Vec<usize>>>, bound: usize) -> Self {
81 assert_eq!(
82 partitions.len(),
83 3,
84 "Expected exactly 3 partition matroids, got {}",
85 partitions.len()
86 );
87 assert!(
88 bound <= ground_set_size,
89 "Bound {} exceeds ground set size {}",
90 bound,
91 ground_set_size
92 );
93 for (m_idx, matroid) in partitions.iter().enumerate() {
94 for (g_idx, group) in matroid.iter().enumerate() {
95 for &elem in group {
96 assert!(
97 elem < ground_set_size,
98 "Matroid {} group {} contains element {} which is outside 0..{}",
99 m_idx,
100 g_idx,
101 elem,
102 ground_set_size
103 );
104 }
105 }
106 }
107 Self {
108 ground_set_size,
109 partitions,
110 bound,
111 }
112 }
113
114 pub fn ground_set_size(&self) -> usize {
116 self.ground_set_size
117 }
118
119 pub fn partitions(&self) -> &[Vec<Vec<usize>>] {
121 &self.partitions
122 }
123
124 pub fn bound(&self) -> usize {
126 self.bound
127 }
128
129 pub fn num_groups(&self) -> usize {
131 self.partitions.iter().map(|m| m.len()).sum()
132 }
133}
134
135impl Problem for ThreeMatroidIntersection {
136 const NAME: &'static str = "ThreeMatroidIntersection";
137 type Value = crate::types::Or;
138
139 fn dims(&self) -> Vec<usize> {
140 vec![2; self.ground_set_size]
141 }
142
143 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
144 crate::types::Or({
145 if config.len() != self.ground_set_size || config.iter().any(|&v| v > 1) {
146 return crate::types::Or(false);
147 }
148
149 let selected_count: usize = config.iter().filter(|&&v| v == 1).sum();
151 if selected_count != self.bound {
152 return crate::types::Or(false);
153 }
154
155 for matroid in &self.partitions {
157 for group in matroid {
158 let count = group.iter().filter(|&&e| config[e] == 1).count();
159 if count > 1 {
160 return crate::types::Or(false);
161 }
162 }
163 }
164
165 true
166 })
167 }
168
169 fn variant() -> Vec<(&'static str, &'static str)> {
170 crate::variant_params![]
171 }
172}
173
174crate::declare_variants! {
175 default ThreeMatroidIntersection => "2^ground_set_size",
176}
177
178#[cfg(feature = "example-db")]
179pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
180 vec![crate::example_db::specs::ModelExampleSpec {
181 id: "three_matroid_intersection",
182 instance: Box::new(ThreeMatroidIntersection::new(
183 6,
184 vec![
185 vec![vec![0, 1, 2], vec![3, 4, 5]],
186 vec![vec![0, 3], vec![1, 4], vec![2, 5]],
187 vec![vec![0, 4], vec![1, 5], vec![2, 3]],
188 ],
189 2,
190 )),
191 optimal_config: vec![1, 0, 0, 0, 0, 1],
192 optimal_value: serde_json::json!(true),
193 }]
194}
195
196#[cfg(test)]
197#[path = "../../unit_tests/models/set/three_matroid_intersection.rs"]
198mod tests;