1use std::collections::VecDeque;
49use std::io::Write;
50use std::ops::Range;
51
52use proptest::prelude::*;
53use proptest::strategy::ValueTree;
54use rand::distributions::Uniform;
55use rand::prelude::Distribution;
56use roaring::RoaringBitmap;
57
58use crate::delta_debugging_bitmap::DeltaDebuggingBitmapValueTree;
59use crate::strictly_upper_triangular_logical_matrix::{
60 strictly_upper_triangular_matrix_capacity, RowColumnIterator,
61 StrictlyUpperTriangularLogicalMatrix, index_from_row_column,
62};
63use crate::{TraversableDirectedGraph, Vertex};
64
65#[derive(Clone, PartialEq, Eq)]
67pub struct DirectedAcyclicGraph {
68 adjacency_matrix: StrictlyUpperTriangularLogicalMatrix,
69}
70
71impl std::fmt::Debug for DirectedAcyclicGraph {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 let ones: Vec<(Vertex, Vertex)> = self.iter_edges().collect();
74 write!(
75 f,
76 "DirectedAcyclicGraph::from_edges_iter({}, vec!{:?}.iter().cloned())",
77 self.get_vertex_count(),
78 ones
79 )?;
80 Ok(())
81 }
82}
83
84impl TraversableDirectedGraph for DirectedAcyclicGraph {
85 fn extend_with_children(&self, u: Vertex, children: &mut Vec<Vertex>) {
86 self.extend_with_children(u, children)
87 }
88
89 fn extend_with_parents(&self, v: Vertex, parents: &mut Vec<Vertex>) {
90 self.extend_with_parents(v, parents)
91 }
92}
93
94impl DirectedAcyclicGraph {
95 pub fn new(vertex_count: Vertex) -> Self {
97 Self {
98 adjacency_matrix: StrictlyUpperTriangularLogicalMatrix::zeroed(vertex_count),
99 }
100 }
101
102 pub fn from_edges_iter<I: Iterator<Item = (Vertex, Vertex)>>(vertex_count: Vertex, edges: I) -> Self {
107 let adjacency_matrix = StrictlyUpperTriangularLogicalMatrix::from_iter(vertex_count, edges);
108 Self { adjacency_matrix }
109 }
110
111 pub fn from_raw_edges(vertex_count: Vertex, edges: &[bool]) -> Self {
117 assert_eq!(
118 edges.len(),
119 usize::try_from(strictly_upper_triangular_matrix_capacity(vertex_count)).unwrap(),
120 );
121
122 let mut iter = RowColumnIterator::new(vertex_count);
123 let mut adjacency_matrix = StrictlyUpperTriangularLogicalMatrix::zeroed(vertex_count);
124 for value in edges {
125 let (row, column) = iter.next().unwrap();
126 if *value {
127 adjacency_matrix.set(row, column);
128 }
129 }
130
131 let dag = DirectedAcyclicGraph::from_adjacency_matrix(adjacency_matrix);
132 dag
133 }
134
135 pub fn from_adjacency_matrix(adjacency_matrix: StrictlyUpperTriangularLogicalMatrix) -> Self {
137 Self { adjacency_matrix }
138 }
139
140 pub fn fully_connected(vertex_count: Vertex) -> Self {
142 let mut adjacency_matrix = StrictlyUpperTriangularLogicalMatrix::zeroed(vertex_count);
143 for i in 0..vertex_count {
144 for j in (i + 1)..vertex_count {
145 adjacency_matrix.set(i, j);
146 }
147 }
148 Self { adjacency_matrix }
149 }
150
151 #[inline]
152 pub fn get_vertex_count(&self) -> Vertex {
153 self.adjacency_matrix.size()
154 }
155
156 pub fn get_edge(&self, u: Vertex, v: Vertex) -> bool {
158 assert!(u < self.get_vertex_count());
159 assert!(v < self.get_vertex_count());
160 assert!(u < v);
161 self.adjacency_matrix.get(u, v)
162 }
163
164 pub fn set_edge(&mut self, u: Vertex, v: Vertex) {
166 assert!(u < self.get_vertex_count());
167 assert!(v < self.get_vertex_count());
168 assert!(u < v);
169 self.adjacency_matrix.set(u, v);
170 }
171
172 pub fn clear_edge(&mut self, u: Vertex, v: Vertex) {
174 assert!(u < self.get_vertex_count());
175 assert!(v < self.get_vertex_count());
176 assert!(u < v);
177 self.adjacency_matrix.clear(u, v);
178 }
179
180 pub fn iter_edges(&self) -> impl Iterator<Item = (Vertex, Vertex)> + '_ {
182 self.adjacency_matrix.iter_ones()
183 }
184
185 pub fn iter_children(&self, u: Vertex) -> impl Iterator<Item = Vertex> + '_ {
188 self.adjacency_matrix.iter_ones_at_row(u)
189 }
190
191 pub fn extend_with_children(&self, u: Vertex, children: &mut Vec<Vertex>) {
192 children.extend(self.adjacency_matrix.iter_ones_at_row(u))
193 }
194
195 pub fn extend_with_parents(&self, v: Vertex, parents: &mut Vec<Vertex>) {
196 parents.extend(self.adjacency_matrix.iter_ones_at_column(v))
197 }
198
199 pub fn into_adjacency_matrix(self) -> StrictlyUpperTriangularLogicalMatrix {
201 self.adjacency_matrix
202 }
203
204 pub fn iter_descendants_dfs(&self, start_vertex: Vertex) -> Box<dyn Iterator<Item = Vertex> + '_> {
207 let iter = crate::digraph::DfsDescendantsIterator {
208 digraph: self,
209 visited: RoaringBitmap::new(),
210 to_visit: vec![start_vertex],
211 };
212 let iter = iter.filter(move |vertex| *vertex != start_vertex);
213 Box::new(iter)
214 }
215
216 pub fn iter_ancestors_dfs(&self, start_vertex: Vertex) -> Box<dyn Iterator<Item = Vertex> + '_> {
217 let iter = crate::digraph::DfsAncestorsIterator {
218 digraph: self,
219 visited: RoaringBitmap::new(),
220 to_visit: vec![start_vertex],
221 };
222 let iter = iter.filter(move |vertex| *vertex != start_vertex);
223 Box::new(iter)
224 }
225
226 pub fn iter_vertices_dfs(&self) -> Box<dyn Iterator<Item = Vertex> + '_> {
228 let iter = crate::digraph::DfsDescendantsIterator {
229 digraph: self,
230 visited: RoaringBitmap::new(),
231 to_visit: self.get_vertices_without_incoming_edges(),
232 };
233 Box::new(iter)
234 }
235
236 pub fn iter_vertices_dfs_post_order(&self) -> Box<dyn Iterator<Item = Vertex> + '_> {
239 let iter = crate::digraph::DfsPostOrderVerticesIterator {
240 digraph: self,
241 visited: RoaringBitmap::new(),
242 to_visit: self.get_vertices_without_incoming_edges(),
243 };
244 Box::new(iter)
245 }
246
247 pub fn iter_edges_dfs_post_order(&self) -> Box<dyn Iterator<Item = (Vertex, Vertex)> + '_> {
250 let iter = crate::digraph::DfsPostOrderEdgesIterator {
251 digraph: self,
252 inner: self.iter_vertices_dfs_post_order(),
253 seen_vertices: RoaringBitmap::new(),
254 buffer: Default::default(),
255 };
256 Box::new(iter)
257 }
258
259 pub fn iter_descendants_dfs_post_order(
263 &self,
264 vertex: Vertex,
265 ) -> Box<dyn Iterator<Item = Vertex> + '_> {
266 let iter = crate::digraph::DfsPostOrderVerticesIterator {
267 digraph: self,
268 visited: RoaringBitmap::new(),
269 to_visit: vec![vertex],
270 };
271 Box::new(iter)
272 }
273
274 pub fn get_topologically_ordered_vertices(&self) -> Vec<Vertex> {
277 let mut result: Vec<Vertex> = Vec::with_capacity(self.get_vertex_count().into());
278 result.extend(self.iter_vertices_dfs_post_order());
279 result.reverse();
280 result
281 }
282
283 pub fn get_descendants(&self) -> Vec<RoaringBitmap> {
285 let mut descendants: Vec<RoaringBitmap> =
286 vec![RoaringBitmap::default(); self.get_vertex_count().into()];
287
288 for u in (0..self.get_vertex_count()).rev() {
289 let mut u_descendants = RoaringBitmap::default();
290 for v in self.iter_children(u) {
291 u_descendants |= &descendants[usize::from(v)];
292 u_descendants.insert(v.into());
293 }
294 descendants[usize::try_from(u).unwrap()] = u_descendants;
295 }
296
297 descendants
298 }
299
300 pub fn transitive_reduction(&self) -> DirectedAcyclicGraph {
303 let mut result = self.clone();
304
305 let descendants = self.get_descendants();
306 for u in 0..self.get_vertex_count() {
307 for v in self.iter_children(u) {
308 for w in descendants[usize::try_from(v).unwrap()].iter() {
309 let w = Vertex::try_from(w).unwrap();
310 if w == v {
311 continue;
312 }
313 result.clear_edge(u, w);
314 }
315 }
316 }
317 result
318 }
319
320 pub fn transitive_closure(&self) -> DirectedAcyclicGraph {
323 let mut result = self.clone();
324
325 let descendants = self.get_descendants();
328 for u in 0..self.get_vertex_count() {
329 for v in descendants[usize::try_from(u).unwrap()].iter() {
330 let v = Vertex::try_from(v).unwrap();
331 result.set_edge(u, v);
332 }
333 }
334
335 result
336 }
337
338 pub fn get_vertices_without_incoming_edges(&self) -> Vec<Vertex> {
341 let incoming_edges_count = {
342 let mut incoming_edges_count: Vec<Vertex> =
343 vec![0; self.get_vertex_count().into()];
344 for (_, v) in self.iter_edges() {
345 incoming_edges_count[usize::try_from(v).unwrap()] += 1;
346 }
347 incoming_edges_count
348 };
349
350 let vertices_without_incoming_edges: Vec<Vertex> = incoming_edges_count
351 .into_iter()
352 .enumerate()
353 .filter(|(_, indegree)| *indegree == 0)
354 .map(|(vertex, _)| Vertex::try_from(vertex).unwrap())
355 .collect();
356
357 vertices_without_incoming_edges
358 }
359
360 pub fn iter_descendants_bfs(&self, vertex: Vertex) -> BfsVerticesIterator {
363 BfsVerticesIterator {
364 dag: self,
365 visited: RoaringBitmap::new(),
366 to_visit: vec![vertex].into(),
367 }
368 }
369
370 pub fn iter_vertices_bfs(&self) -> BfsVerticesIterator {
372 BfsVerticesIterator {
373 dag: self,
374 visited: RoaringBitmap::new(),
375 to_visit: self.get_vertices_without_incoming_edges().into(),
376 }
377 }
378
379 pub fn to_dot<W: Write>(&self, output: &mut W) -> std::result::Result<(), std::io::Error> {
381 writeln!(output, "digraph dag_{} {{", self.get_vertex_count())?;
382
383 for elem in 0..self.get_vertex_count() {
384 writeln!(output, "\t_{}[label=\"{}\"];", elem, elem)?;
385 }
386
387 writeln!(output, "\n")?;
388
389 for (left, right) in self.iter_edges() {
390 writeln!(output, "\t_{} -> _{};", left, right)?;
391 }
392
393 writeln!(output, "}}")?;
394 Ok(())
395 }
396
397 pub fn to_dot_file<P: AsRef<std::path::Path>>(
398 &self,
399 path: P,
400 ) -> std::result::Result<(), std::io::Error> {
401 let mut file = std::fs::File::create(path)?;
402 self.to_dot(&mut file)?;
403 Ok(())
404 }
405}
406
407pub fn arb_dag(vertex_count: impl Into<Range<Vertex>>, edge_probability: f64) -> UniformEdgeProbabilityStrategy {
408 UniformEdgeProbabilityStrategy {
409 vertex_count: vertex_count.into(),
410 edge_probability,
411 }
412}
413
414#[derive(Debug)]
415pub struct UniformEdgeProbabilityStrategy {
416 vertex_count: Range<Vertex>,
417 edge_probability: f64,
418}
419
420#[derive(Debug)]
421pub struct DirectedAcyclicGraphValueTree {
422 vertex_count: u16,
423 state: ReductionState,
424}
425
426#[derive(Debug)]
427enum ReductionState {
428 ReduceVertices {
429 vertex_mask_tree: DeltaDebuggingBitmapValueTree,
430 edge_bitmap: RoaringBitmap,
431 },
432 ReduceEdges {
433 vertex_mask: RoaringBitmap,
434 edge_bitmap_tree: DeltaDebuggingBitmapValueTree,
435 }
436}
437
438impl ReductionState {
439 fn current_vertex_mask(&self) -> RoaringBitmap {
440 match self {
441 Self::ReduceVertices { vertex_mask_tree, .. } => vertex_mask_tree.current(),
442 Self::ReduceEdges { vertex_mask, .. } => vertex_mask.clone(),
443 }
444 }
445
446 fn current_edge_bitmap(&self) -> RoaringBitmap {
447 match self {
448 Self::ReduceVertices { edge_bitmap, .. } => edge_bitmap.clone(),
449 Self::ReduceEdges { edge_bitmap_tree, .. } => edge_bitmap_tree.current(),
450 }
451 }
452}
453
454impl Strategy for UniformEdgeProbabilityStrategy {
455 type Tree = DirectedAcyclicGraphValueTree;
456
457 type Value = DirectedAcyclicGraph;
458
459 fn new_tree(
460 &self,
461 runner: &mut proptest::test_runner::TestRunner,
462 ) -> proptest::strategy::NewTree<Self> {
463 if self.vertex_count.is_empty() {
465 panic!(
466 "Invalid use of empty size range. (hint: did you \
467 accidentally write {}..{} where you meant {}..={} \
468 somewhere?)",
469 self.vertex_count.start,
470 self.vertex_count.end,
471 self.vertex_count.start,
472 self.vertex_count.end
473 );
474 }
475 let vertex_count =
476 Uniform::new(self.vertex_count.start, self.vertex_count.end - 1).sample(runner.rng());
477
478 let vertex_mask = {
479 let mut b = RoaringBitmap::new();
480 b.insert_range(0..vertex_count as u32);
481 b
482 };
483
484 let mut edge_bitmap = RoaringBitmap::new();
485 for i in 0..vertex_count {
486 for j in (i + 1)..vertex_count {
487 if runner.rng().gen_bool(self.edge_probability) {
488 edge_bitmap.insert(index_from_row_column(i, j, vertex_count));
489 }
490 }
491 }
492
493 Ok(DirectedAcyclicGraphValueTree {
494 vertex_count,
495 state: ReductionState::ReduceVertices {
496 vertex_mask_tree: DeltaDebuggingBitmapValueTree::new(vertex_mask),
497 edge_bitmap
498 }
499 })
500 }
501}
502
503impl ValueTree for DirectedAcyclicGraphValueTree {
504 type Value = DirectedAcyclicGraph;
505
506 fn current(&self) -> Self::Value {
507 let vertex_mask = self.state.current_vertex_mask();
508 let edge_map = self.state.current_edge_bitmap();
509
510 let mut from_dst = 0 as Vertex;
511 let mut edges = Vec::with_capacity(strictly_upper_triangular_matrix_capacity(
512 self.vertex_count,
513 ) as usize);
514 for from_src in 0..self.vertex_count {
515 if vertex_mask.contains(from_src as u32) {
516 let mut to_dst = from_dst + 1;
517 for to_src in from_src + 1..self.vertex_count {
518 if vertex_mask.contains(to_src as u32) {
519 let edge_idx = index_from_row_column(from_src, to_src, self.vertex_count);
520 if edge_map.contains(edge_idx) {
521 edges.push((from_dst, to_dst));
522 }
523 to_dst += 1;
524 }
525 }
526 from_dst += 1;
527 }
528 }
529
530 DirectedAcyclicGraph::from_edges_iter(vertex_mask.len() as Vertex, edges.into_iter())
531 }
532
533 fn simplify(&mut self) -> bool {
534 match &mut self.state {
535 ReductionState::ReduceVertices { vertex_mask_tree, edge_bitmap } => {
536 if !vertex_mask_tree.simplify() {
537 self.state = ReductionState::ReduceEdges {
538 vertex_mask: vertex_mask_tree.current(),
539 edge_bitmap_tree: DeltaDebuggingBitmapValueTree::new(edge_bitmap.clone()),
540 };
541 }
542 true
543 },
544 ReductionState::ReduceEdges { edge_bitmap_tree, .. } => edge_bitmap_tree.simplify(),
545 }
546 }
547
548 fn complicate(&mut self) -> bool {
549 match &mut self.state {
550 ReductionState::ReduceVertices { vertex_mask_tree, edge_bitmap } => {
551 if !vertex_mask_tree.complicate() {
552 self.state = ReductionState::ReduceEdges {
553 vertex_mask: vertex_mask_tree.current(),
554 edge_bitmap_tree: DeltaDebuggingBitmapValueTree::new(edge_bitmap.clone()),
555 };
556 }
557 true
558 },
559 ReductionState::ReduceEdges { edge_bitmap_tree, .. } => edge_bitmap_tree.complicate(),
560 }
561 }
562}
563
564pub struct BfsVerticesIterator<'a> {
566 dag: &'a DirectedAcyclicGraph,
567 visited: RoaringBitmap,
568 to_visit: VecDeque<Vertex>,
569}
570
571impl<'a> Iterator for BfsVerticesIterator<'a> {
572 type Item = Vertex;
573
574 fn next(&mut self) -> Option<Self::Item> {
575 while let Some(u) = self.to_visit.pop_front() {
576 if self.visited.contains(u.into()) {
577 continue;
578 }
579 self.visited.insert(u.into());
580 self.to_visit.extend(
581 self.dag
582 .iter_children(u)
583 .filter(|v| !self.visited.contains((*v).into())),
584 );
585 return Some(u);
586 }
587 None
588 }
589}
590
591#[cfg(test)]
592mod tests {
593 use std::{
594 borrow::Borrow,
595 collections::{BTreeMap, HashSet},
596 };
597
598 use proptest::test_runner::{TestCaseResult, TestError, TestRunner};
599
600 use super::*;
601
602 #[test]
603 #[should_panic = "assertion failed: u < v"]
604 fn negative_test_smallest_dag() {
605 let mut dag = DirectedAcyclicGraph::new(2);
606 assert_eq!(dag.get_edge(0, 0), false);
607 dag.set_edge(0, 0);
608 }
609
610 #[test]
611 fn divisibility_poset_of_12_ordered_pairs() {
612 let divisibility_poset_pairs = vec![
613 (1, 2),
614 (1, 3),
615 (1, 4),
616 (1, 5),
617 (1, 6),
618 (1, 7),
619 (1, 8),
620 (1, 9),
621 (1, 10),
622 (1, 11),
623 (1, 12),
624 (2, 4),
625 (2, 6),
626 (2, 8),
627 (2, 10),
628 (2, 12),
629 (3, 6),
630 (3, 9),
631 (3, 12),
632 (4, 8),
633 (4, 12),
634 (5, 10),
635 (6, 12),
636 ];
637 let dag =
638 DirectedAcyclicGraph::from_edges_iter(12 + 1, divisibility_poset_pairs.into_iter());
639 let dag = dag.transitive_reduction();
640
641 let dag_pairs: HashSet<(Vertex, Vertex)> = HashSet::from_iter(dag.iter_edges_dfs_post_order());
642 let expected = HashSet::from_iter(vec![
643 (3, 9),
644 (2, 6),
645 (6, 12),
646 (1, 7),
647 (1, 11),
648 (5, 10),
649 (3, 6),
650 (2, 10),
651 (1, 2),
652 (4, 12),
653 (2, 4),
654 (4, 8),
655 (1, 5),
656 (1, 3),
657 ]);
658 assert_eq!(dag_pairs, expected);
659 }
660
661 proptest! {
662 #[test]
664 fn unblocking_preserves_transitivity(mut dag in arb_dag(0..25, 0.5)) {
665 println!("{:?}", dag);
666 let mut edges: Vec<(Vertex, Vertex)> = dag.iter_edges().collect();
667 while let Some((left, right)) = edges.pop() {
668 dag.clear_edge(left, right);
669 }
670 let edges: Vec<(Vertex, Vertex)> = dag.iter_edges().collect();
671 prop_assert!(edges.is_empty());
672 }
673 }
674
675 #[derive(Clone, Debug)]
677 struct IntegerDivisibilityPoset {
678 number: Vertex,
679 divisors_of: BTreeMap<Vertex, Vec<Vertex>>,
680 }
681
682 impl IntegerDivisibilityPoset {
683 fn get_divisors(number: Vertex) -> BTreeMap<Vertex, Vec<Vertex>> {
684 let mut result: BTreeMap<Vertex, Vec<Vertex>> = Default::default();
685 let mut numbers: Vec<Vertex> = vec![number];
686 while let Some(n) = numbers.pop() {
687 let divisors_of_n: Vec<Vertex> = (1..n / 2 + 1).filter(|d| n % d == 0).rev().collect();
688 for divisor in &divisors_of_n {
689 if !result.contains_key(&divisor) {
690 numbers.push(*divisor);
691 }
692 }
693 result.insert(n, divisors_of_n);
694 }
695 result
696 }
697
698 fn of_number(number: Vertex) -> Self {
699 IntegerDivisibilityPoset {
700 number,
701 divisors_of: Self::get_divisors(number),
702 }
703 }
704
705 fn get_pairs(&self) -> Vec<(Vertex, Vertex)> {
706 let mut result = Vec::new();
707
708 for divisor in self.divisors_of.keys() {
709 result.extend(
710 self.divisors_of[&divisor]
711 .iter()
712 .map(|dividend| (*dividend, *divisor)),
713 );
714 }
715
716 result
717 }
718 }
719
720 proptest! {
721 #[test]
722 fn prop_integer_divisibility_poset_isomorphism(size in 3u32..1000u32) {
723 let integer_divisibility_poset = IntegerDivisibilityPoset::of_number(size.try_into().unwrap());
724
725 println!(
726 "{:10} {:?}",
727 integer_divisibility_poset.number, integer_divisibility_poset.divisors_of
728 );
729
730 let pairs = integer_divisibility_poset.get_pairs();
731
732 let dag = DirectedAcyclicGraph::from_edges_iter(
733 integer_divisibility_poset.number + 1,
734 pairs.iter().cloned(),
735 );
736
737 for (left, right) in pairs {
738 prop_assert!(dag.get_edge(left, right));
739 }
740
741 for (left, right) in dag.iter_edges() {
742 prop_assert_eq!(right % left, 0);
743 }
744 }
745 }
746
747 #[test]
748 fn divisibility_poset_12_children() {
749 let divisibility_poset_pairs = vec![
750 (1, 2),
751 (1, 3),
752 (1, 4),
753 (1, 5),
754 (1, 6),
755 (1, 7),
756 (1, 8),
757 (1, 9),
758 (1, 10),
759 (1, 11),
760 (1, 12),
761 (2, 4),
762 (2, 6),
763 (2, 8),
764 (2, 10),
765 (2, 12),
766 (3, 6),
767 (3, 9),
768 (3, 12),
769 (4, 8),
770 (4, 12),
771 (5, 10),
772 (6, 12),
773 ];
774 let dag =
775 DirectedAcyclicGraph::from_edges_iter(12 + 1, divisibility_poset_pairs.into_iter());
776 assert_eq!(dag.iter_children(12).collect::<Vec<Vertex>>(), vec![]);
777 assert_eq!(dag.iter_children(11).collect::<Vec<Vertex>>(), vec![]);
778 assert_eq!(dag.iter_children(9).collect::<Vec<Vertex>>(), vec![]);
779 assert_eq!(dag.iter_children(8).collect::<Vec<Vertex>>(), vec![]);
780 assert_eq!(dag.iter_children(7).collect::<Vec<Vertex>>(), vec![]);
781 assert_eq!(dag.iter_children(6).collect::<Vec<Vertex>>(), vec![12]);
782 assert_eq!(dag.iter_children(5).collect::<Vec<Vertex>>(), vec![10]);
783 assert_eq!(dag.iter_children(4).collect::<Vec<Vertex>>(), vec![8, 12]);
784 assert_eq!(dag.iter_children(3).collect::<Vec<Vertex>>(), vec![6, 9, 12]);
785 assert_eq!(
786 dag.iter_children(2).collect::<Vec<Vertex>>(),
787 vec![4, 6, 8, 10, 12]
788 );
789 assert_eq!(
790 dag.iter_children(1).collect::<Vec<Vertex>>(),
791 vec![2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
792 );
793 }
794
795 #[test]
796 fn divisibility_poset_of_12_descendants() {
797 let divisibility_poset_pairs = vec![
798 (1, 2),
799 (1, 3),
800 (1, 4),
801 (1, 5),
802 (1, 6),
803 (1, 7),
804 (1, 8),
805 (1, 9),
806 (1, 10),
807 (1, 11),
808 (1, 12),
809 (2, 4),
810 (2, 6),
811 (2, 8),
812 (2, 10),
813 (2, 12),
814 (3, 6),
815 (3, 9),
816 (3, 12),
817 (4, 8),
818 (4, 12),
819 (5, 10),
820 (6, 12),
821 ];
822 let dag =
823 DirectedAcyclicGraph::from_edges_iter(12 + 1, divisibility_poset_pairs.into_iter());
824 let descendants = dag.get_descendants();
825 assert_eq!(descendants[12], RoaringBitmap::new());
826 assert_eq!(descendants[11], RoaringBitmap::new());
827 assert_eq!(descendants[10], RoaringBitmap::new());
828 assert_eq!(descendants[9], RoaringBitmap::new());
829 assert_eq!(descendants[8], RoaringBitmap::new());
830 assert_eq!(descendants[7], RoaringBitmap::new());
831 assert_eq!(descendants[6], RoaringBitmap::from_iter(vec![12]));
832 assert_eq!(descendants[5], RoaringBitmap::from_iter(vec![10]));
833 assert_eq!(descendants[4], RoaringBitmap::from_iter(vec![8, 12]));
834 assert_eq!(descendants[3], RoaringBitmap::from_iter(vec![6, 9, 12]),);
835 assert_eq!(
836 descendants[2],
837 RoaringBitmap::from_iter(vec![4, 6, 8, 10, 12]),
838 );
839 assert_eq!(
840 descendants[1],
841 RoaringBitmap::from_iter(vec![2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
842 );
843 }
844
845 proptest! {
846 #[test]
847 fn prop_transitive_closure_and_transitive_reduction_intersection_equals_transitive_reduction_modulo_order(
848 dag in arb_dag(0..25, 0.5),
849 ) {
850 println!("{:?}", dag);
851 let transitive_closure: HashSet<(Vertex, Vertex)> =
852 dag.transitive_closure().iter_edges().collect();
853 let transitive_reduction: HashSet<(Vertex, Vertex)> =
854 dag.transitive_reduction().iter_edges().collect();
855 let intersection: HashSet<(Vertex, Vertex)> = transitive_closure
856 .intersection(&transitive_reduction)
857 .cloned()
858 .collect();
859 prop_assert_eq!(intersection, transitive_reduction);
860 }
861 }
862
863 #[test]
864 fn divisibility_poset_of_12_dfs_descendants() {
865 let divisibility_poset_pairs = vec![
866 (1, 2),
867 (1, 3),
868 (1, 4),
869 (1, 5),
870 (1, 6),
871 (1, 7),
872 (1, 8),
873 (1, 9),
874 (1, 10),
875 (1, 11),
876 (1, 12),
877 (2, 4),
878 (2, 6),
879 (2, 8),
880 (2, 10),
881 (2, 12),
882 (3, 6),
883 (3, 9),
884 (3, 12),
885 (4, 8),
886 (4, 12),
887 (5, 10),
888 (6, 12),
889 ];
890 let dag =
891 DirectedAcyclicGraph::from_edges_iter(12 + 1, divisibility_poset_pairs.into_iter());
892
893 assert_eq!(dag.iter_descendants_dfs(12).collect::<Vec<Vertex>>(), vec![]);
894 assert_eq!(dag.iter_descendants_dfs(11).collect::<Vec<Vertex>>(), vec![]);
895 assert_eq!(dag.iter_descendants_dfs(6).collect::<Vec<Vertex>>(), vec![12]);
896 }
897
898 proptest! {
899 #[test]
900 fn traversals_equal_modulo_order(dag in arb_dag(0..25, 0.5)) {
901 let bfs: HashSet<Vertex> = dag.iter_vertices_bfs().collect();
902 let dfs: HashSet<Vertex> = dag.iter_vertices_dfs().collect();
903 let dfs_post_order: HashSet<Vertex> = dag.iter_vertices_dfs_post_order().collect();
904 prop_assert_eq!(&bfs, &dfs);
905 prop_assert_eq!(&dfs_post_order, &dfs);
906 prop_assert_eq!(&dfs_post_order, &bfs);
907 }
908 }
909
910 fn fail_on_two_incoming(dag: impl Borrow<DirectedAcyclicGraph>) -> TestCaseResult {
912 for to in 0..dag.borrow().get_vertex_count() {
913 let mut count = 0;
914 for from in 0..to {
915 count += dag.borrow().get_edge(from, to) as u32;
916 if count >= 2 {
917 return Err(TestCaseError::Fail(
918 "contains an edge with two incoming".into(),
919 ));
920 }
921 }
922 }
923 Ok(())
924 }
925
926 #[test]
927 fn minify_dag_to_3_nodes() {
928 let minimal_dag = DirectedAcyclicGraph::from_edges_iter(3, vec![(0, 2), (1, 2)].into_iter());
930 assert!(fail_on_two_incoming(&minimal_dag).is_err());
931
932 let vertex_count = 10;
934 let edge_bitmap = DirectedAcyclicGraph::fully_connected(vertex_count).adjacency_matrix.into_bitset();
935 let vertex_mask = {
936 let mut b = RoaringBitmap::new();
937 b.insert_range(0..vertex_count as u32);
938 b
939 };
940
941 let full_graph_tree = DirectedAcyclicGraphValueTree {
942 vertex_count,
943 state: ReductionState::ReduceVertices {
944 vertex_mask_tree: DeltaDebuggingBitmapValueTree::new(vertex_mask),
945 edge_bitmap,
946 },
947 };
948
949 let mut runner = TestRunner::new(Default::default());
950 let result = runner.run_one(full_graph_tree, fail_on_two_incoming);
951
952 assert_eq!(
954 result,
955 Err(TestError::Fail(
956 "contains an edge with two incoming".into(),
957 minimal_dag
958 ))
959 );
960 }
961}