arboretum_td/graph/
hash_map_graph.rs

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                    // found separator size 3, check for safety (3 is safe when (almost) clique)
135                    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                    // check if graph contains vertex v with N(v) = {p, f1, f2}
146                    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                    // separates into > 2 components OR 2 components with each component containing more than 1 vertex
158                    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(&current).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        // Algorithm in 'An Introduction to Clique Minimal SeparatorDecomposition'
466        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(&current).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        // clique separator
1057        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        // component 1
1065        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        // connect component 1
1073        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        // component 2
1079        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        // connect component 2
1087        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        // almost clique separator
1108        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        // missing:
1114        // graph.add_edge(2, 3);
1115
1116        // component 1
1117        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        // connect component 1
1125        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        // component 2
1131        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        // connect component 2
1139        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}