problemreductions/models/graph/
maximum_independent_set.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
7use crate::topology::{Graph, KingsSubgraph, SimpleGraph, TriangularSubgraph, UnitDiskGraph};
8use crate::traits::{OptimizationProblem, Problem};
9use crate::types::{Direction, One, SolutionSize, WeightElement};
10use num_traits::Zero;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MaximumIndependentSet",
16 module_path: module_path!(),
17 description: "Find maximum weight independent set in a graph",
18 fields: &[
19 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
20 FieldInfo { name: "weights", type_name: "Vec<W>", description: "Vertex weights w: V -> R" },
21 ],
22 }
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct MaximumIndependentSet<G, W> {
57 graph: G,
59 weights: Vec<W>,
61}
62
63impl<G: Graph, W: Clone + Default> MaximumIndependentSet<G, W> {
64 pub fn new(graph: G, weights: Vec<W>) -> Self {
66 assert_eq!(
67 weights.len(),
68 graph.num_vertices(),
69 "weights length must match graph num_vertices"
70 );
71 Self { graph, weights }
72 }
73
74 pub fn graph(&self) -> &G {
76 &self.graph
77 }
78
79 pub fn weights(&self) -> &[W] {
81 &self.weights
82 }
83
84 pub fn is_weighted(&self) -> bool
86 where
87 W: WeightElement,
88 {
89 !W::IS_UNIT
90 }
91
92 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
94 is_independent_set_config(&self.graph, config)
95 }
96}
97
98impl<G: Graph, W: WeightElement> MaximumIndependentSet<G, W> {
99 pub fn num_vertices(&self) -> usize {
101 self.graph().num_vertices()
102 }
103
104 pub fn num_edges(&self) -> usize {
106 self.graph().num_edges()
107 }
108}
109
110impl<G, W> Problem for MaximumIndependentSet<G, W>
111where
112 G: Graph + crate::variant::VariantParam,
113 W: WeightElement + crate::variant::VariantParam,
114{
115 const NAME: &'static str = "MaximumIndependentSet";
116 type Metric = SolutionSize<W::Sum>;
117
118 fn variant() -> Vec<(&'static str, &'static str)> {
119 crate::variant_params![G, W]
120 }
121
122 fn dims(&self) -> Vec<usize> {
123 vec![2; self.graph.num_vertices()]
124 }
125
126 fn evaluate(&self, config: &[usize]) -> SolutionSize<W::Sum> {
127 if !is_independent_set_config(&self.graph, config) {
128 return SolutionSize::Invalid;
129 }
130 let mut total = W::Sum::zero();
131 for (i, &selected) in config.iter().enumerate() {
132 if selected == 1 {
133 total += self.weights[i].to_sum();
134 }
135 }
136 SolutionSize::Valid(total)
137 }
138}
139
140impl<G, W> OptimizationProblem for MaximumIndependentSet<G, W>
141where
142 G: Graph + crate::variant::VariantParam,
143 W: WeightElement + crate::variant::VariantParam,
144{
145 type Value = W::Sum;
146
147 fn direction(&self) -> Direction {
148 Direction::Maximize
149 }
150}
151
152fn is_independent_set_config<G: Graph>(graph: &G, config: &[usize]) -> bool {
154 for (u, v) in graph.edges() {
155 if config.get(u).copied().unwrap_or(0) == 1 && config.get(v).copied().unwrap_or(0) == 1 {
156 return false;
157 }
158 }
159 true
160}
161
162crate::declare_variants! {
163 MaximumIndependentSet<SimpleGraph, i32> => "1.1996^num_vertices",
164 MaximumIndependentSet<SimpleGraph, One> => "1.1996^num_vertices",
165 MaximumIndependentSet<KingsSubgraph, i32> => "2^sqrt(num_vertices)",
166 MaximumIndependentSet<KingsSubgraph, One> => "2^sqrt(num_vertices)",
167 MaximumIndependentSet<TriangularSubgraph, i32> => "2^sqrt(num_vertices)",
168 MaximumIndependentSet<UnitDiskGraph, i32> => "2^sqrt(num_vertices)",
169 MaximumIndependentSet<UnitDiskGraph, One> => "2^sqrt(num_vertices)",
170}
171
172#[cfg(test)]
181pub(crate) fn is_independent_set<G: Graph>(graph: &G, selected: &[bool]) -> bool {
182 assert_eq!(
183 selected.len(),
184 graph.num_vertices(),
185 "selected length must match num_vertices"
186 );
187 for (u, v) in graph.edges() {
188 if selected[u] && selected[v] {
189 return false;
190 }
191 }
192 true
193}
194
195#[cfg(test)]
196#[path = "../../unit_tests/models/graph/maximum_independent_set.rs"]
197mod tests;