1use crate::datastructures::BitSet;
2use crate::graph::base_graph::BaseGraph;
3use crate::graph::mutable_graph::MutableGraph;
4use crate::heuristic_elimination_order::{
5 HeuristicEliminationDecomposer, MinDegreeSelector, MinFillSelector,
6};
7use crate::tree_decomposition::TreeDecomposition;
8use fxhash::FxHashMap;
9use fxhash::FxHashSet;
10use rand::prelude::{SliceRandom, StdRng};
11use rand::{Rng, SeedableRng};
12use std::cmp::{max, min, Ordering};
13use std::collections::VecDeque;
14
15#[cfg(feature = "handle-ctrlc")]
16use crate::signals::received_ctrl_c;
17use crate::solver::AtomSolver;
18
19#[derive(Clone, Debug)]
20pub struct HashMapGraph {
21 data: FxHashMap<usize, FxHashSet<usize>>,
22}
23
24#[derive(Clone, Debug, Copy)]
25struct MissingEdge {
26 u: usize,
27 v: usize,
28}
29
30#[derive(Clone, Debug)]
31pub struct MinorSafeResult {
32 pub separator: FxHashSet<usize>,
33 pub belongs_to: (usize, usize),
34 pub tree_decomposition: TreeDecomposition,
35}
36
37impl HashMapGraph {
38 pub fn has_vertex(&self, u: usize) -> bool {
39 self.data.contains_key(&u)
40 }
41 pub fn neighborhood_set(&self, u: usize) -> &FxHashSet<usize> {
42 self.data.get(&u).unwrap()
43 }
44 pub fn dfs(&self, u: usize) -> HashMapGraphDfs {
45 assert!(self.data.contains_key(&u));
46 let mut visited = BitSet::new(self.data.len());
47 visited.set_bit(u);
48 HashMapGraphDfs {
49 graph: self,
50 stack: vec![u],
51 visited,
52 }
53 }
54
55 pub fn find_cut_vertex(&self) -> Option<FxHashSet<usize>> {
56 if self.data.is_empty() {
57 return None;
58 }
59 let u = self.data.keys().copied().next().unwrap();
60 let mut c = 0;
61 let mut l: FxHashMap<usize, usize> = FxHashMap::default();
62 let mut d: FxHashMap<usize, usize> = FxHashMap::default();
63 let ignore: FxHashSet<usize> = FxHashSet::default();
64 if let Some(v) = self.articulation_point_helper(u, u, &mut c, &mut l, &mut d, &ignore) {
65 let mut set: FxHashSet<usize> = FxHashSet::default();
66 set.insert(v);
67 return Some(set);
68 }
69 None
70 }
71
72 pub fn find_safe_bi_connected_separator(&self) -> Option<FxHashSet<usize>> {
73 if self.data.is_empty() {
74 return None;
75 }
76 for guess in self.data.keys().copied() {
77 #[cfg(feature = "handle-ctrlc")]
78 if received_ctrl_c() {
79 return None;
80 }
81 #[cfg(feature = "cli")]
82 if crate::timeout::timeout() {
83 return None;
84 }
85 let mut c = 0;
86 let mut l: FxHashMap<usize, usize> = FxHashMap::default();
87 let mut d: FxHashMap<usize, usize> = FxHashMap::default();
88 let mut ignore: FxHashSet<usize> = FxHashSet::default();
89 ignore.insert(guess);
90 let u = self.data.keys().copied().find(|x| *x != guess)?;
91 if let Some(p) = self.articulation_point_helper(u, u, &mut c, &mut l, &mut d, &ignore) {
92 let mut set: FxHashSet<usize> = FxHashSet::default();
93 set.insert(guess);
94 set.insert(p);
95 return Some(set);
96 }
97 }
98 None
99 }
100
101 pub fn connected_components(&self) -> Vec<FxHashSet<usize>> {
102 self.separate(&FxHashSet::default())
103 }
104
105 pub fn find_safe_tri_connected_separator(&self) -> Option<FxHashSet<usize>> {
106 if self.data.is_empty() {
107 return None;
108 }
109 for f1 in self.data.keys().copied() {
110 for f2 in self
111 .data
112 .keys()
113 .copied()
114 .filter(|forbidden2| *forbidden2 > f1)
115 {
116 #[cfg(feature = "handle-ctrlc")]
117 if received_ctrl_c() {
118 return None;
119 }
120 #[cfg(feature = "cli")]
121 if crate::timeout::timeout() {
122 return None;
123 }
124 let u = self.data.keys().copied().find(|x| *x != f1 && *x != f2)?;
125 let mut c = 0;
126 let mut l: FxHashMap<usize, usize> = FxHashMap::default();
127 let mut d: FxHashMap<usize, usize> = FxHashMap::default();
128 let mut ignore: FxHashSet<usize> = FxHashSet::default();
129 ignore.insert(f1);
130 ignore.insert(f2);
131 if let Some(p) =
132 self.articulation_point_helper(u, u, &mut c, &mut l, &mut d, &ignore)
133 {
134 if self.data.get(&p).unwrap().contains(&f1)
136 || self.data.get(&p).unwrap().contains(&f2)
137 || self.data.get(&f1).unwrap().contains(&f2)
138 {
139 let mut set: FxHashSet<usize> = FxHashSet::default();
140 set.insert(f1);
141 set.insert(f2);
142 set.insert(p);
143 return Some(set);
144 }
145 let not_found = !self.data.iter().any(|(_, v)| {
147 v.len() == 3 && v.contains(&p) && v.contains(&f1) && v.contains(&f2)
148 });
149 if not_found {
150 let mut set: FxHashSet<usize> = FxHashSet::default();
151 set.insert(f1);
152 set.insert(f2);
153 set.insert(p);
154 return Some(set);
155 }
156
157 let mut separator = FxHashSet::default();
159 separator.insert(f1);
160 separator.insert(f2);
161 separator.insert(p);
162 let components = self.separate(&separator);
163 if components.len() > 2
164 || components.len() == 2 && !components.iter().any(|c| c.len() <= 1)
165 {
166 let mut set: FxHashSet<usize> = FxHashSet::default();
167 set.insert(f1);
168 set.insert(f2);
169 set.insert(p);
170 return Some(set);
171 }
172 }
173 }
174 }
175 None
176 }
177
178 fn no_match_minor_helper(
179 &self,
180 max_tries: usize,
181 max_missing: usize,
182 seed: Option<u64>,
183 use_min_degree: bool,
184 ) -> Option<MinorSafeResult> {
185 let mut new_td = HeuristicEliminationDecomposer::<MinFillSelector>::with_graph(self)
186 .compute()
187 .computed_tree_decomposition()
188 .unwrap();
189 new_td.flatten();
190 if let Some(result) = self.minor_safe_helper(new_td, max_tries, max_missing, seed) {
191 Some(result)
192 } else if use_min_degree {
193 let mut new_td = HeuristicEliminationDecomposer::<MinDegreeSelector>::with_graph(self)
194 .compute()
195 .computed_tree_decomposition()
196 .unwrap();
197 new_td.flatten();
198 self.minor_safe_helper(new_td, max_tries, max_missing, seed)
199 } else {
200 None
201 }
202 }
203
204 pub fn find_minor_safe_separator(
205 &self,
206 tree_decomposition: Option<TreeDecomposition>,
207 seed: Option<u64>,
208 max_tries: usize,
209 max_missing: usize,
210 use_min_degree: bool,
211 ) -> Option<MinorSafeResult> {
212 match tree_decomposition {
213 None => self.no_match_minor_helper(max_tries, max_missing, seed, use_min_degree),
214 Some(working_td) => {
215 match self.minor_safe_helper(working_td, max_tries, max_missing, seed) {
216 None => {
217 self.no_match_minor_helper(max_tries, max_missing, seed, use_min_degree)
218 }
219 Some(result) => Some(result),
220 }
221 }
222 }
223 }
224
225 fn minor_safe_helper(
226 &self,
227 td: TreeDecomposition,
228 max_tries: usize,
229 max_missing: usize,
230 seed: Option<u64>,
231 ) -> Option<MinorSafeResult> {
232 for first_bag in td.bags.iter() {
233 for idx in first_bag.neighbors.iter().copied().filter(|id| {
234 *id >= first_bag.id && !td.bags[*id].vertex_set.eq(&first_bag.vertex_set)
235 }) {
236 #[cfg(feature = "handle-ctrlc")]
237 if received_ctrl_c() {
238 return None;
239 }
240 #[cfg(feature = "cli")]
241 if crate::timeout::timeout() {
242 return None;
243 }
244 let second_bag = &td.bags[idx].vertex_set;
245 let candidate: FxHashSet<usize> = first_bag
246 .vertex_set
247 .intersection(second_bag)
248 .copied()
249 .collect();
250 if self.is_minor_safe(&candidate, max_tries, max_missing, seed) {
251 return Some(MinorSafeResult {
252 separator: candidate,
253 belongs_to: (min(first_bag.id, idx), max(first_bag.id, idx)),
254 tree_decomposition: td,
255 });
256 }
257 }
258 }
259 None
260 }
261
262 fn is_minor_safe(
263 &self,
264 separator: &FxHashSet<usize>,
265 max_tries: usize,
266 max_missing: usize,
267 seed: Option<u64>,
268 ) -> bool {
269 #[cfg(feature = "handle-ctrlc")]
270 if received_ctrl_c() {
271 return false;
272 }
273 #[cfg(feature = "cli")]
274 if crate::timeout::timeout() {
275 return false;
276 }
277 let components = self.separate(separator);
278 if components.len() < 2 {
279 return false;
280 }
281 let mut rng: StdRng = SeedableRng::seed_from_u64(seed.unwrap_or(1337 * 42 * 777));
282
283 for component in components.iter() {
284 #[cfg(feature = "handle-ctrlc")]
285 if received_ctrl_c() {
286 return false;
287 }
288 #[cfg(feature = "cli")]
289 if crate::timeout::timeout() {
290 return false;
291 }
292 let rest: FxHashSet<usize> = self
293 .data
294 .keys()
295 .copied()
296 .filter(|k| !component.contains(k))
297 .collect();
298
299 let mut tmp = self.vertex_induced(&rest);
300 let mut missing_edges: Vec<_> = Vec::new();
301 for u in separator.iter().copied() {
302 for v in separator
303 .iter()
304 .copied()
305 .filter(|v| u < *v && !tmp.data.get(v).unwrap().contains(&u))
306 {
307 missing_edges.push(MissingEdge { u, v });
308 }
309 }
310 if missing_edges.len() > max_missing {
311 return false;
312 }
313 let mut is_minor = false;
314 'outer: for _ in 0..max_tries {
315 missing_edges.shuffle(&mut rng);
316 for missing_edge in missing_edges.iter() {
317 #[cfg(feature = "handle-ctrlc")]
318 if received_ctrl_c() {
319 return false;
320 }
321 #[cfg(feature = "cli")]
322 if crate::timeout::timeout() {
323 return false;
324 }
325 if tmp
326 .data
327 .get(&missing_edge.v)
328 .unwrap()
329 .contains(&missing_edge.u)
330 {
331 continue;
332 }
333 let u = missing_edge.u;
334 let v = missing_edge.v;
335 let common_neighbors: Vec<_> = tmp
336 .data
337 .get(&u)
338 .unwrap()
339 .iter()
340 .copied()
341 .filter(|x| !separator.contains(x) && tmp.data.get(&v).unwrap().contains(x))
342 .collect();
343 if !common_neighbors.is_empty() {
344 let idx: usize = rng.gen_range(0..common_neighbors.len());
345 let contractor = common_neighbors[idx];
346 if rng.gen_bool(0.5) {
347 tmp.contract(contractor, v);
348 } else {
349 tmp.contract(contractor, u);
350 }
351 } else {
352 let mut queue = VecDeque::new();
353 queue.push_back(v);
354 let mut pre: FxHashMap<_, _> =
355 separator.iter().copied().map(|v| (v, v)).collect();
356 pre.remove(&u);
357 while !pre.contains_key(&u) && !queue.is_empty() {
358 #[cfg(feature = "handle-ctrlc")]
359 if received_ctrl_c() {
360 return false;
361 }
362 #[cfg(feature = "cli")]
363 if crate::timeout::timeout() {
364 return false;
365 }
366 let x = queue.pop_front().unwrap();
367 for k in tmp.data.get(&x).unwrap().iter().copied() {
368 if pre.contains_key(&k) {
369 continue;
370 }
371 pre.insert(k, x);
372 queue.push_back(k);
373 if k == u {
374 break;
375 }
376 }
377 }
378 let value = pre.get(&u);
379 if let Some(current) = value {
380 let mut current = *current;
381 while current != v {
382 tmp.contract(current, u);
383 current = *pre.get(¤t).unwrap();
384 }
385 } else {
386 continue 'outer;
387 }
388 }
389 }
390 is_minor = true;
391 break;
392 }
393 if !is_minor {
394 return false;
395 }
396 }
397 true
398 }
399
400 pub fn vertex_induced(&self, vertices: &FxHashSet<usize>) -> Self {
401 let data: FxHashMap<usize, FxHashSet<usize>> = self
402 .data
403 .iter()
404 .filter(|(vertex, _)| vertices.contains(vertex))
405 .map(|(vertex, neighborhood)| {
406 (
407 *vertex,
408 neighborhood
409 .iter()
410 .copied()
411 .filter(|x| vertices.contains(x))
412 .collect(),
413 )
414 })
415 .collect();
416 Self { data }
417 }
418
419 fn is_minimal_separator(&self, separator: &FxHashSet<usize>) -> bool {
420 let components = self.separate(separator);
421 components.len() > 1
422 && !components.iter().any(|component| {
423 separator.iter().any(|v| {
424 !self
425 .data
426 .get(v)
427 .unwrap()
428 .iter()
429 .any(|u| component.contains(u))
430 })
431 })
432 }
433
434 pub fn find_almost_clique_minimal_separator(&self) -> Option<FxHashSet<usize>> {
435 for v in self.data.keys().copied() {
436 #[cfg(feature = "handle-ctrlc")]
437 if received_ctrl_c() {
438 return None;
439 }
440 #[cfg(feature = "cli")]
441 if crate::timeout::timeout() {
442 return None;
443 }
444 let mut ignore = FxHashSet::default();
445 ignore.insert(v);
446 if let Some(mut separator) = self.clique_minimal_separator_helper(&ignore) {
447 separator.insert(v);
448 if self.is_minimal_separator(&separator) {
449 return Some(separator);
450 }
451 }
452 }
453 None
454 }
455
456 pub fn find_clique_minimal_separator(&self) -> Option<FxHashSet<usize>> {
457 let empty = FxHashSet::default();
458 self.clique_minimal_separator_helper(&empty)
459 }
460
461 fn clique_minimal_separator_helper(
462 &self,
463 ignore: &FxHashSet<usize>,
464 ) -> Option<FxHashSet<usize>> {
465 let mut working_graph = self.clone();
467 for v in ignore.iter().copied() {
468 working_graph.remove_vertex(v);
469 }
470 let mut triangulated_graph = self.clone();
471
472 let mut alpha = Vec::with_capacity(self.data.len());
473 let mut generators: FxHashSet<usize> = FxHashSet::default();
474 let mut labels: FxHashMap<usize, usize> =
475 working_graph.data.keys().copied().map(|k| (k, 0)).collect();
476
477 let mut s: Option<usize> = None;
478
479 let working_order = self.order() - ignore.len();
480 for _ in 0..working_order {
481 #[cfg(feature = "handle-ctrlc")]
482 if received_ctrl_c() {
483 return None;
484 }
485 #[cfg(feature = "cli")]
486 if crate::timeout::timeout() {
487 return None;
488 }
489 let x = *working_graph
490 .data
491 .keys()
492 .max_by(|a, b| labels.get(a).cmp(&labels.get(b)))
493 .unwrap();
494 let mut y = working_graph.data.get(&x).unwrap().clone();
495 if s.is_some() && labels.get(&x).unwrap() <= &s.unwrap() {
496 generators.insert(x);
497 }
498 s = Some(*labels.get(&x).unwrap());
499
500 let mut reached: FxHashSet<_> = FxHashSet::default();
501 reached.insert(x);
502 let mut reach: FxHashMap<usize, FxHashSet<usize>> = (0..working_order)
503 .map(|i| (i, FxHashSet::default()))
504 .collect();
505 working_graph.data.get(&x).unwrap().iter().for_each(|i| {
506 reached.insert(*i);
507 reach.get_mut(labels.get(i).unwrap()).unwrap().insert(*i);
508 });
509
510 for j in 0..working_order {
511 while !reach.get(&j).unwrap().is_empty() {
512 let r = *reach.get(&j).unwrap().iter().next().unwrap();
513 reach.get_mut(&j).unwrap().remove(&r);
514 for z in working_graph.data.get(&r).unwrap().iter() {
515 if reached.contains(z) {
516 continue;
517 }
518 reached.insert(*z);
519 if labels.get(z).unwrap() > &j {
520 y.insert(*z);
521 reach.get_mut(labels.get(z).unwrap()).unwrap().insert(*z);
522 } else {
523 reach.get_mut(&j).unwrap().insert(*z);
524 }
525 }
526 }
527 }
528
529 for y in y.iter() {
530 triangulated_graph.add_edge(x, *y);
531 *labels.get_mut(y).unwrap() += 1;
532 }
533
534 alpha.push(x);
535 working_graph.remove_vertex(x);
536 }
537
538 for x in alpha.iter().copied().rev() {
539 if generators.contains(&x) {
540 let s = triangulated_graph.data.get(&x).unwrap();
541 let mut is_clique = true;
542 for v in s.iter() {
543 for u in s.iter().filter(|u| *u > v) {
544 if !self.data.get(v).unwrap().contains(u) {
545 is_clique = false;
546 break;
547 }
548 }
549 if !is_clique {
550 break;
551 }
552 }
553 if is_clique {
554 return Some(s.clone());
555 }
556 }
557 triangulated_graph.remove_vertex(x);
558 }
559 None
560 }
561
562 pub fn separate(&self, separator: &FxHashSet<usize>) -> Vec<FxHashSet<usize>> {
563 let mut components: Vec<FxHashSet<_>> = Vec::with_capacity(2);
564
565 let mut stack: Vec<_> = Vec::with_capacity(self.data.len());
566 let mut visited = FxHashSet::with_capacity_and_hasher(self.data.len(), Default::default());
567 for u in self.data.keys().copied() {
568 if separator.contains(&u) || visited.contains(&u) {
569 continue;
570 }
571 stack.push(u);
572 visited.insert(u);
573 let mut component: FxHashSet<_> = FxHashSet::default();
574 component.insert(u);
575 while let Some(v) = stack.pop() {
576 for x in self.data.get(&v).unwrap().iter() {
577 if component.contains(x) || separator.contains(x) {
578 continue;
579 }
580 stack.push(*x);
581 component.insert(*x);
582 visited.insert(*x);
583 }
584 }
585 components.push(component);
586 }
587 components
588 }
589
590 pub fn vertex_induced_subgraph(&self, vertex_set: &FxHashSet<usize>) -> Self {
591 let mut subgraph = HashMapGraph::with_capacity(vertex_set.len());
592 for u in vertex_set.iter() {
593 for v in vertex_set
594 .iter()
595 .filter(|v| u < *v && self.data.get(*v).unwrap().contains(u))
596 {
597 subgraph.add_edge(*u, *v);
598 }
599 }
600 subgraph
601 }
602
603 fn articulation_point_helper(
604 &self,
605 u: usize,
606 v: usize,
607 count: &mut usize,
608 vertex_to_count: &mut FxHashMap<usize, usize>,
609 discovered: &mut FxHashMap<usize, usize>,
610 ignore: &FxHashSet<usize>,
611 ) -> Option<usize> {
612 #[cfg(feature = "handle-ctrlc")]
613 if received_ctrl_c() {
614 return None;
615 }
616 #[cfg(feature = "cli")]
617 if crate::timeout::timeout() {
618 return None;
619 }
620 *count += 1;
621 let mut children = 0;
622 vertex_to_count.insert(v, *count);
623 discovered.insert(v, *count);
624 let nb = self.data.get(&v).unwrap();
625 for w in nb.iter().filter(|w| !ignore.contains(*w)) {
626 if !discovered.contains_key(w) {
627 children += 1;
628 if let Some(cut) = self.articulation_point_helper(
629 v,
630 *w,
631 count,
632 vertex_to_count,
633 discovered,
634 ignore,
635 ) {
636 return Some(cut);
637 }
638 #[cfg(feature = "handle-ctrlc")]
639 if received_ctrl_c() {
640 return None;
641 }
642 #[cfg(feature = "cli")]
643 if crate::timeout::timeout() {
644 return None;
645 }
646 let v_to_count = *vertex_to_count.get(&v).unwrap();
647 let w_to_count = *vertex_to_count.get(w).unwrap();
648 vertex_to_count.insert(v, min(v_to_count, w_to_count));
649 if vertex_to_count.get(w).unwrap() >= discovered.get(&v).unwrap() && u != v {
650 return Some(v);
651 }
652 } else if *w != u && discovered.get(w).unwrap() < discovered.get(&v).unwrap() {
653 let v_to_count = *vertex_to_count.get(&v).unwrap();
654 let w_to_count = *discovered.get(w).unwrap();
655 vertex_to_count.insert(v, min(v_to_count, w_to_count));
656 }
657 }
658 if u == v && children > 1 {
659 return Some(v);
660 }
661 None
662 }
663}
664
665pub struct HashMapGraphDfs<'a> {
666 graph: &'a HashMapGraph,
667 stack: Vec<usize>,
668 visited: BitSet,
669}
670
671impl<'a> Iterator for HashMapGraphDfs<'a> {
672 type Item = usize;
673
674 fn next(&mut self) -> Option<Self::Item> {
675 let current = self.stack.pop()?;
676 for c in self.graph.data.get(¤t).unwrap().iter().copied() {
677 if !self.visited[c] {
678 self.stack.push(c);
679 self.visited.set_bit(c);
680 }
681 }
682 Some(current)
683 }
684}
685
686impl MutableGraph for HashMapGraph {
687 fn add_vertex(&mut self, u: usize) {
688 self.data.entry(u).or_insert_with(FxHashSet::default);
689 }
690
691 fn add_vertex_with_capacity(&mut self, u: usize, capacity: usize) {
692 self.data
693 .entry(u)
694 .or_insert_with(|| FxHashSet::with_capacity_and_hasher(capacity, Default::default()));
695 }
696
697 fn remove_vertex(&mut self, u: usize) {
698 if let Some(neighbors) = self.data.remove(&u) {
699 for i in neighbors.iter() {
700 self.data.get_mut(i).unwrap().remove(&u);
701 }
702 }
703 }
704
705 fn add_edge(&mut self, u: usize, v: usize) {
706 assert_ne!(u, v);
707 let first = self.data.entry(u).or_insert_with(FxHashSet::default);
708 first.insert(v);
709 let second = self.data.entry(v).or_insert_with(FxHashSet::default);
710 second.insert(u);
711 }
712
713 fn remove_edge(&mut self, u: usize, v: usize) {
714 assert_ne!(u, v);
715 if let Some(x) = self.data.get_mut(&u) {
716 x.remove(&v);
717 }
718 if let Some(x) = self.data.get_mut(&v) {
719 x.remove(&u);
720 }
721 }
722
723 fn eliminate_vertex(&mut self, u: usize) {
724 assert!(self.data.contains_key(&u));
725 let nb = self.data.remove(&u).unwrap();
726 for i in &nb {
727 self.data.get_mut(i).unwrap().remove(&u);
728 }
729 for i in &nb {
730 for j in &nb {
731 if i < j {
732 self.data.get_mut(i).unwrap().insert(*j);
733 self.data.get_mut(j).unwrap().insert(*i);
734 }
735 }
736 }
737 }
738
739 fn contract(&mut self, u: usize, v: usize) {
740 assert_ne!(u, v);
741 assert!(self.data.contains_key(&u));
742 assert!(self.data.contains_key(&v));
743
744 let nb = self.data.remove(&u).unwrap();
745
746 for vertex in nb {
747 if vertex == v {
748 continue;
749 }
750 let a = self.data.get_mut(&vertex).unwrap();
751 a.remove(&u);
752 a.insert(v);
753 let b = self.data.get_mut(&v).unwrap();
754 b.insert(vertex);
755 }
756 self.data.get_mut(&v).unwrap().remove(&u);
757 }
758
759 fn new() -> Self {
760 HashMapGraph {
761 data: FxHashMap::default(),
762 }
763 }
764
765 fn with_capacity(capacity: usize) -> Self {
766 HashMapGraph {
767 data: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
768 }
769 }
770}
771
772impl BaseGraph for HashMapGraph {
773 fn degree(&self, u: usize) -> usize {
774 assert!(self.data.contains_key(&u));
775 self.data.get(&u).unwrap().len()
776 }
777
778 fn order(&self) -> usize {
779 self.data.len()
780 }
781
782 fn is_clique(&self, vertices: &[usize]) -> bool {
783 for (i, v) in vertices.iter().enumerate() {
784 assert!(self.data.contains_key(v));
785 for u in vertices.iter().skip(i + 1) {
786 assert!(self.data.contains_key(u));
787 if !self.data.get(v).unwrap().contains(u) || !self.data.get(u).unwrap().contains(v)
788 {
789 return false;
790 }
791 }
792 }
793 true
794 }
795
796 fn is_neighborhood_clique(&self, u: usize) -> bool {
797 let nb = self.data.get(&u).unwrap();
798 self.is_clique(&nb.iter().copied().collect::<Vec<_>>())
799 }
800
801 fn has_edge(&self, u: usize, v: usize) -> bool {
802 self.data.get(&u).unwrap().contains(&v)
803 }
804
805 fn is_simplicial(&self, u: usize) -> bool {
806 self.is_neighborhood_clique(u)
807 }
808
809 fn is_almost_simplicial(&self, u: usize) -> bool {
810 let mut check: Option<FxHashSet<_>> = None;
811 let nb = self.data.get(&u).unwrap();
812 for v in nb.iter().copied() {
813 for w in nb
814 .iter()
815 .copied()
816 .filter(|w| v < *w && !self.has_edge(v, *w))
817 {
818 if check.is_some() {
819 check.as_mut().unwrap().retain(|x| *x == v || *x == w);
820 if check.as_ref().unwrap().is_empty() {
821 return false;
822 }
823 } else {
824 check = Some([v, w].iter().copied().collect());
825 }
826 }
827 }
828 check.is_none() && check.unwrap().len() == 1
829 }
830
831 fn vertices(&self) -> Box<dyn Iterator<Item = usize> + '_> {
832 let keys = self.data.keys().copied();
833 Box::new(keys)
834 }
835
836 fn neighborhood(&self, u: usize) -> Box<dyn Iterator<Item = usize> + '_> {
837 Box::new(self.data.get(&u).unwrap().iter().copied())
838 }
839
840 fn fill_in_count(&self, u: usize) -> usize {
841 let mut count = 0;
842 for x in self.neighborhood_set(u) {
843 for y in self.neighborhood_set(u) {
844 if x < y && !self.has_edge(*x, *y) {
845 count += 1;
846 }
847 }
848 }
849 count
850 }
851
852 fn min_vertex_by<F: FnMut(&usize, &usize) -> Ordering>(&self, cmp: F) -> Option<usize> {
853 self.data.keys().copied().min_by(cmp)
854 }
855
856 fn max_vertex_by<F: FnMut(&usize, &usize) -> Ordering>(&self, cmp: F) -> Option<usize> {
857 self.data.keys().copied().max_by(cmp)
858 }
859
860 fn min_neighbor_by<F: FnMut(&usize, &usize) -> Ordering>(
861 &self,
862 u: usize,
863 cmp: F,
864 ) -> Option<usize> {
865 self.data.get(&u).unwrap().iter().copied().min_by(cmp)
866 }
867
868 fn max_neighbor_by<F: FnMut(&usize, &usize) -> Ordering>(
869 &self,
870 u: usize,
871 cmp: F,
872 ) -> Option<usize> {
873 self.data.get(&u).unwrap().iter().copied().max_by(cmp)
874 }
875}
876
877impl HashMapGraph {
878 pub fn from_graph<G: BaseGraph>(graph: &G) -> Self {
879 let data = graph
880 .vertices()
881 .map(|v| (v, graph.neighborhood(v).collect()))
882 .collect();
883 HashMapGraph { data }
884 }
885}
886
887#[cfg(test)]
888mod tests {
889 use crate::graph::base_graph::BaseGraph;
890 use crate::graph::hash_map_graph::HashMapGraph;
891 use crate::graph::mutable_graph::MutableGraph;
892
893 #[test]
894 fn test_order() {
895 let mut graph = HashMapGraph::new();
896 assert_eq!(graph.order(), 0);
897
898 graph.add_vertex(0);
899 graph.add_vertex(0);
900 assert_eq!(graph.order(), 1);
901 graph.remove_vertex(0);
902 assert_eq!(graph.order(), 0);
903
904 graph.add_vertex_with_capacity(0, 0);
905 graph.add_vertex_with_capacity(0, 0);
906 assert_eq!(graph.order(), 1);
907 }
908
909 #[test]
910 fn test_degree() {
911 let mut graph = HashMapGraph::new();
912 graph.add_edge(0, 1);
913
914 assert_eq!(graph.degree(0), 1);
915 assert_eq!(graph.degree(1), 1);
916
917 assert_eq!(graph.order(), 2);
918
919 graph.add_edge(0, 1);
920
921 assert_eq!(graph.degree(0), 1);
922 assert_eq!(graph.degree(1), 1);
923
924 assert_eq!(graph.order(), 2);
925
926 graph.remove_edge(0, 1);
927
928 assert_eq!(graph.degree(0), 0);
929 assert_eq!(graph.degree(1), 0);
930 assert_eq!(graph.order(), 2);
931 }
932
933 #[test]
934 fn cut_vertex() {
935 let mut graph = HashMapGraph::new();
936 graph.add_edge(0, 1);
937 graph.add_edge(1, 2);
938 graph.add_edge(0, 2);
939
940 graph.add_edge(3, 4);
941 graph.add_edge(4, 5);
942 graph.add_edge(3, 5);
943
944 graph.add_edge(1, 4);
945 graph.add_edge(1, 5);
946
947 let separator = graph.find_cut_vertex();
948 assert!(separator.is_some());
949 let separator = separator.unwrap();
950 assert_eq!(separator.len(), 1);
951 assert!(separator.contains(&1));
952 assert!(graph.separate(&separator).len() > 1);
953 }
954
955 #[test]
956 fn no_cut_vertex() {
957 let mut graph = HashMapGraph::new();
958 graph.add_edge(0, 1);
959 graph.add_edge(1, 2);
960 graph.add_edge(0, 2);
961
962 graph.add_edge(3, 4);
963 graph.add_edge(4, 5);
964 graph.add_edge(3, 5);
965
966 graph.add_edge(0, 3);
967 graph.add_edge(1, 4);
968
969 let cut_vertex = graph.find_cut_vertex();
970 assert!(cut_vertex.is_none());
971 }
972
973 #[test]
974 fn safe_bi_connected_separator() {
975 let mut graph = HashMapGraph::new();
976 graph.add_edge(0, 1);
977 graph.add_edge(0, 2);
978 graph.add_edge(0, 5);
979
980 graph.add_edge(1, 2);
981 graph.add_edge(1, 5);
982
983 graph.add_edge(2, 3);
984 graph.add_edge(2, 4);
985 graph.add_edge(2, 5);
986
987 graph.add_edge(3, 4);
988 graph.add_edge(3, 5);
989
990 graph.add_edge(4, 5);
991
992 let separator = graph.find_safe_bi_connected_separator();
993 assert!(separator.is_some());
994 let separator = separator.unwrap();
995 assert_eq!(separator.len(), 2);
996 assert!(separator.contains(&2));
997 assert!(separator.contains(&5));
998 assert!(graph.separate(&separator).len() > 1);
999 }
1000
1001 #[test]
1002 fn no_safe_bi_connected_separator() {
1003 let mut graph = HashMapGraph::new();
1004 graph.add_edge(0, 1);
1005 graph.add_edge(0, 2);
1006 graph.add_edge(0, 4);
1007 graph.add_edge(0, 5);
1008
1009 graph.add_edge(1, 2);
1010 graph.add_edge(1, 5);
1011
1012 graph.add_edge(2, 3);
1013 graph.add_edge(2, 4);
1014 graph.add_edge(2, 5);
1015
1016 graph.add_edge(3, 4);
1017 graph.add_edge(3, 5);
1018
1019 graph.add_edge(4, 5);
1020
1021 let separator = graph.find_safe_bi_connected_separator();
1022 assert!(separator.is_none());
1023 }
1024
1025 #[test]
1026 fn safe_tri_connected_separator() {
1027 let mut graph = HashMapGraph::new();
1028 graph.add_edge(0, 1);
1029 graph.add_edge(0, 2);
1030 graph.add_edge(0, 4);
1031 graph.add_edge(0, 5);
1032
1033 graph.add_edge(1, 2);
1034 graph.add_edge(1, 5);
1035
1036 graph.add_edge(2, 3);
1037 graph.add_edge(2, 4);
1038 graph.add_edge(2, 5);
1039
1040 graph.add_edge(3, 4);
1041 graph.add_edge(3, 5);
1042
1043 graph.add_edge(4, 5);
1044
1045 let separator = graph.find_safe_tri_connected_separator();
1046 assert!(separator.is_some());
1047 let separator = separator.unwrap();
1048 assert_eq!(separator.len(), 3);
1049
1050 assert!(graph.separate(&separator).len() > 1);
1051 }
1052
1053 #[test]
1054 fn safe_clique_separator() {
1055 let mut graph = HashMapGraph::new();
1056 graph.add_edge(0, 1);
1058 graph.add_edge(0, 2);
1059 graph.add_edge(0, 3);
1060 graph.add_edge(1, 2);
1061 graph.add_edge(1, 3);
1062 graph.add_edge(2, 3);
1063
1064 graph.add_edge(10, 11);
1066 graph.add_edge(10, 12);
1067 graph.add_edge(10, 13);
1068 graph.add_edge(11, 12);
1069 graph.add_edge(11, 13);
1070 graph.add_edge(12, 13);
1071
1072 graph.add_edge(0, 10);
1074 graph.add_edge(1, 11);
1075 graph.add_edge(2, 12);
1076 graph.add_edge(3, 13);
1077
1078 graph.add_edge(100, 101);
1080 graph.add_edge(100, 102);
1081 graph.add_edge(100, 103);
1082 graph.add_edge(101, 102);
1083 graph.add_edge(101, 103);
1084 graph.add_edge(102, 103);
1085
1086 graph.add_edge(0, 100);
1088 graph.add_edge(1, 101);
1089 graph.add_edge(2, 102);
1090 graph.add_edge(3, 103);
1091
1092 let separator = graph.find_clique_minimal_separator();
1093
1094 assert!(separator.is_some());
1095 let separator = separator.unwrap();
1096 assert!(separator.contains(&0));
1097 assert!(separator.contains(&1));
1098 assert!(separator.contains(&2));
1099 assert!(separator.contains(&3));
1100 let components = graph.separate(&separator);
1101 assert!(components.len() > 1);
1102 }
1103
1104 #[test]
1105 fn safe_almost_clique_separator() {
1106 let mut graph = HashMapGraph::new();
1107 graph.add_edge(0, 1);
1109 graph.add_edge(0, 2);
1110 graph.add_edge(0, 3);
1111 graph.add_edge(1, 2);
1112 graph.add_edge(1, 3);
1113 graph.add_edge(10, 11);
1118 graph.add_edge(10, 12);
1119 graph.add_edge(10, 13);
1120 graph.add_edge(11, 12);
1121 graph.add_edge(11, 13);
1122 graph.add_edge(12, 13);
1123
1124 graph.add_edge(0, 10);
1126 graph.add_edge(1, 11);
1127 graph.add_edge(2, 12);
1128 graph.add_edge(3, 13);
1129
1130 graph.add_edge(100, 101);
1132 graph.add_edge(100, 102);
1133 graph.add_edge(100, 103);
1134 graph.add_edge(101, 102);
1135 graph.add_edge(101, 103);
1136 graph.add_edge(102, 103);
1137
1138 graph.add_edge(0, 100);
1140 graph.add_edge(1, 101);
1141 graph.add_edge(2, 102);
1142 graph.add_edge(3, 103);
1143
1144 let separator = graph.find_almost_clique_minimal_separator();
1145
1146 assert!(separator.is_some());
1147 let separator = separator.unwrap();
1148 assert!(separator.contains(&0));
1149 assert!(separator.contains(&1));
1150 assert!(separator.contains(&2));
1151 assert!(separator.contains(&3));
1152 let components = graph.separate(&separator);
1153 assert!(components.len() > 1);
1154 }
1155}