1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, KingsSubgraph, SimpleGraph, TriangularSubgraph, UnitDiskGraph};
8use crate::traits::Problem;
9use crate::types::{Max, One, WeightElement};
10use num_traits::Zero;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MaximumIndependentSet",
16 display_name: "Maximum Independent Set",
17 aliases: &["MIS"],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph", "KingsSubgraph", "TriangularSubgraph", "UnitDiskGraph"]),
20 VariantDimension::new("weight", "One", &["One", "i32"]),
21 ],
22 module_path: module_path!(),
23 description: "Find maximum weight independent set in a graph",
24 fields: &[
25 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
26 FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
27 ],
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct MaximumIndependentSet<G, W> {
63 graph: G,
65 weights: Vec<W>,
67}
68
69impl<G: Graph, W: Clone + Default> MaximumIndependentSet<G, W> {
70 pub fn new(graph: G, weights: Vec<W>) -> Self {
72 assert_eq!(
73 weights.len(),
74 graph.num_vertices(),
75 "weights length must match graph num_vertices"
76 );
77 Self { graph, weights }
78 }
79
80 pub fn graph(&self) -> &G {
82 &self.graph
83 }
84
85 pub fn weights(&self) -> &[W] {
87 &self.weights
88 }
89
90 pub fn is_weighted(&self) -> bool
92 where
93 W: WeightElement,
94 {
95 !W::IS_UNIT
96 }
97
98 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
100 is_independent_set_config(&self.graph, config)
101 }
102}
103
104impl<G: Graph, W: WeightElement> MaximumIndependentSet<G, W> {
105 pub fn num_vertices(&self) -> usize {
107 self.graph().num_vertices()
108 }
109
110 pub fn num_edges(&self) -> usize {
112 self.graph().num_edges()
113 }
114}
115
116impl<G, W> Problem for MaximumIndependentSet<G, W>
117where
118 G: Graph + crate::variant::VariantParam,
119 W: WeightElement + crate::variant::VariantParam,
120{
121 const NAME: &'static str = "MaximumIndependentSet";
122 type Value = Max<W::Sum>;
123
124 fn variant() -> Vec<(&'static str, &'static str)> {
125 crate::variant_params![G, W]
126 }
127
128 fn dims(&self) -> Vec<usize> {
129 vec![2; self.graph.num_vertices()]
130 }
131
132 fn evaluate(&self, config: &[usize]) -> Max<W::Sum> {
133 if !is_independent_set_config(&self.graph, config) {
134 return Max(None);
135 }
136 let mut total = W::Sum::zero();
137 for (i, &selected) in config.iter().enumerate() {
138 if selected == 1 {
139 total += self.weights[i].to_sum();
140 }
141 }
142 Max(Some(total))
143 }
144}
145
146fn is_independent_set_config<G: Graph>(graph: &G, config: &[usize]) -> bool {
148 for (u, v) in graph.edges() {
149 if config.get(u).copied().unwrap_or(0) == 1 && config.get(v).copied().unwrap_or(0) == 1 {
150 return false;
151 }
152 }
153 true
154}
155
156crate::declare_variants! {
157 MaximumIndependentSet<SimpleGraph, i32> => "1.1996^num_vertices",
158 default MaximumIndependentSet<SimpleGraph, One> => "1.1996^num_vertices",
159 MaximumIndependentSet<KingsSubgraph, i32> => "2^sqrt(num_vertices)",
160 MaximumIndependentSet<KingsSubgraph, One> => "2^sqrt(num_vertices)",
161 MaximumIndependentSet<TriangularSubgraph, i32> => "2^sqrt(num_vertices)",
162 MaximumIndependentSet<UnitDiskGraph, i32> => "2^sqrt(num_vertices)",
163 MaximumIndependentSet<UnitDiskGraph, One> => "2^sqrt(num_vertices)",
164}
165
166impl<G, W> crate::models::decision::DecisionProblemMeta for MaximumIndependentSet<G, W>
167where
168 G: Graph + crate::variant::VariantParam,
169 W: WeightElement + crate::variant::VariantParam,
170 W::Sum: std::fmt::Debug + serde::Serialize + serde::de::DeserializeOwned,
171{
172 const DECISION_NAME: &'static str = "DecisionMaximumIndependentSet";
173}
174
175#[cfg(feature = "example-db")]
176pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
177 vec![
178 crate::example_db::specs::ModelExampleSpec {
179 id: "maximum_independent_set_simplegraph_one",
180 instance: Box::new(MaximumIndependentSet::new(
181 SimpleGraph::new(
182 10,
183 vec![
184 (0, 1),
185 (1, 2),
186 (2, 3),
187 (3, 4),
188 (4, 0),
189 (5, 7),
190 (7, 9),
191 (9, 6),
192 (6, 8),
193 (8, 5),
194 (0, 5),
195 (1, 6),
196 (2, 7),
197 (3, 8),
198 (4, 9),
199 ],
200 ),
201 vec![One; 10],
202 )),
203 optimal_config: vec![1, 0, 1, 0, 0, 0, 0, 0, 1, 1],
204 optimal_value: serde_json::json!(4),
205 },
206 crate::example_db::specs::ModelExampleSpec {
207 id: "maximum_independent_set_simplegraph_i32",
208 instance: Box::new(MaximumIndependentSet::new(
209 SimpleGraph::new(
210 10,
211 vec![
212 (0, 1),
213 (1, 2),
214 (2, 3),
215 (3, 4),
216 (4, 0),
217 (5, 7),
218 (7, 9),
219 (9, 6),
220 (6, 8),
221 (8, 5),
222 (0, 5),
223 (1, 6),
224 (2, 7),
225 (3, 8),
226 (4, 9),
227 ],
228 ),
229 vec![5, 1, 1, 1, 1, 3, 1, 1, 1, 3],
230 )),
231 optimal_config: vec![1, 0, 1, 0, 0, 0, 0, 0, 1, 1],
232 optimal_value: serde_json::json!(10),
233 },
234 ]
235}
236
237#[cfg(test)]
246pub(crate) fn is_independent_set<G: Graph>(graph: &G, selected: &[bool]) -> bool {
247 assert_eq!(
248 selected.len(),
249 graph.num_vertices(),
250 "selected length must match num_vertices"
251 );
252 for (u, v) in graph.edges() {
253 if selected[u] && selected[v] {
254 return false;
255 }
256 }
257 true
258}
259
260#[cfg(test)]
261#[path = "../../unit_tests/models/graph/maximum_independent_set.rs"]
262mod tests;