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#[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
39impl 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 #[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 #[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 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 #[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!(f, "DirectedGraph {{ ")?;
179 write!(
181 f,
182 "V = {{{}}}, ",
183 V!(self)
184 .map(|x| format!("\"{}\"", self.label(x)))
185 .join(", ")
186 )?;
187 write!(
189 f,
190 "E = {{{}}}",
191 E!(self)
192 .map(|(x, y)| format!("(\"{}\", \"{}\")", self.label(x), self.label(y)))
193 .join(", ")
194 )?;
195 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 let mut labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
229 let edges: EdgeList<_> = edges
231 .into_iter()
232 .map(|(x, y)| (x.into(), y.into()))
233 .collect();
234 labels.extend(edges.iter().cloned().flat_map(|(x, y)| [x, y]));
236
237 let order = labels.len();
239 let labels_indices: BiHashMap<_, _> = labels
241 .iter()
242 .cloned()
243 .enumerate()
244 .map(|(i, x)| (x, i))
245 .collect();
246 let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((order, order), false);
248
249 let mut size = 0;
251 for (x, y) in edges {
253 let (i, j) = (
255 *labels_indices.get_by_left(&x).unwrap(),
256 *labels_indices.get_by_left(&y).unwrap(),
257 );
258 adjacency_matrix[[i, j]] = true;
260 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 self.labels.clear();
276 self.labels_indices.clear();
278 self.adjacency_matrix = Default::default();
280 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 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 debug_assert_eq!(V!(self).len(), self.labels.len());
316 debug_assert_eq!(self.labels.len(), self.labels_indices.len());
318 debug_assert_eq!(self.labels_indices.len(), self.adjacency_matrix.nrows());
320 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 let f = self.labels_indices.contains_right(&x);
330
331 debug_assert_eq!(V!(self).any(|y| y == x), f);
333 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 let x = x.into();
345
346 if !self.labels.insert(x.clone()) {
348 return self.vertex(&x);
350 }
351
352 let i = self.labels.iter().position(|y| y == &x).unwrap();
354
355 for (j, y) in self.labels.iter().skip(i).enumerate() {
357 self.labels_indices.insert(y.clone(), i + j);
359 }
360
361 let n = self.adjacency_matrix.nrows();
363 let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((n + 1, n + 1), false);
365 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 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 self.adjacency_matrix = adjacency_matrix;
376
377 debug_assert!(self.labels.contains(&x));
379 debug_assert!(self.labels_indices.contains_left(&x));
380 debug_assert!(self
382 .labels
383 .iter()
384 .eq(self.labels_indices.left_values().sorted()));
385 debug_assert!(self
388 .labels_indices
389 .right_values()
390 .cloned()
391 .sorted()
392 .eq(0..self.labels_indices.len()));
393 debug_assert_eq!(self.labels_indices.len(), self.adjacency_matrix.nrows());
395 debug_assert!(self.adjacency_matrix.is_square());
397
398 i
400 }
401
402 fn del_vertex(&mut self, x: usize) -> bool {
403 let x_i = self.labels_indices.remove_by_right(&x);
405
406 if x_i.is_none() {
408 return false;
410 }
411
412 let (x, i) = x_i.unwrap();
414
415 self.labels.remove(&x);
417
418 for (j, y) in self.labels.iter().skip(i).enumerate() {
420 self.labels_indices.insert(y.clone(), i + j);
422 }
423
424 let n = self.adjacency_matrix.nrows();
426 let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((n - 1, n - 1), false);
428 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 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 self.adjacency_matrix = adjacency_matrix;
439
440 debug_assert!(!self.labels.contains(&x));
442 debug_assert!(!self.labels_indices.contains_left(&x));
443 debug_assert!(self
445 .labels
446 .iter()
447 .eq(self.labels_indices.left_values().sorted()));
448 debug_assert!(self
451 .labels_indices
452 .right_values()
453 .cloned()
454 .sorted()
455 .eq(0..self.labels_indices.len()));
456 debug_assert_eq!(self.labels_indices.len(), self.adjacency_matrix.nrows());
458 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 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 self.adjacency_matrix[[x, y]] {
486 return false;
488 }
489
490 self.adjacency_matrix[[x, y]] = true;
492 self.size += 1;
494
495 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 !self.adjacency_matrix[[x, y]] {
505 return false;
507 }
508
509 self.adjacency_matrix[[x, y]] = false;
511 self.size -= 1;
513
514 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 let f = self.has_edge(x, y) || self.has_edge(y, x);
529
530 debug_assert_eq!(Adj!(self, x).any(|z| z == y), f);
532
533 f
534 }
535}
536
537impl 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 let labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
558
559 let order = labels.len();
561 let labels_indices = labels
563 .iter()
564 .cloned()
565 .enumerate()
566 .map(|(i, x)| (x, i))
567 .collect();
568 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 let labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
586
587 let order = labels.len();
589 let labels_indices = labels
591 .iter()
592 .cloned()
593 .enumerate()
594 .map(|(i, x)| (x, i))
595 .collect();
596 let mut adjacency_matrix = DenseAdjacencyMatrix::from_elem((order, order), true);
598 adjacency_matrix.diag_mut().map_inplace(|x| *x = false);
600
601 let size = order * (order.saturating_sub(1));
603
604 Self {
605 labels,
606 labels_indices,
607 adjacency_matrix,
608 size,
609 }
610 }
611}
612
613impl<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 let vertices: Vec<_> = adjacency_list.keys().cloned().collect();
631 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 let labels: BTreeSet<_> = vertices.into_iter().map(|x| x.into()).collect();
652
653 if labels.len() != adjacency_matrix.nrows() {
655 return Err(E::InconsistentMatrix);
656 }
657 if !adjacency_matrix.is_square() {
659 return Err(E::NonSquareMatrix);
660 }
661
662 let labels_indices = labels
664 .iter()
665 .cloned()
666 .enumerate()
667 .map(|(i, x)| (x, i))
668 .collect();
669
670 let adjacency_matrix = adjacency_matrix.as_standard_layout().into_owned();
672
673 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 let mut dense_adjacency_matrix =
697 DenseAdjacencyMatrix::from_elem(adjacency_matrix.shape(), false);
698 for (&f, (i, j)) in adjacency_matrix.triplet_iter() {
700 dense_adjacency_matrix[[i, j]] = f;
701 }
702 Self::try_from((vertices, dense_adjacency_matrix))
704 }
705}
706
707#[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 let size = self.size * 2;
745 let (mut rows, mut cols) = (Vec::with_capacity(size), Vec::with_capacity(size));
747 for ((i, j), &f) in self.adjacency_matrix.indexed_iter() {
749 if f {
750 rows.push(i);
751 cols.push(j);
752 }
753 }
754 rows.shrink_to_fit();
756 cols.shrink_to_fit();
757 let data: Vec<_> = std::iter::repeat(true).take(rows.len()).collect();
759 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
767impl PartialEq for DirectedDenseAdjacencyMatrixGraph {
769 #[inline]
770 fn eq(&self, other: &Self) -> bool {
771 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 let lhs: HashSet<_> = V!(self).map(|x| self.label(x)).collect();
782 let rhs: HashSet<_> = V!(other).map(|x| other.label(x)).collect();
783 partial_cmp_sets!(lhs, rhs).and_then(|vertices| {
785 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 partial_cmp_sets!(lhs, rhs).and_then(|edges| {
794 match (vertices, edges) {
796 (Ordering::Greater, Ordering::Greater) => Some(Ordering::Greater),
798 (Ordering::Less, Ordering::Less) => Some(Ordering::Less),
799 (_, Ordering::Equal) => Some(vertices),
801 (Ordering::Equal, _) => Some(edges),
802 _ => None,
804 }
805 })
806 })
807 }
808}
809
810impl PartialOrdGraph for DirectedDenseAdjacencyMatrixGraph {}
811
812impl 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 let mut indices = vec![false; self.order()];
821 for x in vertices {
823 indices[x] = true;
824 }
825
826 let mut adjacency_matrix = Self::Data::from_elem(self.adjacency_matrix.dim(), false);
828 for (x, y) in edges {
830 adjacency_matrix[[x, y]] = true;
832 indices[x] = true;
834 indices[y] = true;
835 }
836
837 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 let adjacency_matrix = adjacency_matrix
849 .select(Axis(0), &indices)
850 .select(Axis(1), &indices);
851
852 let vertices = indices.into_iter().map(|x| self.label(x));
854
855 debug_assert_eq!(vertices.len(), adjacency_matrix.nrows());
857 debug_assert!(adjacency_matrix.is_square());
859
860 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 let indices: BTreeSet<_> = vertices.into_iter().collect();
870 let indices: Vec<_> = indices.into_iter().collect();
872
873 let adjacency_matrix = self
875 .adjacency_matrix
876 .select(Axis(0), &indices)
877 .select(Axis(1), &indices);
878
879 let vertices = indices.into_iter().map(|x| self.label(x));
881
882 debug_assert_eq!(vertices.len(), adjacency_matrix.nrows());
884 debug_assert!(adjacency_matrix.is_square());
886
887 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 let mut indices = vec![false; self.order()];
897
898 let mut adjacency_matrix = Self::Data::from_elem(self.adjacency_matrix.dim(), false);
900 for (x, y) in edges {
902 adjacency_matrix[[x, y]] = true;
904 indices[x] = true;
906 indices[y] = true;
907 }
908
909 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 let adjacency_matrix = adjacency_matrix
921 .select(Axis(0), &indices)
922 .select(Axis(1), &indices);
923
924 let vertices = indices.into_iter().map(|x| self.label(x));
926
927 debug_assert_eq!(vertices.len(), adjacency_matrix.nrows());
929 debug_assert!(adjacency_matrix.is_square());
931
932 Self::try_from((vertices, adjacency_matrix)).unwrap()
934 }
935}
936
937#[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 pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
951 Self {
952 g,
953 iter: {
954 let adjacency_matrix = g.deref();
956 let mut prev = Array1::from_elem((adjacency_matrix.ncols(),), false);
958 let mut curr = adjacency_matrix.column(x).to_owned();
960
961 while curr != prev {
963 prev.assign(&curr);
965 let next = adjacency_matrix & &curr;
967 let next = next.fold_axis(Axis(1), false, |acc, f| acc | f);
969 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 #[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 #[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 pub fn new(g: &'a DirectedDenseAdjacencyMatrixGraph, x: usize) -> Self {
1081 Self {
1082 g,
1083 iter: {
1084 let adjacency_matrix = g.deref();
1086 let mut prev = Array1::from_elem((adjacency_matrix.ncols(),), false);
1088 let mut curr = adjacency_matrix.row(x).to_owned();
1090
1091 while curr != prev {
1093 prev.assign(&curr);
1095 let next = &adjacency_matrix.t() & &curr;
1097 let next = next.fold_axis(Axis(1), false, |acc, f| acc | f);
1099 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 let d = self.adjacency_matrix.column(x).mapv(|f| f as usize).sum();
1166
1167 debug_assert_eq!(Pa!(self, x).count(), d);
1169
1170 d
1171 }
1172
1173 #[inline]
1174 fn out_degree(&self, x: usize) -> usize {
1175 let d = self.adjacency_matrix.row(x).mapv(|f| f as usize).sum();
1177
1178 debug_assert_eq!(Ch!(self, x).count(), d);
1180
1181 d
1182 }
1183}
1184
1185impl 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 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 let mut h = self.to_undirected();
1217 for x in V!(self) {
1219 for e in Pa!(self, x).combinations(2) {
1221 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_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}