problemreductions/models/graph/
highly_connected_deletion.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, ProblemSizeFieldEntry, VariantDimension};
20use crate::topology::{Graph, SimpleGraph};
21use crate::traits::Problem;
22use crate::types::Min;
23use crate::variant::VariantParam;
24use serde::{Deserialize, Serialize};
25use std::collections::{HashSet, VecDeque};
26
27inventory::submit! {
28 ProblemSchemaEntry {
29 name: "HighlyConnectedDeletion",
30 display_name: "Highly Connected Deletion",
31 aliases: &[],
32 dimensions: &[
33 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
34 ],
35 module_path: module_path!(),
36 description: "Minimum number of edge deletions so every component is an isolated vertex or a highly connected graph on >=3 vertices",
37 fields: &[
38 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
39 ],
40 }
41}
42
43inventory::submit! {
44 ProblemSizeFieldEntry {
45 name: "HighlyConnectedDeletion",
46 fields: &["num_vertices", "num_edges"],
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
81pub struct HighlyConnectedDeletion<G> {
82 graph: G,
84}
85
86impl<G: Graph> HighlyConnectedDeletion<G> {
87 pub fn new(graph: G) -> Self {
89 Self { graph }
90 }
91
92 pub fn graph(&self) -> &G {
94 &self.graph
95 }
96
97 pub fn num_vertices(&self) -> usize {
99 self.graph.num_vertices()
100 }
101
102 pub fn num_edges(&self) -> usize {
104 self.graph.num_edges()
105 }
106
107 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
110 is_feasible_deletion(&self.graph, config)
111 }
112}
113
114impl<G> Problem for HighlyConnectedDeletion<G>
115where
116 G: Graph + VariantParam,
117{
118 const NAME: &'static str = "HighlyConnectedDeletion";
119 type Value = Min<i64>;
120
121 fn variant() -> Vec<(&'static str, &'static str)> {
122 crate::variant_params![G]
123 }
124
125 fn dims(&self) -> Vec<usize> {
126 vec![2; self.graph.num_edges()]
127 }
128
129 fn evaluate(&self, config: &[usize]) -> Min<i64> {
130 if !is_feasible_deletion(&self.graph, config) {
131 return Min(None);
132 }
133 let deleted: i64 = config.iter().filter(|&&x| x == 1).count() as i64;
134 Min(Some(deleted))
135 }
136}
137
138fn is_feasible_deletion<G: Graph>(graph: &G, config: &[usize]) -> bool {
144 let n = graph.num_vertices();
145 let edges = graph.edges();
146 if config.len() != edges.len() {
147 return false;
148 }
149
150 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
152 for (i, &(u, v)) in edges.iter().enumerate() {
153 if config.get(i).copied().unwrap_or(0) == 0 {
154 adj[u].push(v);
155 adj[v].push(u);
156 }
157 }
158
159 let mut visited = vec![false; n];
161 for start in 0..n {
162 if visited[start] {
163 continue;
164 }
165 let mut component: Vec<usize> = Vec::new();
166 let mut queue: VecDeque<usize> = VecDeque::new();
167 queue.push_back(start);
168 visited[start] = true;
169 while let Some(u) = queue.pop_front() {
170 component.push(u);
171 for &w in &adj[u] {
172 if !visited[w] {
173 visited[w] = true;
174 queue.push_back(w);
175 }
176 }
177 }
178 let size = component.len();
179 if size == 1 {
180 continue; }
182 if size == 2 {
183 return false; }
185 let lambda = edge_connectivity(&component, &adj);
187 if 2 * lambda <= size {
189 return false;
190 }
191 }
192 true
193}
194
195fn edge_connectivity(vertices: &[usize], adj: &[Vec<usize>]) -> usize {
208 let size = vertices.len();
209 if size <= 1 {
210 return 0;
211 }
212 let mut local: std::collections::HashMap<usize, usize> =
214 std::collections::HashMap::with_capacity(size);
215 for (i, &v) in vertices.iter().enumerate() {
216 local.insert(v, i);
217 }
218
219 let in_component: HashSet<usize> = vertices.iter().copied().collect();
224 let mut head: Vec<usize> = Vec::new();
225 let mut cap: Vec<i32> = Vec::new();
226 let mut out: Vec<Vec<usize>> = vec![Vec::new(); size];
227
228 let mut seen_edges: HashSet<(usize, usize)> = HashSet::new();
229 for &u in vertices {
230 let lu = local[&u];
231 for &v in &adj[u] {
232 if !in_component.contains(&v) {
233 continue;
234 }
235 let key = if u < v { (u, v) } else { (v, u) };
236 if !seen_edges.insert(key) {
237 continue;
238 }
239 let lv = local[&v];
240 let a = head.len();
242 head.push(lv);
243 cap.push(1);
244 head.push(lu);
246 cap.push(1);
247 out[lu].push(a);
248 out[lv].push(a + 1);
249 }
250 }
251
252 let mut best = usize::MAX;
253 let s = 0;
254 for t in 1..size {
255 for c in cap.iter_mut() {
257 *c = 1;
258 }
259 let mut flow = 0usize;
260 loop {
261 let mut parent_arc: Vec<i32> = vec![-1; size];
263 let mut visited = vec![false; size];
264 visited[s] = true;
265 let mut queue: VecDeque<usize> = VecDeque::new();
266 queue.push_back(s);
267 while let Some(u) = queue.pop_front() {
268 if u == t {
269 break;
270 }
271 for &a in &out[u] {
272 let v = head[a];
273 if !visited[v] && cap[a] > 0 {
274 visited[v] = true;
275 parent_arc[v] = a as i32;
276 queue.push_back(v);
277 }
278 }
279 }
280 if !visited[t] {
281 break;
282 }
283 let mut cur = t;
285 while cur != s {
286 let a = parent_arc[cur] as usize;
287 cap[a] -= 1;
288 cap[a ^ 1] += 1;
289 cur = head[a ^ 1];
291 }
292 flow += 1;
293 }
294 if flow < best {
295 best = flow;
296 if best == 0 {
297 return 0;
298 }
299 }
300 }
301 if best == usize::MAX {
302 0
303 } else {
304 best
305 }
306}
307
308crate::declare_variants! {
309 default HighlyConnectedDeletion<SimpleGraph> => "2^num_edges",
310}
311
312#[cfg(feature = "example-db")]
313pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
314 vec![crate::example_db::specs::ModelExampleSpec {
315 id: "highly_connected_deletion_simplegraph",
316 instance: Box::new(HighlyConnectedDeletion::new(SimpleGraph::new(
317 4,
318 vec![(0, 1), (0, 2), (1, 2), (2, 3)],
319 ))),
320 optimal_config: vec![0, 0, 0, 1],
322 optimal_value: serde_json::json!(1),
323 }]
324}
325
326pub(crate) fn is_feasible_cluster<G: Graph>(graph: &G, vertices: &[usize]) -> bool {
335 let size = vertices.len();
336 if size == 0 {
337 return false;
338 }
339 if size == 1 {
340 return true;
341 }
342 if size == 2 {
343 return false;
344 }
345
346 let n = graph.num_vertices();
348 let in_subset: HashSet<usize> = vertices.iter().copied().collect();
349 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
350 for (u, v) in graph.edges() {
351 if in_subset.contains(&u) && in_subset.contains(&v) {
352 adj[u].push(v);
353 adj[v].push(u);
354 }
355 }
356
357 let mut visited: HashSet<usize> = HashSet::new();
359 let start = vertices[0];
360 let mut queue: VecDeque<usize> = VecDeque::new();
361 queue.push_back(start);
362 visited.insert(start);
363 while let Some(u) = queue.pop_front() {
364 for &w in &adj[u] {
365 if !visited.contains(&w) {
366 visited.insert(w);
367 queue.push_back(w);
368 }
369 }
370 }
371 if visited.len() != size {
372 return false;
373 }
374
375 let lambda = edge_connectivity(vertices, &adj);
377 2 * lambda > size
378}
379
380pub(crate) fn induced_edge_count<G: Graph>(graph: &G, vertices: &[usize]) -> usize {
383 let in_subset: HashSet<usize> = vertices.iter().copied().collect();
384 graph
385 .edges()
386 .into_iter()
387 .filter(|(u, v)| in_subset.contains(u) && in_subset.contains(v))
388 .count()
389}
390
391#[cfg(test)]
392#[path = "../../unit_tests/models/graph/highly_connected_deletion.rs"]
393mod tests;
394
395#[cfg(test)]
396pub(crate) fn edge_connectivity_for_tests(vertices: &[usize], adj: &[Vec<usize>]) -> usize {
397 edge_connectivity(vertices, adj)
398}