problemreductions/models/graph/
maximal_is.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::Problem;
9use crate::types::{Max, WeightElement};
10use num_traits::Zero;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MaximalIS",
16 display_name: "Maximal IS",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 VariantDimension::new("weight", "i32", &["i32"]),
21 ],
22 module_path: module_path!(),
23 description: "Find maximum weight maximal independent set",
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)]
59pub struct MaximalIS<G, W> {
60 graph: G,
62 weights: Vec<W>,
64}
65
66impl<G: Graph, W: Clone + Default> MaximalIS<G, W> {
67 pub fn new(graph: G, weights: Vec<W>) -> Self {
69 assert_eq!(
70 weights.len(),
71 graph.num_vertices(),
72 "weights length must match graph num_vertices"
73 );
74 Self { graph, weights }
75 }
76
77 pub fn graph(&self) -> &G {
79 &self.graph
80 }
81
82 pub fn weights(&self) -> &[W] {
84 &self.weights
85 }
86
87 pub fn is_weighted(&self) -> bool
89 where
90 W: WeightElement,
91 {
92 !W::IS_UNIT
93 }
94
95 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
97 self.is_maximal(config)
98 }
99
100 fn is_independent(&self, config: &[usize]) -> bool {
102 for (u, v) in self.graph.edges() {
103 if config.get(u).copied().unwrap_or(0) == 1 && config.get(v).copied().unwrap_or(0) == 1
104 {
105 return false;
106 }
107 }
108 true
109 }
110
111 fn is_maximal(&self, config: &[usize]) -> bool {
113 if !self.is_independent(config) {
114 return false;
115 }
116
117 let n = self.graph.num_vertices();
118 for v in 0..n {
119 if config.get(v).copied().unwrap_or(0) == 1 {
120 continue; }
122
123 let neighbors = self.graph.neighbors(v);
125 let can_add = neighbors
126 .iter()
127 .all(|&u| config.get(u).copied().unwrap_or(0) == 0);
128
129 if can_add {
130 return false; }
132 }
133
134 true
135 }
136}
137
138impl<G: Graph, W: WeightElement> MaximalIS<G, W> {
139 pub fn num_vertices(&self) -> usize {
141 self.graph().num_vertices()
142 }
143
144 pub fn num_edges(&self) -> usize {
146 self.graph().num_edges()
147 }
148}
149
150impl<G, W> Problem for MaximalIS<G, W>
151where
152 G: Graph + crate::variant::VariantParam,
153 W: WeightElement + crate::variant::VariantParam,
154{
155 const NAME: &'static str = "MaximalIS";
156 type Value = Max<W::Sum>;
157
158 fn variant() -> Vec<(&'static str, &'static str)> {
159 crate::variant_params![G, W]
160 }
161
162 fn dims(&self) -> Vec<usize> {
163 vec![2; self.graph.num_vertices()]
164 }
165
166 fn evaluate(&self, config: &[usize]) -> Max<W::Sum> {
167 if !self.is_maximal(config) {
168 return Max(None);
169 }
170 let mut total = W::Sum::zero();
171 for (i, &selected) in config.iter().enumerate() {
172 if selected == 1 {
173 total += self.weights[i].to_sum();
174 }
175 }
176 Max(Some(total))
177 }
178}
179
180#[cfg(feature = "example-db")]
181pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
182 vec![crate::example_db::specs::ModelExampleSpec {
183 id: "maximal_is_simplegraph_i32",
184 instance: Box::new(MaximalIS::new(
185 SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]),
186 vec![1i32; 5],
187 )),
188 optimal_config: vec![1, 0, 1, 0, 1],
189 optimal_value: serde_json::json!(3),
190 }]
191}
192
193#[cfg(test)]
198pub(crate) fn is_maximal_independent_set<G: Graph>(graph: &G, selected: &[bool]) -> bool {
199 assert_eq!(
200 selected.len(),
201 graph.num_vertices(),
202 "selected length must match num_vertices"
203 );
204
205 for (u, v) in graph.edges() {
207 if selected[u] && selected[v] {
208 return false;
209 }
210 }
211
212 for v in 0..graph.num_vertices() {
214 if selected[v] {
215 continue;
216 }
217 if graph.neighbors(v).iter().all(|&u| !selected[u]) {
218 return false;
219 }
220 }
221
222 true
223}
224
225crate::declare_variants! {
226 default MaximalIS<SimpleGraph, i32> => "3^(num_vertices / 3)",
227}
228
229#[cfg(test)]
230#[path = "../../unit_tests/models/graph/maximal_is.rs"]
231mod tests;