problemreductions/models/graph/
maximal_is.rs1use crate::registry::{CreateSpec, 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", "i64", &["i64"]),
21 ],
22 category: crate::registry::ProblemCategory::Graph,
23 module_path: module_path!(),
24 description: "Find maximum weight maximal independent set",
25 fields: MaximalISCreateSpec::FIELDS,
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(try_from = "MaximalISData<G, W>")]
58#[serde(bound(deserialize = "G: Graph + Deserialize<'de>, W: Clone + Default + Deserialize<'de>"))]
59pub struct MaximalIS<G, W> {
60 graph: G,
62 weights: Vec<W>,
64}
65
66#[derive(Deserialize)]
67struct MaximalISData<G, W> {
68 graph: G,
69 weights: Vec<W>,
70}
71
72impl<G, W> TryFrom<MaximalISData<G, W>> for MaximalIS<G, W>
73where
74 G: Graph,
75 W: Clone + Default,
76{
77 type Error = crate::registry::ConstructionError;
78
79 fn try_from(data: MaximalISData<G, W>) -> Result<Self, Self::Error> {
80 Self::try_new(data.graph, data.weights)
81 }
82}
83
84#[derive(Debug, Deserialize, crate::CreateSpec)]
85struct MaximalISCreateSpec {
86 graph: SimpleGraph,
88 weights: Vec<i64>,
90}
91
92impl TryFrom<MaximalISCreateSpec> for MaximalIS<SimpleGraph, i64> {
93 type Error = crate::registry::ConstructionError;
94 fn try_from(spec: MaximalISCreateSpec) -> Result<Self, Self::Error> {
95 Self::try_new(spec.graph, spec.weights)
96 }
97}
98
99impl<G: Graph, W: Clone + Default> MaximalIS<G, W> {
100 pub fn new(graph: G, weights: Vec<W>) -> Self {
102 Self::try_new(graph, weights).unwrap_or_else(|error| panic!("{error}"))
103 }
104
105 fn try_new(graph: G, weights: Vec<W>) -> Result<Self, crate::registry::ConstructionError> {
106 if weights.len() != graph.num_vertices() {
107 return Err(crate::registry::ConstructionError::length_mismatch(
108 "weights",
109 weights.len(),
110 graph.num_vertices(),
111 ));
112 }
113 Ok(Self { graph, weights })
114 }
115
116 pub fn graph(&self) -> &G {
118 &self.graph
119 }
120
121 pub fn weights(&self) -> &[W] {
123 &self.weights
124 }
125
126 pub fn is_weighted(&self) -> bool
128 where
129 W: WeightElement,
130 {
131 !W::IS_UNIT
132 }
133
134 pub fn is_valid_solution(&self, config: &[bool]) -> bool {
136 self.is_maximal(config)
137 }
138
139 fn is_independent(&self, config: &[bool]) -> bool {
141 for (u, v) in self.graph.edges() {
142 if config.get(u).copied().unwrap_or(false) && config.get(v).copied().unwrap_or(false) {
143 return false;
144 }
145 }
146 true
147 }
148
149 fn is_maximal(&self, config: &[bool]) -> bool {
151 if !self.is_independent(config) {
152 return false;
153 }
154
155 let n = self.graph.num_vertices();
156 for v in 0..n {
157 if config.get(v).copied().unwrap_or(false) {
158 continue; }
160
161 let neighbors = self.graph.neighbors(v);
163 let can_add = neighbors
164 .iter()
165 .all(|&u| !config.get(u).copied().unwrap_or(false));
166
167 if can_add {
168 return false; }
170 }
171
172 true
173 }
174}
175
176impl<G: Graph, W: WeightElement> MaximalIS<G, W> {
177 pub fn num_vertices(&self) -> usize {
179 self.graph().num_vertices()
180 }
181
182 pub fn num_edges(&self) -> usize {
184 self.graph().num_edges()
185 }
186}
187
188impl<G, W> Problem for MaximalIS<G, W>
189where
190 G: Graph + crate::variant::VariantParam,
191 W: WeightElement + crate::variant::VariantParam,
192{
193 const NAME: &'static str = "MaximalIS";
194 type Solution = Vec<bool>;
195 type Value = Max<W::Sum>;
196
197 crate::problem_parameters![("num_edges", num_edges), ("num_vertices", num_vertices),];
198
199 fn variant() -> Vec<(&'static str, &'static str)> {
200 crate::variant_params![G, W]
201 }
202
203 fn evaluate(
204 &self,
205 config: &Self::Solution,
206 ) -> Result<Max<W::Sum>, crate::traits::EvaluationError> {
207 if config.len() != self.graph.num_vertices() {
208 return Err(crate::traits::EvaluationError::InvalidConfiguration(
209 "vertex-selection length does not match the graph".into(),
210 ));
211 }
212 Ok({
213 if !self.is_maximal(config) {
214 return Ok(Max(None));
215 }
216 let mut total = W::Sum::zero();
217 for (i, &selected) in config.iter().enumerate() {
218 if selected {
219 total = W::checked_add_to_sum(
220 total,
221 self.weights[i].to_sum(),
222 "summing selected maximal-independent-set weights",
223 )?;
224 }
225 }
226 Max(Some(total))
227 })
228 }
229}
230
231impl<G, W> crate::solvers::BruteForceProblem for MaximalIS<G, W>
232where
233 G: Graph + crate::variant::VariantParam,
234 W: WeightElement + crate::variant::VariantParam,
235{
236 fn dimensions(&self) -> Vec<usize> {
237 vec![2; self.graph.num_vertices()]
238 }
239}
240
241#[cfg(feature = "example-db")]
242pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
243 vec![crate::example_db::specs::ModelExampleSpec {
244 id: "maximal_is_simplegraph",
245 instance: Box::new(MaximalIS::new(
246 SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]),
247 vec![1i64; 5],
248 )),
249 optimal_config: serde_json::json!(vec![true, false, true, false, true]),
250 optimal_value: serde_json::json!(3),
251 }]
252}
253
254#[cfg(test)]
259pub(crate) fn is_maximal_independent_set<G: Graph>(graph: &G, selected: &[bool]) -> bool {
260 assert_eq!(
261 selected.len(),
262 graph.num_vertices(),
263 "selected length must match num_vertices"
264 );
265
266 for (u, v) in graph.edges() {
268 if selected[u] && selected[v] {
269 return false;
270 }
271 }
272
273 for v in 0..graph.num_vertices() {
275 if selected[v] {
276 continue;
277 }
278 if graph.neighbors(v).iter().all(|&u| !selected[u]) {
279 return false;
280 }
281 }
282
283 true
284}
285
286crate::impl_random_generate!(MaximalIS<SimpleGraph, i64>, crate::random::SimpleGraphRandomSpec, |spec| {
287 Ok(MaximalIS::new(spec.graph()?, vec![1; spec.num_vertices]))
288});
289
290crate::declare_variants! {
291 default MaximalIS<SimpleGraph, i64> => "3^(num_vertices / 3)" create MaximalISCreateSpec random,
292}
293
294crate::register_brute_force! {
295 MaximalIS<SimpleGraph, i64> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
296}
297
298#[cfg(test)]
299#[path = "../../unit_tests/models/graph/maximal_is.rs"]
300mod tests;