causal_hub/graphs/structs/
directed_dense_adjacency_matrix.rs

1use std::{
2    cmp::Ordering,
3    collections::{BTreeSet, HashSet},
4    fmt::Display,
5    hash::{Hash, Hasher},
6    iter::{Enumerate, FilterMap, FusedIterator},
7    ops::{Deref, Range},
8};
9
10use bimap::BiHashMap;
11use itertools::{iproduct, Itertools};
12use ndarray::{iter::IndexedIter, prelude::*, OwnedRepr};
13use serde::{Deserialize, Serialize};
14
15use super::UndirectedDenseAdjacencyMatrixGraph;
16use crate::{
17    graphs::{
18        algorithms::traversal::{DFSEdge, DFSEdges, Traversal},
19        directions, BaseGraph, DefaultGraph, DirectedGraph, ErrorGraph as E, IntoUndirectedGraph,
20        PartialOrdGraph, PathGraph, SubGraph,
21    },
22    io::DOT,
23    models::MoralGraph,
24    prelude::BFS,
25    types::{AdjacencyList, DenseAdjacencyMatrix, EdgeList, SparseAdjacencyMatrix},
26    utils::partial_cmp_sets,
27    Adj, Ch, Pa, E, V,
28};
29
30/// Directed graph struct based on dense adjacency matrix data structure.
31#[derive(Clone, Debug, Serialize, Deserialize)]
32pub struct DirectedDenseAdjacencyMatrixGraph {
33    labels: BTreeSet<String>,
34    labels_indices: BiHashMap<String, usize>,
35    adjacency_matrix: DenseAdjacencyMatrix,
36    size: usize,
37}
38
39/* Implement BaseGraph trait. */
40impl Deref for DirectedDenseAdjacencyMatrixGraph {
41    type Target = DenseAdjacencyMatrix;
42
43    #[inline]
44    fn deref(&self) -> &Self::Target {
45        &self.adjacency_matrix
46    }
47}
48
49pub struct LabelsIterator<'a> {
50    graph: &'a DirectedDenseAdjacencyMatrixGraph,
51    iter: Range<usize>,
52}
53
54impl<'a> LabelsIterator<'a> {
55    /// Constructor.
56    #[inline]
57    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph) -> Self {
58        Self {
59            graph: g,
60            iter: Range {
61                start: 0,
62                end: g.labels.len(),
63            },
64        }
65    }
66}
67
68impl<'a> Iterator for LabelsIterator<'a> {
69    type Item = &'a str;
70
71    #[inline]
72    fn next(&mut self) -> Option<Self::Item> {
73        self.iter.next().map(|x| self.graph.label(x))
74    }
75
76    #[inline]
77    fn size_hint(&self) -> (usize, Option<usize>) {
78        self.iter.size_hint()
79    }
80}
81
82impl<'a> ExactSizeIterator for LabelsIterator<'a> {}
83
84#[allow(dead_code, clippy::type_complexity)]
85pub struct EdgesIterator<'a> {
86    g: &'a DirectedDenseAdjacencyMatrixGraph,
87    iter: FilterMap<
88        IndexedIter<'a, bool, Ix2>,
89        fn(((usize, usize), &bool)) -> Option<(usize, usize)>,
90    >,
91    size: usize,
92}
93
94impl<'a> FusedIterator for LabelsIterator<'a> {}
95
96impl<'a> EdgesIterator<'a> {
97    /// Constructor.
98    #[inline]
99    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph) -> Self {
100        Self {
101            g,
102            iter: g.indexed_iter().filter_map(|((x, y), &f)| match f {
103                true => Some((x, y)),
104                false => None,
105            }),
106            size: g.size,
107        }
108    }
109}
110
111impl<'a> Iterator for EdgesIterator<'a> {
112    type Item = (usize, usize);
113
114    #[inline]
115    fn next(&mut self) -> Option<Self::Item> {
116        self.iter.next().map(|(x, y)| {
117            // Decrement inner counter.
118            self.size -= 1;
119
120            (x, y)
121        })
122    }
123
124    #[inline]
125    fn size_hint(&self) -> (usize, Option<usize>) {
126        (self.size, Some(self.size))
127    }
128}
129
130impl<'a> ExactSizeIterator for EdgesIterator<'a> {}
131
132impl<'a> FusedIterator for EdgesIterator<'a> {}
133
134#[allow(dead_code, clippy::type_complexity)]
135pub struct AdjacentsIterator<'a> {
136    g: &'a DirectedDenseAdjacencyMatrixGraph,
137    iter: FilterMap<
138        Enumerate<<ArrayBase<OwnedRepr<bool>, Dim<[usize; 1]>> as IntoIterator>::IntoIter>,
139        fn((usize, bool)) -> Option<usize>,
140    >,
141}
142
143impl<'a> AdjacentsIterator<'a> {
144    /// Constructor.
145    #[inline]
146    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
147        Self {
148            g,
149            iter: {
150                let (row, col) = (g.row(x), g.column(x));
151
152                (&row | &col)
153                    .into_iter()
154                    .enumerate()
155                    .filter_map(|(x, f)| match f {
156                        true => Some(x),
157                        false => None,
158                    })
159            },
160        }
161    }
162}
163
164impl<'a> Iterator for AdjacentsIterator<'a> {
165    type Item = usize;
166
167    #[inline]
168    fn next(&mut self) -> Option<Self::Item> {
169        self.iter.next()
170    }
171}
172
173impl<'a> FusedIterator for AdjacentsIterator<'a> {}
174
175impl Display for DirectedDenseAdjacencyMatrixGraph {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        // Write graph type.
178        write!(f, "DirectedGraph {{ ")?;
179        // Write vertex set.
180        write!(
181            f,
182            "V = {{{}}}, ",
183            V!(self)
184                .map(|x| format!("\"{}\"", self.label(x)))
185                .join(", ")
186        )?;
187        // Write edge set.
188        write!(
189            f,
190            "E = {{{}}}",
191            E!(self)
192                .map(|(x, y)| format!("(\"{}\", \"{}\")", self.label(x), self.label(y)))
193                .join(", ")
194        )?;
195        // Write ending character.
196        write!(f, " }}")
197    }
198}
199
200impl Hash for DirectedDenseAdjacencyMatrixGraph {
201    #[inline]
202    fn hash<H: Hasher>(&self, state: &mut H) {
203        self.labels.hash(state);
204        self.adjacency_matrix.hash(state);
205    }
206}
207
208impl BaseGraph for DirectedDenseAdjacencyMatrixGraph {
209    type Data = DenseAdjacencyMatrix;
210
211    type Direction = directions::Directed;
212
213    type LabelsIter<'a> = LabelsIterator<'a>;
214
215    type VerticesIter<'a> = Range<usize>;
216
217    type EdgesIter<'a> = EdgesIterator<'a>;
218
219    type AdjacentsIter<'a> = AdjacentsIterator<'a>;
220
221    fn new<V, I, J>(vertices: I, edges: J) -> Self
222    where
223        V: Into<String>,
224        I: IntoIterator<Item = V>,
225        J: IntoIterator<Item = (V, V)>,
226    {
227        // Remove duplicated vertices labels.
228        let mut labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
229        // Map edges iterator into edge list.
230        let edges: EdgeList<_> = edges
231            .into_iter()
232            .map(|(x, y)| (x.into(), y.into()))
233            .collect();
234        // Add missing vertices from the edges.
235        labels.extend(edges.iter().cloned().flat_map(|(x, y)| [x, y]));
236
237        // Compute new graph order.
238        let order = labels.len();
239        // Map vertices labels to vertices indices.
240        let labels_indices: BiHashMap<_, _> = labels
241            .iter()
242            .cloned()
243            .enumerate()
244            .map(|(i, x)| (x, i))
245            .collect();
246        // Initialize adjacency matrix given graph order.
247        let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((order, order), false);
248
249        // Initialize the size.
250        let mut size = 0;
251        // Fill adjacency matrix given edge set.
252        for (x, y) in edges {
253            // Get associated vertices indices.
254            let (i, j) = (
255                *labels_indices.get_by_left(&x).unwrap(),
256                *labels_indices.get_by_left(&y).unwrap(),
257            );
258            // Set edge given indices.
259            adjacency_matrix[[i, j]] = true;
260            // Increment size.
261            size += 1;
262        }
263
264        Self {
265            labels,
266            labels_indices,
267            adjacency_matrix,
268            size,
269        }
270    }
271
272    #[inline]
273    fn clear(&mut self) {
274        // Clear the vertices.
275        self.labels.clear();
276        // Clear the vertices map.
277        self.labels_indices.clear();
278        // Clear the adjacency matrix.
279        self.adjacency_matrix = Default::default();
280        // Clear the size.
281        self.size = 0;
282    }
283
284    #[inline]
285    fn label(&self, x: usize) -> &str {
286        self.labels_indices
287            .get_by_right(&x)
288            .unwrap_or_else(|| panic!("No vertex with label `{x}`"))
289    }
290
291    #[inline]
292    fn labels(&self) -> Self::LabelsIter<'_> {
293        Self::LabelsIter::new(self)
294    }
295
296    #[inline]
297    fn vertex(&self, x: &str) -> usize {
298        *self
299            .labels_indices
300            .get_by_left(x)
301            .unwrap_or_else(|| panic!("No vertex with identifier `{x}`"))
302    }
303
304    #[inline]
305    fn vertices(&self) -> Self::VerticesIter<'_> {
306        // Assert vertex set and vertices map are consistent.
307        debug_assert_eq!(self.labels.len(), self.labels_indices.len());
308
309        0..self.labels.len()
310    }
311
312    #[inline]
313    fn order(&self) -> usize {
314        // Check iterator consistency.
315        debug_assert_eq!(V!(self).len(), self.labels.len());
316        // Assert vertex set and vertices map are consistent.
317        debug_assert_eq!(self.labels.len(), self.labels_indices.len());
318        // Assert vertex set is consistent with adjacency matrix shape.
319        debug_assert_eq!(self.labels_indices.len(), self.adjacency_matrix.nrows());
320        // Assert adjacency matrix is square.
321        debug_assert!(self.adjacency_matrix.is_square());
322
323        self.labels.len()
324    }
325
326    #[inline]
327    fn has_vertex(&self, x: usize) -> bool {
328        // Check vertex existence.
329        let f = self.labels_indices.contains_right(&x);
330
331        // Check iterator consistency.
332        debug_assert_eq!(V!(self).any(|y| y == x), f);
333        // Assert vertex set and vertices map are consistent.
334        debug_assert_eq!(x < self.order(), f);
335
336        f
337    }
338
339    fn add_vertex<V>(&mut self, x: V) -> usize
340    where
341        V: Into<String>,
342    {
343        // Cast vertex label.
344        let x = x.into();
345
346        // If vertex was already present ...
347        if !self.labels.insert(x.clone()) {
348            // ... return early.
349            return self.vertex(&x);
350        }
351
352        // Get vertex identifier.
353        let i = self.labels.iter().position(|y| y == &x).unwrap();
354
355        // Update the vertices map after the added vertex.
356        for (j, y) in self.labels.iter().skip(i).enumerate() {
357            // Add the given vertex and increment subsequent ones by overwriting the entries.
358            self.labels_indices.insert(y.clone(), i + j);
359        }
360
361        // Compute the new size of adjacency matrix.
362        let n = self.adjacency_matrix.nrows();
363        // Allocate new adjacency matrix.
364        let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((n + 1, n + 1), false);
365        // Compute blocks.
366        let (p, q) = ([0..i, (i + 1)..(n + 1)], [0..i, i..n]);
367        let (p, q) = (iproduct!(p.clone(), p), iproduct!(q.clone(), q));
368        // Copy old adjacency matrix using blocks operations.
369        for ((p_start, p_end), (q_start, q_end)) in p.zip(q) {
370            adjacency_matrix
371                .slice_mut(s![p_start, p_end])
372                .assign(&self.adjacency_matrix.slice(s![q_start, q_end]));
373        }
374        // Replace old with new adjacency matrix.
375        self.adjacency_matrix = adjacency_matrix;
376
377        // Assert vertex has been added.
378        debug_assert!(self.labels.contains(&x));
379        debug_assert!(self.labels_indices.contains_left(&x));
380        // Assert vertex set is still consistent with vertices map.
381        debug_assert!(self
382            .labels
383            .iter()
384            .eq(self.labels_indices.left_values().sorted()));
385        // Assert vertices labels are still associated to an ordered and
386        // contiguous sequence of integers starting from zero, i.e in [0, n).
387        debug_assert!(self
388            .labels_indices
389            .right_values()
390            .cloned()
391            .sorted()
392            .eq(0..self.labels_indices.len()));
393        // Assert vertex set is still consistent with adjacency matrix shape.
394        debug_assert_eq!(self.labels_indices.len(), self.adjacency_matrix.nrows());
395        // Assert adjacency matrix is still square.
396        debug_assert!(self.adjacency_matrix.is_square());
397
398        // Return new vertex.
399        i
400    }
401
402    fn del_vertex(&mut self, x: usize) -> bool {
403        // Get vertex label and identifier.
404        let x_i = self.labels_indices.remove_by_right(&x);
405
406        // If vertex was not present ...
407        if x_i.is_none() {
408            // ... then return early.
409            return false;
410        }
411
412        // Get vertex label and identifier.
413        let (x, i) = x_i.unwrap();
414
415        // Remove vertex label.
416        self.labels.remove(&x);
417
418        // Update the vertices map after the removed vertex.
419        for (j, y) in self.labels.iter().skip(i).enumerate() {
420            // Decrement subsequent ones by overwriting the entries.
421            self.labels_indices.insert(y.clone(), i + j);
422        }
423
424        // Compute the new size of adjacency matrix.
425        let n = self.adjacency_matrix.nrows();
426        // Allocate new adjacency matrix.
427        let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((n - 1, n - 1), false);
428        // Compute blocks.
429        let (p, q) = ([0..i, i..(n - 1)], [0..i, (i + 1)..n]);
430        let (p, q) = (iproduct!(p.clone(), p), iproduct!(q.clone(), q));
431        // Copy old adjacency matrix using blocks operations.
432        for ((p_start, p_end), (q_start, q_end)) in p.zip(q) {
433            adjacency_matrix
434                .slice_mut(s![p_start, p_end])
435                .assign(&self.adjacency_matrix.slice(s![q_start, q_end]));
436        }
437        // Replace old with new adjacency matrix.
438        self.adjacency_matrix = adjacency_matrix;
439
440        // Assert vertex has been removed.
441        debug_assert!(!self.labels.contains(&x));
442        debug_assert!(!self.labels_indices.contains_left(&x));
443        // Assert vertex set is still consistent with vertices map.
444        debug_assert!(self
445            .labels
446            .iter()
447            .eq(self.labels_indices.left_values().sorted()));
448        // Assert vertices labels are still associated to an ordered and
449        // contiguous sequence of integers starting from zero, i.e in [0, n).
450        debug_assert!(self
451            .labels_indices
452            .right_values()
453            .cloned()
454            .sorted()
455            .eq(0..self.labels_indices.len()));
456        // Assert vertex set is still consistent with adjacency matrix shape.
457        debug_assert_eq!(self.labels_indices.len(), self.adjacency_matrix.nrows());
458        // Assert adjacency matrix is still square.
459        debug_assert!(self.adjacency_matrix.is_square());
460
461        true
462    }
463
464    #[inline]
465    fn edges(&self) -> Self::EdgesIter<'_> {
466        Self::EdgesIter::new(self)
467    }
468
469    #[inline]
470    fn size(&self) -> usize {
471        // Check iterator consistency.
472        debug_assert_eq!(E!(self).len(), self.size);
473
474        self.size
475    }
476
477    #[inline]
478    fn has_edge(&self, x: usize, y: usize) -> bool {
479        self.adjacency_matrix[[x, y]]
480    }
481
482    #[inline]
483    fn add_edge(&mut self, x: usize, y: usize) -> bool {
484        // If edge already exists ...
485        if self.adjacency_matrix[[x, y]] {
486            // ... return early.
487            return false;
488        }
489
490        // Add edge.
491        self.adjacency_matrix[[x, y]] = true;
492        // Increment size.
493        self.size += 1;
494
495        // Assert size counter and adjacency matrix are still consistent.
496        debug_assert_eq!(self.size, self.adjacency_matrix.mapv(|f| f as usize).sum());
497
498        true
499    }
500
501    #[inline]
502    fn del_edge(&mut self, x: usize, y: usize) -> bool {
503        // If edge does not exists ...
504        if !self.adjacency_matrix[[x, y]] {
505            // ... return early.
506            return false;
507        }
508
509        // Remove edge.
510        self.adjacency_matrix[[x, y]] = false;
511        // Decrement size.
512        self.size -= 1;
513
514        // Assert size counter and adjacency matrix are still consistent.
515        debug_assert_eq!(self.size, self.adjacency_matrix.mapv(|f| f as usize).sum());
516
517        true
518    }
519
520    #[inline]
521    fn adjacents(&self, x: usize) -> Self::AdjacentsIter<'_> {
522        Self::AdjacentsIter::new(self, x)
523    }
524
525    #[inline]
526    fn is_adjacent(&self, x: usize, y: usize) -> bool {
527        // Check using has_edge.
528        let f = self.has_edge(x, y) || self.has_edge(y, x);
529
530        // Check iterator consistency.
531        debug_assert_eq!(Adj!(self, x).any(|z| z == y), f);
532
533        f
534    }
535}
536
537/* Implement DefaultGraph trait. */
538impl Default for DirectedDenseAdjacencyMatrixGraph {
539    #[inline]
540    fn default() -> Self {
541        Self {
542            labels: Default::default(),
543            labels_indices: Default::default(),
544            adjacency_matrix: DenseAdjacencyMatrix::from_elem((0, 0), false),
545            size: 0,
546        }
547    }
548}
549
550impl DefaultGraph for DirectedDenseAdjacencyMatrixGraph {
551    fn empty<V, I>(vertices: I) -> Self
552    where
553        V: Into<String>,
554        I: IntoIterator<Item = V>,
555    {
556        // Remove duplicated vertices labels.
557        let labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
558
559        // Compute new graph order.
560        let order = labels.len();
561        // Map vertices labels to vertices indices.
562        let labels_indices = labels
563            .iter()
564            .cloned()
565            .enumerate()
566            .map(|(i, x)| (x, i))
567            .collect();
568        // Initialize adjacency matrix given graph order.
569        let adjacency_matrix = DenseAdjacencyMatrix::from_elem((order, order), false);
570
571        Self {
572            labels,
573            labels_indices,
574            adjacency_matrix,
575            size: 0,
576        }
577    }
578
579    fn complete<V, I>(vertices: I) -> Self
580    where
581        V: Into<String>,
582        I: IntoIterator<Item = V>,
583    {
584        // Remove duplicated vertices labels.
585        let labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
586
587        // Compute new graph order.
588        let order = labels.len();
589        // Map vertices labels to vertices indices.
590        let labels_indices = labels
591            .iter()
592            .cloned()
593            .enumerate()
594            .map(|(i, x)| (x, i))
595            .collect();
596        // Initialize adjacency matrix given graph order.
597        let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((order, order), true);
598        // Remove self loops.
599        adjacency_matrix.diag_mut().map_inplace(|x| *x = false);
600
601        // Compute size.
602        let size = order * (order.saturating_sub(1));
603
604        Self {
605            labels,
606            labels_indices,
607            adjacency_matrix,
608            size,
609        }
610    }
611}
612
613/* Implement TryFrom traits. */
614impl<V> From<EdgeList<V>> for DirectedDenseAdjacencyMatrixGraph
615where
616    V: Into<String>,
617{
618    #[inline]
619    fn from(edge_list: EdgeList<V>) -> Self {
620        Self::new([], edge_list)
621    }
622}
623
624impl<V> From<AdjacencyList<V>> for DirectedDenseAdjacencyMatrixGraph
625where
626    V: Clone + Into<String>,
627{
628    fn from(adjacency_list: AdjacencyList<V>) -> Self {
629        // Map into vertices.
630        let vertices: Vec<_> = adjacency_list.keys().cloned().collect();
631        // Map into edges.
632        let edges = adjacency_list
633            .into_iter()
634            .flat_map(|(x, ys)| std::iter::repeat(x).take(ys.len()).zip(ys.into_iter()));
635
636        Self::new(vertices, edges)
637    }
638}
639
640impl<V, I> TryFrom<(I, DenseAdjacencyMatrix)> for DirectedDenseAdjacencyMatrixGraph
641where
642    V: Into<String>,
643    I: IntoIterator<Item = V>,
644{
645    type Error = E;
646
647    fn try_from(
648        (vertices, adjacency_matrix): (I, DenseAdjacencyMatrix),
649    ) -> Result<Self, Self::Error> {
650        // Remove duplicated vertices labels.
651        let labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
652
653        // Check if vertex set is not consistent with given adjacency matrix.
654        if labels.len() != adjacency_matrix.nrows() {
655            return Err(E::InconsistentMatrix);
656        }
657        // Check if adjacency matrix is not square.
658        if !adjacency_matrix.is_square() {
659            return Err(E::NonSquareMatrix);
660        }
661
662        // Map vertices labels to vertices indices.
663        let labels_indices = labels
664            .iter()
665            .cloned()
666            .enumerate()
667            .map(|(i, x)| (x, i))
668            .collect();
669
670        // Cast to standard memory layout (i.e. C layout), if not already.
671        let adjacency_matrix = adjacency_matrix.as_standard_layout().into_owned();
672
673        // Compute size.
674        let size = adjacency_matrix.mapv(|f| f as usize).sum();
675
676        Ok(Self {
677            labels,
678            labels_indices,
679            adjacency_matrix,
680            size,
681        })
682    }
683}
684
685impl<V, I> TryFrom<(I, SparseAdjacencyMatrix)> for DirectedDenseAdjacencyMatrixGraph
686where
687    V: Into<String>,
688    I: IntoIterator<Item = V>,
689{
690    type Error = E;
691
692    fn try_from(
693        (vertices, adjacency_matrix): (I, SparseAdjacencyMatrix),
694    ) -> Result<Self, Self::Error> {
695        // Allocate dense adjacency matrix.
696        let mut dense_adjacency_matrix =
697            DenseAdjacencyMatrix::from_elem(adjacency_matrix.shape(), false);
698        // Fill dense adjacency matrix from sparse triplets.
699        for (&f, (i, j)) in adjacency_matrix.triplet_iter() {
700            dense_adjacency_matrix[[i, j]] = f;
701        }
702        // Delegate constructor to dense adjacency matrix constructor.
703        Self::try_from((vertices, dense_adjacency_matrix))
704    }
705}
706
707/* Implement Into traits. */
708
709#[allow(clippy::from_over_into)]
710impl Into<EdgeList<String>> for DirectedDenseAdjacencyMatrixGraph {
711    fn into(self) -> EdgeList<String> {
712        E!(self)
713            .map(|(x, y)| (self.label(x).into(), self.label(y).into()))
714            .collect()
715    }
716}
717
718#[allow(clippy::from_over_into)]
719impl Into<AdjacencyList<String>> for DirectedDenseAdjacencyMatrixGraph {
720    fn into(self) -> AdjacencyList<String> {
721        V!(self)
722            .map(|x| {
723                (
724                    self.label(x).into(),
725                    Adj!(self, x).map(|y| self.label(y).into()).collect(),
726                )
727            })
728            .collect()
729    }
730}
731
732#[allow(clippy::from_over_into)]
733impl Into<(BTreeSet<String>, DenseAdjacencyMatrix)> for DirectedDenseAdjacencyMatrixGraph {
734    #[inline]
735    fn into(self) -> (BTreeSet<String>, DenseAdjacencyMatrix) {
736        (self.labels, self.adjacency_matrix)
737    }
738}
739
740#[allow(clippy::from_over_into)]
741impl Into<(BTreeSet<String>, SparseAdjacencyMatrix)> for DirectedDenseAdjacencyMatrixGraph {
742    fn into(self) -> (BTreeSet<String>, SparseAdjacencyMatrix) {
743        // Get upper bound capacity.
744        let size = self.size * 2;
745        // Allocate triplets indices.
746        let (mut rows, mut cols) = (Vec::with_capacity(size), Vec::with_capacity(size));
747        // Build triplets indices.
748        for ((i, j), &f) in self.adjacency_matrix.indexed_iter() {
749            if f {
750                rows.push(i);
751                cols.push(j);
752            }
753        }
754        // Shrink triplets indices to actual capacity.
755        rows.shrink_to_fit();
756        cols.shrink_to_fit();
757        // Build data vector.
758        let data: Vec<_> = std::iter::repeat(true).take(rows.len()).collect();
759        // Construct sparse adjacency matrix.
760        let sparse_adjacency_matrix =
761            SparseAdjacencyMatrix::from_triplets(self.adjacency_matrix.dim(), rows, cols, data);
762
763        (self.labels, sparse_adjacency_matrix)
764    }
765}
766
767/* Implement PartialOrdGraph trait. */
768impl PartialEq for DirectedDenseAdjacencyMatrixGraph {
769    #[inline]
770    fn eq(&self, other: &Self) -> bool {
771        // Check that V(\mathcal{G}) == V(\mathcal{H}) && E(\mathcal{G}) == E(\mathcal{H}).
772        self.labels.eq(&other.labels) && self.adjacency_matrix.eq(&other.adjacency_matrix)
773    }
774}
775
776impl Eq for DirectedDenseAdjacencyMatrixGraph {}
777
778impl PartialOrd for DirectedDenseAdjacencyMatrixGraph {
779    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
780        // Compare vertices sets.
781        let lhs: HashSet<_> = V!(self).map(|x| self.label(x)).collect();
782        let rhs: HashSet<_> = V!(other).map(|x| other.label(x)).collect();
783        // If the vertices sets are comparable ...
784        partial_cmp_sets!(lhs, rhs).and_then(|vertices| {
785            // ... compare edges sets.
786            let lhs: HashSet<_> = E!(self)
787                .map(|(x, y)| (self.label(x), self.label(y)))
788                .collect();
789            let rhs: HashSet<_> = E!(other)
790                .map(|(x, y)| (other.label(x), other.label(y)))
791                .collect();
792            // If the edges sets are comparable ...
793            partial_cmp_sets!(lhs, rhs).and_then(|edges| {
794                // ... then return ordering.
795                match (vertices, edges) {
796                    // If vertices and edges are the same, then ordering is determined.
797                    (Ordering::Greater, Ordering::Greater) => Some(Ordering::Greater),
798                    (Ordering::Less, Ordering::Less) => Some(Ordering::Less),
799                    // If either vertices or edges are equal, the rest determines the order.
800                    (_, Ordering::Equal) => Some(vertices),
801                    (Ordering::Equal, _) => Some(edges),
802                    // Every other combination does not determine an order.
803                    _ => None,
804                }
805            })
806        })
807    }
808}
809
810impl PartialOrdGraph for DirectedDenseAdjacencyMatrixGraph {}
811
812/* Implement SubGraph trait. */
813impl SubGraph for DirectedDenseAdjacencyMatrixGraph {
814    fn subgraph<I, J>(&self, vertices: I, edges: J) -> Self
815    where
816        I: IntoIterator<Item = usize>,
817        J: IntoIterator<Item = (usize, usize)>,
818    {
819        // Initialize new indices.
820        let mut indices = vec![false; self.order()];
821        // Add the required vertices.
822        for x in vertices {
823            indices[x] = true;
824        }
825
826        // Initialize a new adjacency matrix.
827        let mut adjacency_matrix = Self::Data::from_elem(self.adjacency_matrix.dim(), false);
828        // Fill the adjacency matrix.
829        for (x, y) in edges {
830            // Add the edge.
831            adjacency_matrix[[x, y]] = true;
832            // Add the vertices.
833            indices[x] = true;
834            indices[y] = true;
835        }
836
837        // Map the indices.
838        let indices: Vec<_> = indices
839            .into_iter()
840            .enumerate()
841            .filter_map(|(i, f)| match f {
842                true => Some(i),
843                false => None,
844            })
845            .collect();
846
847        // Get minor of matrix.
848        let adjacency_matrix = adjacency_matrix
849            .select(Axis(0), &indices)
850            .select(Axis(1), &indices);
851
852        // Get vertices labels.
853        let vertices = indices.into_iter().map(|x| self.label(x));
854
855        // Assert vertex set is still consistent with adjacency matrix shape.
856        debug_assert_eq!(vertices.len(), adjacency_matrix.nrows());
857        // Assert adjacency matrix is still square.
858        debug_assert!(adjacency_matrix.is_square());
859
860        // Build subgraph from vertices and adjacency matrix.
861        Self::try_from((vertices, adjacency_matrix)).unwrap()
862    }
863
864    fn subgraph_by_vertices<I>(&self, vertices: I) -> Self
865    where
866        I: IntoIterator<Item = usize>,
867    {
868        // Remove duplicated vertices identifiers.
869        let indices: BTreeSet<_> = vertices.into_iter().collect();
870        // Cast to vector of indices.
871        let indices: Vec<_> = indices.into_iter().collect();
872
873        // Get minor of matrix.
874        let adjacency_matrix = self
875            .adjacency_matrix
876            .select(Axis(0), &indices)
877            .select(Axis(1), &indices);
878
879        // Get vertices labels.
880        let vertices = indices.into_iter().map(|x| self.label(x));
881
882        // Assert vertex set is still consistent with adjacency matrix shape.
883        debug_assert_eq!(vertices.len(), adjacency_matrix.nrows());
884        // Assert adjacency matrix is still square.
885        debug_assert!(adjacency_matrix.is_square());
886
887        // Build subgraph from vertices and adjacency matrix.
888        Self::try_from((vertices, adjacency_matrix)).unwrap()
889    }
890
891    fn subgraph_by_edges<J>(&self, edges: J) -> Self
892    where
893        J: IntoIterator<Item = (usize, usize)>,
894    {
895        // Initialize new indices.
896        let mut indices = vec![false; self.order()];
897
898        // Initialize a new adjacency matrix.
899        let mut adjacency_matrix = Self::Data::from_elem(self.adjacency_matrix.dim(), false);
900        // Fill the adjacency matrix.
901        for (x, y) in edges {
902            // Add the edge.
903            adjacency_matrix[[x, y]] = true;
904            // Add the vertices.
905            indices[x] = true;
906            indices[y] = true;
907        }
908
909        // Map the indices.
910        let indices: Vec<_> = indices
911            .into_iter()
912            .enumerate()
913            .filter_map(|(i, f)| match f {
914                true => Some(i),
915                false => None,
916            })
917            .collect();
918
919        // Get minor of matrix.
920        let adjacency_matrix = adjacency_matrix
921            .select(Axis(0), &indices)
922            .select(Axis(1), &indices);
923
924        // Get vertices labels.
925        let vertices = indices.into_iter().map(|x| self.label(x));
926
927        // Assert vertex set is still consistent with adjacency matrix shape.
928        debug_assert_eq!(vertices.len(), adjacency_matrix.nrows());
929        // Assert adjacency matrix is still square.
930        debug_assert!(adjacency_matrix.is_square());
931
932        // Build subgraph from vertices and adjacency matrix.
933        Self::try_from((vertices, adjacency_matrix)).unwrap()
934    }
935}
936
937/* Implement DirectedGraph trait. */
938
939#[allow(dead_code, clippy::type_complexity)]
940pub struct AncestorsIterator<'a> {
941    g: &'a DirectedDenseAdjacencyMatrixGraph,
942    iter: FilterMap<
943        Enumerate<<ArrayBase<OwnedRepr<bool>, Dim<[usize; 1]>> as IntoIterator>::IntoIter>,
944        fn((usize, bool)) -> Option<usize>,
945    >,
946}
947
948impl<'a> AncestorsIterator<'a> {
949    /// Constructor.
950    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
951        Self {
952            g,
953            iter: {
954                // Get underlying adjacency matrix.
955                let adjacency_matrix = g.deref();
956                // Initialize previous solution.
957                let mut prev = Array1::from_elem((adjacency_matrix.ncols(),), false);
958                // Get current ancestors set, i.e. parents set.
959                let mut curr = adjacency_matrix.column(x).to_owned();
960
961                // Check stopping criterion.
962                while curr != prev {
963                    // Update previous.
964                    prev.assign(&curr);
965                    // Select current parents.
966                    let next = adjacency_matrix & &curr;
967                    // Collapse new parents.
968                    let next = next.fold_axis(Axis(1), false, |acc, f| acc | f);
969                    // Accumulate new parents.
970                    curr = curr | next;
971                }
972
973                curr.into_iter().enumerate().filter_map(|(x, f)| match f {
974                    true => Some(x),
975                    false => None,
976                })
977            },
978        }
979    }
980}
981
982impl<'a> Iterator for AncestorsIterator<'a> {
983    type Item = usize;
984
985    #[inline]
986    fn next(&mut self) -> Option<Self::Item> {
987        self.iter.next()
988    }
989}
990
991impl<'a> FusedIterator for AncestorsIterator<'a> {}
992
993#[allow(dead_code, clippy::type_complexity)]
994pub struct ParentsIterator<'a> {
995    g: &'a DirectedDenseAdjacencyMatrixGraph,
996    iter: FilterMap<
997        Enumerate<ndarray::iter::Iter<'a, bool, Dim<[usize; 1]>>>,
998        fn((usize, &bool)) -> Option<usize>,
999    >,
1000}
1001
1002impl<'a> ParentsIterator<'a> {
1003    /// Constructor.
1004    #[inline]
1005    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
1006        Self {
1007            g,
1008            iter: g
1009                .column(x)
1010                .into_iter()
1011                .enumerate()
1012                .filter_map(|(i, &f)| match f {
1013                    true => Some(i),
1014                    false => None,
1015                }),
1016        }
1017    }
1018}
1019
1020impl<'a> Iterator for ParentsIterator<'a> {
1021    type Item = usize;
1022
1023    #[inline]
1024    fn next(&mut self) -> Option<Self::Item> {
1025        self.iter.next()
1026    }
1027}
1028
1029impl<'a> FusedIterator for ParentsIterator<'a> {}
1030
1031#[allow(dead_code, clippy::type_complexity)]
1032pub struct ChildrenIterator<'a> {
1033    g: &'a DirectedDenseAdjacencyMatrixGraph,
1034    iter: FilterMap<
1035        Enumerate<ndarray::iter::Iter<'a, bool, Dim<[usize; 1]>>>,
1036        fn((usize, &bool)) -> Option<usize>,
1037    >,
1038}
1039
1040impl<'a> ChildrenIterator<'a> {
1041    /// Constructor.
1042    #[inline]
1043    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
1044        Self {
1045            g,
1046            iter: g
1047                .row(x)
1048                .into_iter()
1049                .enumerate()
1050                .filter_map(|(i, &f)| match f {
1051                    true => Some(i),
1052                    false => None,
1053                }),
1054        }
1055    }
1056}
1057
1058impl<'a> Iterator for ChildrenIterator<'a> {
1059    type Item = usize;
1060
1061    #[inline]
1062    fn next(&mut self) -> Option<Self::Item> {
1063        self.iter.next()
1064    }
1065}
1066
1067impl<'a> FusedIterator for ChildrenIterator<'a> {}
1068
1069#[allow(dead_code, clippy::type_complexity)]
1070pub struct DescendantsIterator<'a> {
1071    g: &'a DirectedDenseAdjacencyMatrixGraph,
1072    iter: FilterMap<
1073        Enumerate<<ArrayBase<OwnedRepr<bool>, Dim<[usize; 1]>> as IntoIterator>::IntoIter>,
1074        fn((usize, bool)) -> Option<usize>,
1075    >,
1076}
1077
1078impl<'a> DescendantsIterator<'a> {
1079    /// Constructor.
1080    pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
1081        Self {
1082            g,
1083            iter: {
1084                // Get underlying adjacency matrix.
1085                let adjacency_matrix = g.deref();
1086                // Initialize previous solution.
1087                let mut prev = Array1::from_elem((adjacency_matrix.ncols(),), false);
1088                // Get current ancestors set, i.e. parents set.
1089                let mut curr = adjacency_matrix.row(x).to_owned();
1090
1091                // Check stopping criterion.
1092                while curr != prev {
1093                    // Update previous.
1094                    prev.assign(&curr);
1095                    // Select current parents.
1096                    let next = &adjacency_matrix.t() & &curr;
1097                    // Collapse new parents.
1098                    let next = next.fold_axis(Axis(1), false, |acc, f| acc | f);
1099                    // Accumulate new parents.
1100                    curr = curr | next;
1101                }
1102
1103                curr.into_iter().enumerate().filter_map(|(x, f)| match f {
1104                    true => Some(x),
1105                    false => None,
1106                })
1107            },
1108        }
1109    }
1110}
1111
1112impl<'a> Iterator for DescendantsIterator<'a> {
1113    type Item = usize;
1114
1115    #[inline]
1116    fn next(&mut self) -> Option<Self::Item> {
1117        self.iter.next()
1118    }
1119}
1120
1121impl<'a> FusedIterator for DescendantsIterator<'a> {}
1122
1123impl DirectedGraph for DirectedDenseAdjacencyMatrixGraph {
1124    type AncestorsIter<'a> = AncestorsIterator<'a>;
1125
1126    type ParentsIter<'a> = ParentsIterator<'a>;
1127
1128    type ChildrenIter<'a> = ChildrenIterator<'a>;
1129
1130    type DescendantsIter<'a> = DescendantsIterator<'a>;
1131
1132    #[inline]
1133    fn ancestors(&self, x: usize) -> Self::AncestorsIter<'_> {
1134        Self::AncestorsIter::new(self, x)
1135    }
1136
1137    #[inline]
1138    fn parents(&self, x: usize) -> Self::ParentsIter<'_> {
1139        Self::ParentsIter::new(self, x)
1140    }
1141
1142    #[inline]
1143    fn is_parent(&self, x: usize, y: usize) -> bool {
1144        self.adjacency_matrix[[y, x]]
1145    }
1146
1147    #[inline]
1148    fn children(&self, x: usize) -> Self::ChildrenIter<'_> {
1149        Self::ChildrenIter::new(self, x)
1150    }
1151
1152    #[inline]
1153    fn is_child(&self, x: usize, y: usize) -> bool {
1154        self.adjacency_matrix[[x, y]]
1155    }
1156
1157    #[inline]
1158    fn descendants(&self, x: usize) -> Self::DescendantsIter<'_> {
1159        Self::DescendantsIter::new(self, x)
1160    }
1161
1162    #[inline]
1163    fn in_degree(&self, x: usize) -> usize {
1164        // Compute in-degree.
1165        let d = self.adjacency_matrix.column(x).mapv(|f| f as usize).sum();
1166
1167        // Check iterator consistency.
1168        debug_assert_eq!(Pa!(self, x).count(), d);
1169
1170        d
1171    }
1172
1173    #[inline]
1174    fn out_degree(&self, x: usize) -> usize {
1175        // Compute out-degree.
1176        let d = self.adjacency_matrix.row(x).mapv(|f| f as usize).sum();
1177
1178        // Check iterator consistency.
1179        debug_assert_eq!(Ch!(self, x).count(), d);
1180
1181        d
1182    }
1183}
1184
1185/* Implement PathGraph */
1186impl PathGraph for DirectedDenseAdjacencyMatrixGraph {
1187    #[inline]
1188    fn has_path(&self, x: usize, y: usize) -> bool {
1189        self.has_edge(x, y) || BFS::from((self, x)).skip(1).any(|z| z == y)
1190    }
1191
1192    #[inline]
1193    fn is_acyclic(&self) -> bool {
1194        !DFSEdges::new(self, None, Traversal::Forest).any(|e| matches!(e, DFSEdge::Back(_, _)))
1195    }
1196}
1197
1198impl IntoUndirectedGraph for DirectedDenseAdjacencyMatrixGraph {
1199    type UndirectedGraph = UndirectedDenseAdjacencyMatrixGraph;
1200
1201    #[inline]
1202    fn to_undirected(&self) -> Self::UndirectedGraph {
1203        // Make the adjacent matrix symmetric.
1204        let adjacency_matrix = &self.adjacency_matrix | &self.adjacency_matrix.t();
1205
1206        Self::UndirectedGraph::try_from((self.labels.clone(), adjacency_matrix)).unwrap()
1207    }
1208}
1209
1210impl MoralGraph for DirectedDenseAdjacencyMatrixGraph {
1211    type MoralGraph = UndirectedDenseAdjacencyMatrixGraph;
1212
1213    #[inline]
1214    fn moral(&self) -> Self::MoralGraph {
1215        // Make an undirected copy of the current graph.
1216        let mut h = self.to_undirected();
1217        // For each vertex ...
1218        for x in V!(self) {
1219            // ... for each pair of parents ...
1220            for e in Pa!(self, x).combinations(2) {
1221                // ... add an edge between them.
1222                h.add_edge(e[0], e[1]);
1223            }
1224        }
1225
1226        h
1227    }
1228}
1229
1230impl From<DOT> for DirectedDenseAdjacencyMatrixGraph {
1231    #[inline]
1232    fn from(other: DOT) -> Self {
1233        // Assert graph type.
1234        assert_eq!(
1235            other.graph_type, "digraph",
1236            "DOT graph type must match direction"
1237        );
1238
1239        Self::new(other.vertices.into_keys(), other.edges.into_keys())
1240    }
1241}