1use crate::registry::{
7 ConstructionError, CreateSpec, FieldInfo, ProblemSchemaEntry, VariantDimension,
8};
9use crate::topology::{Graph, KingsSubgraph, SimpleGraph, TriangularSubgraph, UnitDiskGraph};
10use crate::traits::Problem;
11use crate::types::{Max, One, WeightElement};
12use num_traits::Zero;
13use serde::{Deserialize, Serialize};
14
15inventory::submit! {
16 ProblemSchemaEntry {
17 name: "MaximumIndependentSet",
18 display_name: "Maximum Independent Set",
19 aliases: &["MIS"],
20 dimensions: &[
21 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph", "KingsSubgraph", "TriangularSubgraph", "UnitDiskGraph"]),
22 VariantDimension::new("weight", "One", &["One", "i64", "f64"]),
23 ],
24 category: crate::registry::ProblemCategory::Graph,
25 module_path: module_path!(),
26 description: "Find maximum weight independent set in a graph",
27 fields: MaximumIndependentSetSimpleI64CreateSpec::FIELDS,
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(try_from = "MaximumIndependentSetData<G, W>")]
63#[serde(bound(deserialize = "G: Graph + Deserialize<'de>, W: Clone + Default + Deserialize<'de>"))]
64pub struct MaximumIndependentSet<G, W> {
65 graph: G,
67 weights: Vec<W>,
69}
70
71#[derive(Deserialize)]
72struct MaximumIndependentSetData<G, W> {
73 graph: G,
74 weights: Vec<W>,
75}
76
77impl<G, W> TryFrom<MaximumIndependentSetData<G, W>> for MaximumIndependentSet<G, W>
78where
79 G: Graph,
80 W: Clone + Default,
81{
82 type Error = crate::registry::ConstructionError;
83
84 fn try_from(data: MaximumIndependentSetData<G, W>) -> Result<Self, Self::Error> {
85 Self::try_new(data.graph, data.weights)
86 }
87}
88
89macro_rules! simple_mis_spec {
90 ($name:ident,$weight:ty,$one:expr $(, $weights:ident)?) => {
91 #[derive(Debug, Deserialize, crate::CreateSpec)]
92 struct $name {
93 #[create(codec = "edge-list")]
94 graph: Vec<(usize, usize)>,
95 num_vertices: Option<usize>,
96 $(
97 #[create(codec = "comma-separated")]
98 $weights: Option<Vec<$weight>>,
99 )?
100 }
101 impl TryFrom<$name> for MaximumIndependentSet<SimpleGraph, $weight> {
102 type Error = crate::registry::ConstructionError;
103 fn try_from(spec: $name) -> Result<Self, crate::registry::ConstructionError> {
104 if spec.graph.is_empty() && spec.num_vertices.is_none() {
105 return Err("num_vertices is required for an empty graph".into());
106 }
107 for &(u, v) in &spec.graph {
108 if u == v {
109 return Err("self-loops are not allowed".into());
110 }
111 }
112 let inferred = spec
113 .graph
114 .iter()
115 .flat_map(|&(u, v)| [u, v])
116 .max()
117 .map(|v| v.checked_add(1).ok_or("vertex count overflows usize"))
118 .transpose()?
119 .unwrap_or(0);
120 let count = spec.num_vertices.unwrap_or(inferred);
121 if count < inferred {
122 return Err("num_vertices is too small".into());
123 }
124 let weights = { $(if let Some(value) = spec.$weights { value } else)? { vec![$one; count] } };
125 Self::try_new(SimpleGraph::new(count, spec.graph), weights)
126 }
127 }
128 };
129}
130simple_mis_spec!(MaximumIndependentSetSimpleOneCreateSpec, One, One);
131simple_mis_spec!(
132 MaximumIndependentSetSimpleI64CreateSpec,
133 i64,
134 1_i64,
135 weights
136);
137simple_mis_spec!(
138 MaximumIndependentSetSimpleF64CreateSpec,
139 f64,
140 1_f64,
141 weights
142);
143
144macro_rules! grid_mis_spec {
145 ($name:ident,$graph:ty,$weight:ty,$one:expr $(, $weights:ident)?) => {
146 #[derive(Debug, Deserialize, crate::CreateSpec)]
147 struct $name {
148 positions: Vec<(i64, i64)>,
149 $(
150 #[create(codec = "comma-separated")]
151 $weights: Option<Vec<$weight>>,
152 )?
153 }
154 impl TryFrom<$name> for MaximumIndependentSet<$graph, $weight> {
155 type Error = crate::registry::ConstructionError;
156 fn try_from(spec: $name) -> Result<Self, crate::registry::ConstructionError> {
157 let weights = { $(if let Some(value) = spec.$weights { value } else)? { vec![$one; spec.positions.len()] } };
158 Self::try_new(<$graph>::new(spec.positions), weights)
159 }
160 }
161 };
162}
163grid_mis_spec!(
164 MaximumIndependentSetKingsOneCreateSpec,
165 KingsSubgraph,
166 One,
167 One
168);
169grid_mis_spec!(
170 MaximumIndependentSetKingsI64CreateSpec,
171 KingsSubgraph,
172 i64,
173 1_i64,
174 weights
175);
176grid_mis_spec!(
177 MaximumIndependentSetTriangularI64CreateSpec,
178 TriangularSubgraph,
179 i64,
180 1_i64,
181 weights
182);
183
184macro_rules! unit_disk_mis_spec {
185 ($name:ident,$weight:ty,$one:expr $(, $weights:ident)?) => {
186 #[derive(Debug, Deserialize, crate::CreateSpec)]
187 struct $name {
188 positions: Vec<(f64, f64)>,
189 radius: Option<f64>,
190 $(
191 #[create(codec = "comma-separated")]
192 $weights: Option<Vec<$weight>>,
193 )?
194 }
195 impl TryFrom<$name> for MaximumIndependentSet<UnitDiskGraph, $weight> {
196 type Error = ConstructionError;
197 fn try_from(spec: $name) -> Result<Self, ConstructionError> {
198 let radius = spec.radius.unwrap_or(1.0);
199 let weights = { $(if let Some(value) = spec.$weights { value } else)? { vec![$one; spec.positions.len()] } };
200 Self::try_new(UnitDiskGraph::new(spec.positions, radius)?, weights)
201 }
202 }
203 };
204}
205unit_disk_mis_spec!(MaximumIndependentSetUnitDiskOneCreateSpec, One, One);
206unit_disk_mis_spec!(
207 MaximumIndependentSetUnitDiskI64CreateSpec,
208 i64,
209 1_i64,
210 weights
211);
212
213impl<G: Graph, W: Clone + Default> MaximumIndependentSet<G, W> {
214 pub fn new(graph: G, weights: Vec<W>) -> Self {
216 Self::try_new(graph, weights).unwrap_or_else(|error| panic!("{error}"))
217 }
218
219 fn try_new(graph: G, weights: Vec<W>) -> Result<Self, crate::registry::ConstructionError> {
220 if weights.len() != graph.num_vertices() {
221 return Err(crate::registry::ConstructionError::length_mismatch(
222 "weights",
223 weights.len(),
224 graph.num_vertices(),
225 ));
226 }
227 Ok(Self { graph, weights })
228 }
229
230 pub fn graph(&self) -> &G {
232 &self.graph
233 }
234
235 pub fn weights(&self) -> &[W] {
237 &self.weights
238 }
239
240 pub fn is_weighted(&self) -> bool
242 where
243 W: WeightElement,
244 {
245 !W::IS_UNIT
246 }
247
248 pub fn is_valid_solution(&self, config: &[bool]) -> bool {
250 is_independent_set_config(&self.graph, config)
251 }
252}
253
254impl<G: Graph, W: WeightElement> MaximumIndependentSet<G, W> {
255 pub fn num_vertices(&self) -> usize {
257 self.graph().num_vertices()
258 }
259
260 pub fn num_edges(&self) -> usize {
262 self.graph().num_edges()
263 }
264}
265
266impl<G, W> Problem for MaximumIndependentSet<G, W>
267where
268 G: Graph + crate::variant::VariantParam,
269 W: WeightElement + crate::variant::VariantParam,
270{
271 const NAME: &'static str = "MaximumIndependentSet";
272 type Solution = Vec<bool>;
273 type Value = Max<W::Sum>;
274
275 crate::problem_parameters![("num_edges", num_edges), ("num_vertices", num_vertices),];
276
277 fn variant() -> Vec<(&'static str, &'static str)> {
278 crate::variant_params![G, W]
279 }
280
281 fn evaluate(
282 &self,
283 solution: &Self::Solution,
284 ) -> Result<Max<W::Sum>, crate::traits::EvaluationError> {
285 Ok({
286 if solution.len() != self.graph.num_vertices() {
287 return Err(crate::traits::EvaluationError::InvalidConfiguration(
288 format!(
289 "solution has {} variables, expected {}",
290 solution.len(),
291 self.graph.num_vertices()
292 ),
293 ));
294 }
295 if !is_independent_set_config(&self.graph, solution) {
296 return Ok(Max(None));
297 }
298 let mut total = W::Sum::zero();
299 for (i, &selected) in solution.iter().enumerate() {
300 if selected {
301 total = W::checked_add_to_sum(
302 total,
303 self.weights[i].to_sum(),
304 "summing selected independent-set weights",
305 )?;
306 }
307 }
308 Max(Some(total))
309 })
310 }
311}
312
313impl<G, W> crate::solvers::BruteForceProblem for MaximumIndependentSet<G, W>
314where
315 G: Graph + crate::variant::VariantParam,
316 W: WeightElement + crate::variant::VariantParam,
317{
318 fn dimensions(&self) -> Vec<usize> {
319 vec![2; self.graph.num_vertices()]
320 }
321}
322
323fn is_independent_set_config<G: Graph>(graph: &G, config: &[bool]) -> bool {
325 for (u, v) in graph.edges() {
326 if config.get(u).copied().unwrap_or(false) && config.get(v).copied().unwrap_or(false) {
327 return false;
328 }
329 }
330 true
331}
332
333crate::impl_random_generate!(MaximumIndependentSet<SimpleGraph, i64>, crate::random::SimpleGraphRandomSpec, |spec| {
334 Ok(MaximumIndependentSet::new(spec.graph()?, vec![1; spec.num_vertices]))
335});
336crate::impl_random_generate!(MaximumIndependentSet<SimpleGraph, One>, crate::random::SimpleGraphRandomSpec, |spec| {
337 Ok(MaximumIndependentSet::new(spec.graph()?, vec![One; spec.num_vertices]))
338});
339crate::impl_random_generate!(MaximumIndependentSet<KingsSubgraph, i64>, crate::random::IntegerGeometryRandomSpec, |spec| {
340 let seed = crate::random::seed_to_u64(spec.seed)?;
341 Ok(MaximumIndependentSet::new(KingsSubgraph::new(crate::random::create_random_int_positions(spec.num_vertices, seed)), vec![1; spec.num_vertices]))
342});
343crate::impl_random_generate!(MaximumIndependentSet<KingsSubgraph, One>, crate::random::IntegerGeometryRandomSpec, |spec| {
344 let seed = crate::random::seed_to_u64(spec.seed)?;
345 Ok(MaximumIndependentSet::new(KingsSubgraph::new(crate::random::create_random_int_positions(spec.num_vertices, seed)), vec![One; spec.num_vertices]))
346});
347crate::impl_random_generate!(MaximumIndependentSet<TriangularSubgraph, i64>, crate::random::IntegerGeometryRandomSpec, |spec| {
348 let seed = crate::random::seed_to_u64(spec.seed)?;
349 Ok(MaximumIndependentSet::new(TriangularSubgraph::new(crate::random::create_random_int_positions(spec.num_vertices, seed)), vec![1; spec.num_vertices]))
350});
351crate::impl_random_generate!(MaximumIndependentSet<UnitDiskGraph, i64>, crate::random::UnitDiskRandomSpec, |spec| {
352 let seed = crate::random::seed_to_u64(spec.seed)?;
353 Ok(MaximumIndependentSet::new(UnitDiskGraph::new(crate::random::create_random_float_positions(spec.num_vertices, seed), spec.radius.unwrap_or(1.0))?, vec![1; spec.num_vertices]))
354});
355crate::impl_random_generate!(MaximumIndependentSet<UnitDiskGraph, One>, crate::random::UnitDiskRandomSpec, |spec| {
356 let seed = crate::random::seed_to_u64(spec.seed)?;
357 Ok(MaximumIndependentSet::new(UnitDiskGraph::new(crate::random::create_random_float_positions(spec.num_vertices, seed), spec.radius.unwrap_or(1.0))?, vec![One; spec.num_vertices]))
358});
359
360crate::declare_variants! {
361 MaximumIndependentSet<SimpleGraph, i64> => "1.1996^num_vertices" create MaximumIndependentSetSimpleI64CreateSpec random,
362 default MaximumIndependentSet<SimpleGraph, One> => "1.1996^num_vertices" create MaximumIndependentSetSimpleOneCreateSpec random,
363 MaximumIndependentSet<KingsSubgraph, i64> => "2^sqrt(num_vertices)" create MaximumIndependentSetKingsI64CreateSpec random,
364 MaximumIndependentSet<KingsSubgraph, One> => "2^sqrt(num_vertices)" create MaximumIndependentSetKingsOneCreateSpec random,
365 MaximumIndependentSet<TriangularSubgraph, i64> => "2^sqrt(num_vertices)" create MaximumIndependentSetTriangularI64CreateSpec random,
366 MaximumIndependentSet<UnitDiskGraph, i64> => "2^sqrt(num_vertices)" create MaximumIndependentSetUnitDiskI64CreateSpec random,
367 MaximumIndependentSet<UnitDiskGraph, One> => "2^sqrt(num_vertices)" create MaximumIndependentSetUnitDiskOneCreateSpec random,
368 MaximumIndependentSet<SimpleGraph, f64> => "2^num_vertices" create MaximumIndependentSetSimpleF64CreateSpec,
369}
370
371crate::register_brute_force! {
372 MaximumIndependentSet<SimpleGraph, i64> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
373 MaximumIndependentSet<SimpleGraph, One> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
374 MaximumIndependentSet<KingsSubgraph, i64> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
375 MaximumIndependentSet<KingsSubgraph, One> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
376 MaximumIndependentSet<TriangularSubgraph, i64> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
377 MaximumIndependentSet<UnitDiskGraph, i64> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
378 MaximumIndependentSet<UnitDiskGraph, One> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
379 MaximumIndependentSet<SimpleGraph, f64> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
380}
381
382impl<G, W> crate::models::decision::DecisionProblemMeta for MaximumIndependentSet<G, W>
383where
384 G: Graph + crate::variant::VariantParam,
385 W: WeightElement + crate::variant::VariantParam,
386 W::Sum: std::fmt::Debug + serde::Serialize + serde::de::DeserializeOwned,
387{
388 const DECISION_NAME: &'static str = "DecisionMaximumIndependentSet";
389}
390
391impl<W> crate::models::decision::Decision<MaximumIndependentSet<SimpleGraph, W>>
392where
393 W: WeightElement + crate::variant::VariantParam,
394 W::Sum: std::fmt::Debug + serde::Serialize + serde::de::DeserializeOwned,
395{
396 pub fn num_vertices(&self) -> usize {
397 self.inner().num_vertices()
398 }
399
400 pub fn num_edges(&self) -> usize {
401 self.inner().num_edges()
402 }
403}
404
405crate::register_decision_variant!(
406 MaximumIndependentSet<SimpleGraph, i64>,
407 "DecisionMaximumIndependentSet",
408 "1.1996^num_vertices",
409 &["DMIS", "IndependentSet"],
410 "Decision version: does an independent set of weight at least the bound exist?",
411 category: crate::registry::ProblemCategory::Graph,
412 dims: [
413 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
414 VariantDimension::new("weight", "i64", &["i64", "One"]),
415 ],
416 fields: [
417 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
418 FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
419 FieldInfo { name: "bound", type_name: "W::Sum", description: "Decision bound (minimum required independent-set weight)" },
420 ],
421 additional: [MaximumIndependentSet<SimpleGraph, One> => "1.1996^num_vertices"],
422 decode: |_, indices: Vec<usize>| crate::config::config_to_bits(&indices)
423);
424
425#[cfg(feature = "example-db")]
426pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
427 vec![
428 crate::example_db::specs::ModelExampleSpec {
429 id: "maximum_independent_set_petersen_graph",
430 instance: Box::new(MaximumIndependentSet::new(
431 SimpleGraph::new(
432 10,
433 vec![
434 (0, 1),
435 (1, 2),
436 (2, 3),
437 (3, 4),
438 (4, 0),
439 (5, 7),
440 (7, 9),
441 (9, 6),
442 (6, 8),
443 (8, 5),
444 (0, 5),
445 (1, 6),
446 (2, 7),
447 (3, 8),
448 (4, 9),
449 ],
450 ),
451 vec![One; 10],
452 )),
453 optimal_config: serde_json::json!(vec![
454 true, false, true, false, false, false, false, false, true, true
455 ]),
456 optimal_value: serde_json::json!(4),
457 },
458 crate::example_db::specs::ModelExampleSpec {
459 id: "maximum_independent_set_simplegraph",
460 instance: Box::new(MaximumIndependentSet::new(
461 SimpleGraph::new(
462 10,
463 vec![
464 (0, 1),
465 (1, 2),
466 (2, 3),
467 (3, 4),
468 (4, 0),
469 (5, 7),
470 (7, 9),
471 (9, 6),
472 (6, 8),
473 (8, 5),
474 (0, 5),
475 (1, 6),
476 (2, 7),
477 (3, 8),
478 (4, 9),
479 ],
480 ),
481 vec![5, 1, 1, 1, 1, 3, 1, 1, 1, 3],
482 )),
483 optimal_config: serde_json::json!(vec![
484 true, false, true, false, false, false, false, false, true, true
485 ]),
486 optimal_value: serde_json::json!(10),
487 },
488 ]
489}
490
491#[cfg(feature = "example-db")]
492pub(crate) fn decision_canonical_model_example_specs(
493) -> Vec<crate::example_db::specs::ModelExampleSpec> {
494 vec![
495 crate::example_db::specs::ModelExampleSpec {
496 id: "decision_maximum_independent_set_simplegraph",
497 instance: Box::new(crate::models::decision::Decision::new(
498 MaximumIndependentSet::new(SimpleGraph::path(4), vec![1i64; 4]),
499 2,
500 )),
501 optimal_config: serde_json::json!(vec![true, false, true, false]),
502 optimal_value: serde_json::json!(true),
503 },
504 crate::example_db::specs::ModelExampleSpec {
505 id: "decision_maximum_independent_set_unit",
506 instance: Box::new(crate::models::decision::Decision::new(
507 MaximumIndependentSet::new(SimpleGraph::path(3), vec![One; 3]),
508 2,
509 )),
510 optimal_config: serde_json::json!(vec![true, false, true]),
511 optimal_value: serde_json::json!(true),
512 },
513 ]
514}
515
516#[cfg(feature = "example-db")]
517pub(crate) fn decision_canonical_rule_example_specs(
518) -> Vec<crate::example_db::specs::RuleExampleSpec> {
519 use crate::example_db::specs::{rule_example_with_witness, RuleExampleSpec};
520 use crate::export::SolutionPair;
521 use crate::models::decision::Decision;
522 vec![
523 RuleExampleSpec {
524 id: "decision_maximum_independent_set_to_maximum_independent_set",
525 build: || {
526 let source = Decision::new(
527 MaximumIndependentSet::new(SimpleGraph::path(4), vec![1i64; 4]),
528 2,
529 );
530 rule_example_with_witness::<_, MaximumIndependentSet<SimpleGraph, i64>>(
531 source,
532 SolutionPair {
533 source_config: serde_json::json!([true, false, true, false]),
534 target_config: serde_json::json!([true, false, true, false]),
535 },
536 )
537 },
538 },
539 RuleExampleSpec {
540 id: "decision_maximum_independent_set_unit_to_maximum_independent_set",
541 build: || {
542 let source = Decision::new(
543 MaximumIndependentSet::new(SimpleGraph::path(3), vec![One; 3]),
544 2,
545 );
546 rule_example_with_witness::<_, MaximumIndependentSet<SimpleGraph, One>>(
547 source,
548 SolutionPair {
549 source_config: serde_json::json!([true, false, true]),
550 target_config: serde_json::json!([true, false, true]),
551 },
552 )
553 },
554 },
555 ]
556}
557
558#[cfg(test)]
567pub(crate) fn is_independent_set<G: Graph>(graph: &G, selected: &[bool]) -> bool {
568 assert_eq!(
569 selected.len(),
570 graph.num_vertices(),
571 "selected length must match num_vertices"
572 );
573 for (u, v) in graph.edges() {
574 if selected[u] && selected[v] {
575 return false;
576 }
577 }
578 true
579}
580
581#[cfg(test)]
582#[path = "../../unit_tests/models/graph/maximum_independent_set.rs"]
583mod tests;