1 #![cfg(feature = "quickcheck")]
2 #[macro_use]
3 extern crate quickcheck;
4 extern crate petgraph;
5 extern crate rand;
6 #[macro_use]
7 extern crate defmac;
8 
9 extern crate itertools;
10 extern crate odds;
11 
12 mod utils;
13 
14 use utils::{Small, Tournament};
15 
16 use odds::prelude::*;
17 use std::collections::HashSet;
18 use std::hash::Hash;
19 
20 use itertools::assert_equal;
21 use itertools::cloned;
22 use quickcheck::{Arbitrary, Gen};
23 use rand::Rng;
24 
25 use petgraph::algo::{
26     bellman_ford, condensation, dijkstra, find_negative_cycle, floyd_warshall, ford_fulkerson,
27     greedy_feedback_arc_set, greedy_matching, is_cyclic_directed, is_cyclic_undirected,
28     is_isomorphic, is_isomorphic_matching, k_shortest_path, kosaraju_scc, maximum_matching,
29     min_spanning_tree, page_rank, tarjan_scc, toposort, Matching,
30 };
31 use petgraph::data::FromElements;
32 use petgraph::dot::{Config, Dot};
33 use petgraph::graph::{edge_index, node_index, IndexType};
34 use petgraph::graphmap::NodeTrait;
35 use petgraph::operator::complement;
36 use petgraph::prelude::*;
37 use petgraph::visit::{
38     EdgeFiltered, EdgeIndexable, IntoEdgeReferences, IntoEdges, IntoNeighbors, IntoNodeIdentifiers,
39     IntoNodeReferences, NodeCount, NodeIndexable, Reversed, Topo, VisitMap, Visitable,
40 };
41 use petgraph::EdgeType;
42 
mst_graph<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> Graph<N, E, Undirected, Ix> where Ty: EdgeType, Ix: IndexType, N: Clone, E: Clone + PartialOrd,43 fn mst_graph<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> Graph<N, E, Undirected, Ix>
44 where
45     Ty: EdgeType,
46     Ix: IndexType,
47     N: Clone,
48     E: Clone + PartialOrd,
49 {
50     Graph::from_elements(min_spanning_tree(&g))
51 }
52 
53 use std::fmt;
54 
55 quickcheck! {
56     fn mst_directed(g: Small<Graph<(), u32>>) -> bool {
57         // filter out isolated nodes
58         let no_singles = g.filter_map(
59             |nx, w| g.neighbors_undirected(nx).next().map(|_| w),
60             |_, w| Some(w));
61         for i in no_singles.node_indices() {
62             assert!(no_singles.neighbors_undirected(i).count() > 0);
63         }
64         assert_eq!(no_singles.edge_count(), g.edge_count());
65         let mst = mst_graph(&no_singles);
66         assert!(!is_cyclic_undirected(&mst));
67         true
68     }
69 }
70 
71 quickcheck! {
72     fn mst_undirected(g: Graph<(), u32, Undirected>) -> bool {
73         // filter out isolated nodes
74         let no_singles = g.filter_map(
75             |nx, w| g.neighbors_undirected(nx).next().map(|_| w),
76             |_, w| Some(w));
77         for i in no_singles.node_indices() {
78             assert!(no_singles.neighbors_undirected(i).count() > 0);
79         }
80         assert_eq!(no_singles.edge_count(), g.edge_count());
81         let mst = mst_graph(&no_singles);
82         assert!(!is_cyclic_undirected(&mst));
83         true
84     }
85 }
86 
87 quickcheck! {
88     fn reverse_undirected(g: Small<UnGraph<(), ()>>) -> bool {
89         let mut h = (*g).clone();
90         h.reverse();
91         is_isomorphic(&*g, &h)
92     }
93 }
94 
assert_graph_consistent<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) where Ty: EdgeType, Ix: IndexType,95 fn assert_graph_consistent<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>)
96 where
97     Ty: EdgeType,
98     Ix: IndexType,
99 {
100     assert_eq!(g.node_count(), g.node_indices().count());
101     assert_eq!(g.edge_count(), g.edge_indices().count());
102     for edge in g.raw_edges() {
103         assert!(
104             g.find_edge(edge.source(), edge.target()).is_some(),
105             "Edge not in graph! {:?} to {:?}",
106             edge.source(),
107             edge.target()
108         );
109     }
110 }
111 
112 #[test]
reverse_directed()113 fn reverse_directed() {
114     fn prop<Ty: EdgeType>(mut g: Graph<(), (), Ty>) -> bool {
115         let node_outdegrees = g
116             .node_indices()
117             .map(|i| g.neighbors_directed(i, Outgoing).count())
118             .collect::<Vec<_>>();
119         let node_indegrees = g
120             .node_indices()
121             .map(|i| g.neighbors_directed(i, Incoming).count())
122             .collect::<Vec<_>>();
123 
124         g.reverse();
125         let new_outdegrees = g
126             .node_indices()
127             .map(|i| g.neighbors_directed(i, Outgoing).count())
128             .collect::<Vec<_>>();
129         let new_indegrees = g
130             .node_indices()
131             .map(|i| g.neighbors_directed(i, Incoming).count())
132             .collect::<Vec<_>>();
133         assert_eq!(node_outdegrees, new_indegrees);
134         assert_eq!(node_indegrees, new_outdegrees);
135         assert_graph_consistent(&g);
136         true
137     }
138     quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
139 }
140 
141 #[test]
graph_retain_nodes()142 fn graph_retain_nodes() {
143     fn prop<Ty: EdgeType>(mut g: Graph<i32, i32, Ty>) -> bool {
144         // Remove all negative nodes, these should be randomly spread
145         let og = g.clone();
146         let nodes = g.node_count();
147         let num_negs = g.raw_nodes().iter().filter(|n| n.weight < 0).count();
148         let mut removed = 0;
149         g.retain_nodes(|g, i| {
150             let keep = g[i] >= 0;
151             if !keep {
152                 removed += 1;
153             }
154             keep
155         });
156         let num_negs_post = g.raw_nodes().iter().filter(|n| n.weight < 0).count();
157         let num_pos_post = g.raw_nodes().iter().filter(|n| n.weight >= 0).count();
158         assert_eq!(num_negs_post, 0);
159         assert_eq!(removed, num_negs);
160         assert_eq!(num_negs + g.node_count(), nodes);
161         assert_eq!(num_pos_post, g.node_count());
162 
163         // check against filter_map
164         let filtered = og.filter_map(
165             |_, w| if *w >= 0 { Some(*w) } else { None },
166             |_, w| Some(*w),
167         );
168         assert_eq!(g.node_count(), filtered.node_count());
169         /*
170         println!("Iso of graph with nodes={}, edges={}",
171                  g.node_count(), g.edge_count());
172                  */
173         assert!(is_isomorphic_matching(
174             &filtered,
175             &g,
176             PartialEq::eq,
177             PartialEq::eq
178         ));
179 
180         true
181     }
182     quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
183     quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
184 }
185 
186 #[test]
graph_retain_edges()187 fn graph_retain_edges() {
188     fn prop<Ty: EdgeType>(mut g: Graph<(), i32, Ty>) -> bool {
189         // Remove all negative edges, these should be randomly spread
190         let og = g.clone();
191         let edges = g.edge_count();
192         let num_negs = g.raw_edges().iter().filter(|n| n.weight < 0).count();
193         let mut removed = 0;
194         g.retain_edges(|g, i| {
195             let keep = g[i] >= 0;
196             if !keep {
197                 removed += 1;
198             }
199             keep
200         });
201         let num_negs_post = g.raw_edges().iter().filter(|n| n.weight < 0).count();
202         let num_pos_post = g.raw_edges().iter().filter(|n| n.weight >= 0).count();
203         assert_eq!(num_negs_post, 0);
204         assert_eq!(removed, num_negs);
205         assert_eq!(num_negs + g.edge_count(), edges);
206         assert_eq!(num_pos_post, g.edge_count());
207         if og.edge_count() < 30 {
208             // check against filter_map
209             let filtered = og.filter_map(
210                 |_, w| Some(*w),
211                 |_, w| if *w >= 0 { Some(*w) } else { None },
212             );
213             assert_eq!(g.node_count(), filtered.node_count());
214             assert!(is_isomorphic(&filtered, &g));
215         }
216         true
217     }
218     quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
219     quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
220 }
221 
222 #[test]
stable_graph_retain_edges()223 fn stable_graph_retain_edges() {
224     fn prop<Ty: EdgeType>(mut g: StableGraph<(), i32, Ty>) -> bool {
225         // Remove all negative edges, these should be randomly spread
226         let og = g.clone();
227         let edges = g.edge_count();
228         let num_negs = g.edge_references().filter(|n| *n.weight() < 0).count();
229         let mut removed = 0;
230         g.retain_edges(|g, i| {
231             let keep = g[i] >= 0;
232             if !keep {
233                 removed += 1;
234             }
235             keep
236         });
237         let num_negs_post = g.edge_references().filter(|n| *n.weight() < 0).count();
238         let num_pos_post = g.edge_references().filter(|n| *n.weight() >= 0).count();
239         assert_eq!(num_negs_post, 0);
240         assert_eq!(removed, num_negs);
241         assert_eq!(num_negs + g.edge_count(), edges);
242         assert_eq!(num_pos_post, g.edge_count());
243         if og.edge_count() < 30 {
244             // check against filter_map
245             let filtered = og.filter_map(
246                 |_, w| Some(*w),
247                 |_, w| if *w >= 0 { Some(*w) } else { None },
248             );
249             assert_eq!(g.node_count(), filtered.node_count());
250         }
251         true
252     }
253     quickcheck::quickcheck(prop as fn(StableGraph<_, _, Directed>) -> bool);
254     quickcheck::quickcheck(prop as fn(StableGraph<_, _, Undirected>) -> bool);
255 }
256 
257 #[test]
isomorphism_1()258 fn isomorphism_1() {
259     // using small weights so that duplicates are likely
260     fn prop<Ty: EdgeType>(g: Small<Graph<i8, i8, Ty>>) -> bool {
261         let mut rng = rand::thread_rng();
262         // several trials of different isomorphisms of the same graph
263         // mapping of node indices
264         let mut map = g.node_indices().collect::<Vec<_>>();
265         let mut ng = Graph::<_, _, Ty>::with_capacity(g.node_count(), g.edge_count());
266         for _ in 0..1 {
267             rng.shuffle(&mut map);
268             ng.clear();
269 
270             for _ in g.node_indices() {
271                 ng.add_node(0);
272             }
273             // Assign node weights
274             for i in g.node_indices() {
275                 ng[map[i.index()]] = g[i];
276             }
277             // Add edges
278             for i in g.edge_indices() {
279                 let (s, t) = g.edge_endpoints(i).unwrap();
280                 ng.add_edge(map[s.index()], map[t.index()], g[i]);
281             }
282             if g.node_count() < 20 && g.edge_count() < 50 {
283                 assert!(is_isomorphic(&*g, &ng));
284             }
285             assert!(is_isomorphic_matching(
286                 &*g,
287                 &ng,
288                 PartialEq::eq,
289                 PartialEq::eq
290             ));
291         }
292         true
293     }
294     quickcheck::quickcheck(prop::<Undirected> as fn(_) -> bool);
295     quickcheck::quickcheck(prop::<Directed> as fn(_) -> bool);
296 }
297 
298 #[test]
isomorphism_modify()299 fn isomorphism_modify() {
300     // using small weights so that duplicates are likely
301     fn prop<Ty: EdgeType>(g: Small<Graph<i16, i8, Ty>>, node: u8, edge: u8) -> bool {
302         println!("graph {:#?}", g);
303         let mut ng = (*g).clone();
304         let i = node_index(node as usize);
305         let j = edge_index(edge as usize);
306         if i.index() < g.node_count() {
307             ng[i] = (g[i] == 0) as i16;
308         }
309         if j.index() < g.edge_count() {
310             ng[j] = (g[j] == 0) as i8;
311         }
312         if i.index() < g.node_count() || j.index() < g.edge_count() {
313             assert!(!is_isomorphic_matching(
314                 &*g,
315                 &ng,
316                 PartialEq::eq,
317                 PartialEq::eq
318             ));
319         } else {
320             assert!(is_isomorphic_matching(
321                 &*g,
322                 &ng,
323                 PartialEq::eq,
324                 PartialEq::eq
325             ));
326         }
327         true
328     }
329     quickcheck::quickcheck(prop::<Undirected> as fn(_, _, _) -> bool);
330     quickcheck::quickcheck(prop::<Directed> as fn(_, _, _) -> bool);
331 }
332 
333 #[test]
graph_remove_edge()334 fn graph_remove_edge() {
335     fn prop<Ty: EdgeType>(mut g: Graph<(), (), Ty>, a: u8, b: u8) -> bool {
336         let a = node_index(a as usize);
337         let b = node_index(b as usize);
338         let edge = g.find_edge(a, b);
339         if !g.is_directed() {
340             assert_eq!(edge.is_some(), g.find_edge(b, a).is_some());
341         }
342         if let Some(ex) = edge {
343             assert!(g.remove_edge(ex).is_some());
344         }
345         assert_graph_consistent(&g);
346         assert!(g.find_edge(a, b).is_none());
347         assert!(g.neighbors(a).find(|x| *x == b).is_none());
348         if !g.is_directed() {
349             assert!(g.neighbors(b).find(|x| *x == a).is_none());
350         }
351         true
352     }
353     quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>, _, _) -> bool);
354     quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>, _, _) -> bool);
355 }
356 
357 #[cfg(feature = "stable_graph")]
358 #[test]
stable_graph_remove_edge()359 fn stable_graph_remove_edge() {
360     fn prop<Ty: EdgeType>(mut g: StableGraph<(), (), Ty>, a: u8, b: u8) -> bool {
361         let a = node_index(a as usize);
362         let b = node_index(b as usize);
363         let edge = g.find_edge(a, b);
364         if !g.is_directed() {
365             assert_eq!(edge.is_some(), g.find_edge(b, a).is_some());
366         }
367         if let Some(ex) = edge {
368             assert!(g.remove_edge(ex).is_some());
369         }
370         //assert_graph_consistent(&g);
371         assert!(g.find_edge(a, b).is_none());
372         assert!(g.neighbors(a).find(|x| *x == b).is_none());
373         if !g.is_directed() {
374             assert!(g.find_edge(b, a).is_none());
375             assert!(g.neighbors(b).find(|x| *x == a).is_none());
376         }
377         true
378     }
379     quickcheck::quickcheck(prop as fn(StableGraph<_, _, Undirected>, _, _) -> bool);
380     quickcheck::quickcheck(prop as fn(StableGraph<_, _, Directed>, _, _) -> bool);
381 }
382 
383 #[cfg(feature = "stable_graph")]
384 #[test]
stable_graph_add_remove_edges()385 fn stable_graph_add_remove_edges() {
386     fn prop<Ty: EdgeType>(mut g: StableGraph<(), (), Ty>, edges: Vec<(u8, u8)>) -> bool {
387         for &(a, b) in &edges {
388             let a = node_index(a as usize);
389             let b = node_index(b as usize);
390             let edge = g.find_edge(a, b);
391 
392             if edge.is_none() && g.contains_node(a) && g.contains_node(b) {
393                 let _index = g.add_edge(a, b, ());
394                 continue;
395             }
396 
397             if !g.is_directed() {
398                 assert_eq!(edge.is_some(), g.find_edge(b, a).is_some());
399             }
400             if let Some(ex) = edge {
401                 assert!(g.remove_edge(ex).is_some());
402             }
403             //assert_graph_consistent(&g);
404             assert!(
405                 g.find_edge(a, b).is_none(),
406                 "failed to remove edge {:?} from graph {:?}",
407                 (a, b),
408                 g
409             );
410             assert!(g.neighbors(a).find(|x| *x == b).is_none());
411             if !g.is_directed() {
412                 assert!(g.find_edge(b, a).is_none());
413                 assert!(g.neighbors(b).find(|x| *x == a).is_none());
414             }
415         }
416         true
417     }
418     quickcheck::quickcheck(prop as fn(StableGraph<_, _, Undirected>, _) -> bool);
419     quickcheck::quickcheck(prop as fn(StableGraph<_, _, Directed>, _) -> bool);
420 }
421 
assert_graphmap_consistent<N, E, Ty>(g: &GraphMap<N, E, Ty>) where Ty: EdgeType, N: NodeTrait + fmt::Debug,422 fn assert_graphmap_consistent<N, E, Ty>(g: &GraphMap<N, E, Ty>)
423 where
424     Ty: EdgeType,
425     N: NodeTrait + fmt::Debug,
426 {
427     for (a, b, _weight) in g.all_edges() {
428         assert!(
429             g.contains_edge(a, b),
430             "Edge not in graph! {:?} to {:?}",
431             a,
432             b
433         );
434         assert!(
435             g.neighbors(a).find(|x| *x == b).is_some(),
436             "Edge {:?} not in neighbor list for {:?}",
437             (a, b),
438             a
439         );
440         if !g.is_directed() {
441             assert!(
442                 g.neighbors(b).find(|x| *x == a).is_some(),
443                 "Edge {:?} not in neighbor list for {:?}",
444                 (b, a),
445                 b
446             );
447         }
448     }
449 }
450 
451 #[test]
graphmap_remove()452 fn graphmap_remove() {
453     fn prop<Ty: EdgeType>(mut g: GraphMap<i8, (), Ty>, a: i8, b: i8) -> bool {
454         //if g.edge_count() > 20 { return true; }
455         assert_graphmap_consistent(&g);
456         let contains = g.contains_edge(a, b);
457         if !g.is_directed() {
458             assert_eq!(contains, g.contains_edge(b, a));
459         }
460         assert_eq!(g.remove_edge(a, b).is_some(), contains);
461         assert!(!g.contains_edge(a, b) && g.neighbors(a).find(|x| *x == b).is_none());
462         //(g.is_directed() || g.neighbors(b).find(|x| *x == a).is_none()));
463         assert!(g.remove_edge(a, b).is_none());
464         assert_graphmap_consistent(&g);
465         true
466     }
467     quickcheck::quickcheck(prop as fn(DiGraphMap<_, _>, _, _) -> bool);
468     quickcheck::quickcheck(prop as fn(UnGraphMap<_, _>, _, _) -> bool);
469 }
470 
471 #[test]
graphmap_add_remove()472 fn graphmap_add_remove() {
473     fn prop(mut g: UnGraphMap<i8, ()>, a: i8, b: i8) -> bool {
474         assert_eq!(g.contains_edge(a, b), g.add_edge(a, b, ()).is_some());
475         g.remove_edge(a, b);
476         !g.contains_edge(a, b)
477             && g.neighbors(a).find(|x| *x == b).is_none()
478             && g.neighbors(b).find(|x| *x == a).is_none()
479     }
480     quickcheck::quickcheck(prop as fn(_, _, _) -> bool);
481 }
482 
sort_sccs<T: Ord>(v: &mut [Vec<T>])483 fn sort_sccs<T: Ord>(v: &mut [Vec<T>]) {
484     for scc in &mut *v {
485         scc.sort();
486     }
487     v.sort();
488 }
489 
490 quickcheck! {
491     fn graph_sccs(g: Graph<(), ()>) -> bool {
492         let mut sccs = kosaraju_scc(&g);
493         let mut tsccs = tarjan_scc(&g);
494         sort_sccs(&mut sccs);
495         sort_sccs(&mut tsccs);
496         if sccs != tsccs {
497             println!("{:?}",
498                      Dot::with_config(&g, &[Config::EdgeNoLabel,
499                                       Config::NodeIndexLabel]));
500             println!("Sccs {:?}", sccs);
501             println!("Sccs (Tarjan) {:?}", tsccs);
502             return false;
503         }
504         true
505     }
506 }
507 
508 quickcheck! {
509     fn kosaraju_scc_is_topo_sort(g: Graph<(), ()>) -> bool {
510         let tsccs = kosaraju_scc(&g);
511         let firsts = tsccs.iter().rev().map(|v| v[0]).collect::<Vec<_>>();
512         subset_is_topo_order(&g, &firsts)
513     }
514 }
515 
516 quickcheck! {
517     fn tarjan_scc_is_topo_sort(g: Graph<(), ()>) -> bool {
518         let tsccs = tarjan_scc(&g);
519         let firsts = tsccs.iter().rev().map(|v| v[0]).collect::<Vec<_>>();
520         subset_is_topo_order(&g, &firsts)
521     }
522 }
523 
524 quickcheck! {
525     // Reversed edges gives the same sccs (when sorted)
526     fn graph_reverse_sccs(g: Graph<(), ()>) -> bool {
527         let mut sccs = kosaraju_scc(&g);
528         let mut tsccs = kosaraju_scc(Reversed(&g));
529         sort_sccs(&mut sccs);
530         sort_sccs(&mut tsccs);
531         if sccs != tsccs {
532             println!("{:?}",
533                      Dot::with_config(&g, &[Config::EdgeNoLabel,
534                                       Config::NodeIndexLabel]));
535             println!("Sccs {:?}", sccs);
536             println!("Sccs (Reversed) {:?}", tsccs);
537             return false;
538         }
539         true
540     }
541 }
542 
543 quickcheck! {
544     // Reversed edges gives the same sccs (when sorted)
545     fn graphmap_reverse_sccs(g: DiGraphMap<u16, ()>) -> bool {
546         let mut sccs = kosaraju_scc(&g);
547         let mut tsccs = kosaraju_scc(Reversed(&g));
548         sort_sccs(&mut sccs);
549         sort_sccs(&mut tsccs);
550         if sccs != tsccs {
551             println!("{:?}",
552                      Dot::with_config(&g, &[Config::EdgeNoLabel,
553                                       Config::NodeIndexLabel]));
554             println!("Sccs {:?}", sccs);
555             println!("Sccs (Reversed) {:?}", tsccs);
556             return false;
557         }
558         true
559     }
560 }
561 
562 #[test]
graph_condensation_acyclic()563 fn graph_condensation_acyclic() {
564     fn prop(g: Graph<(), ()>) -> bool {
565         !is_cyclic_directed(&condensation(g, /* make_acyclic */ true))
566     }
567     quickcheck::quickcheck(prop as fn(_) -> bool);
568 }
569 
570 #[derive(Debug, Clone)]
571 struct DAG<N: Default + Clone + Send + 'static>(Graph<N, ()>);
572 
573 impl<N: Default + Clone + Send + 'static> Arbitrary for DAG<N> {
arbitrary<G: Gen>(g: &mut G) -> Self574     fn arbitrary<G: Gen>(g: &mut G) -> Self {
575         let nodes = usize::arbitrary(g);
576         if nodes == 0 {
577             return DAG(Graph::with_capacity(0, 0));
578         }
579         let split = g.gen_range(0., 1.);
580         let max_width = f64::sqrt(nodes as f64) as usize;
581         let tall = (max_width as f64 * split) as usize;
582         let fat = max_width - tall;
583 
584         let edge_prob = 1. - (1. - g.gen_range(0., 1.)) * (1. - g.gen_range(0., 1.));
585         let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
586         let mut gr = Graph::with_capacity(nodes, edges);
587         let mut nodes = 0;
588         for _ in 0..tall {
589             let cur_nodes = g.gen_range(0, fat);
590             for _ in 0..cur_nodes {
591                 gr.add_node(N::default());
592             }
593             for j in 0..nodes {
594                 for k in 0..cur_nodes {
595                     if g.gen_range(0., 1.) < edge_prob {
596                         gr.add_edge(NodeIndex::new(j), NodeIndex::new(k + nodes), ());
597                     }
598                 }
599             }
600             nodes += cur_nodes;
601         }
602         DAG(gr)
603     }
604 
605     // shrink the graph by splitting it in two by a very
606     // simple algorithm, just even and odd node indices
shrink(&self) -> Box<dyn Iterator<Item = Self>>607     fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
608         let self_ = self.clone();
609         Box::new((0..2).filter_map(move |x| {
610             let gr = self_.0.filter_map(
611                 |i, w| {
612                     if i.index() % 2 == x {
613                         Some(w.clone())
614                     } else {
615                         None
616                     }
617                 },
618                 |_, w| Some(w.clone()),
619             );
620             // make sure we shrink
621             if gr.node_count() < self_.0.node_count() {
622                 Some(DAG(gr))
623             } else {
624                 None
625             }
626         }))
627     }
628 }
629 
is_topo_order<N>(gr: &Graph<N, (), Directed>, order: &[NodeIndex]) -> bool630 fn is_topo_order<N>(gr: &Graph<N, (), Directed>, order: &[NodeIndex]) -> bool {
631     if gr.node_count() != order.len() {
632         println!(
633             "Graph ({}) and count ({}) had different amount of nodes.",
634             gr.node_count(),
635             order.len()
636         );
637         return false;
638     }
639     // check all the edges of the graph
640     for edge in gr.raw_edges() {
641         let a = edge.source();
642         let b = edge.target();
643         let ai = order.find(&a).unwrap();
644         let bi = order.find(&b).unwrap();
645         if ai >= bi {
646             println!("{:?} > {:?} ", a, b);
647             return false;
648         }
649     }
650     true
651 }
652 
subset_is_topo_order<N>(gr: &Graph<N, (), Directed>, order: &[NodeIndex]) -> bool653 fn subset_is_topo_order<N>(gr: &Graph<N, (), Directed>, order: &[NodeIndex]) -> bool {
654     if gr.node_count() < order.len() {
655         println!(
656             "Graph (len={}) had less nodes than order (len={})",
657             gr.node_count(),
658             order.len()
659         );
660         return false;
661     }
662     // check all the edges of the graph
663     for edge in gr.raw_edges() {
664         let a = edge.source();
665         let b = edge.target();
666         if a == b {
667             continue;
668         }
669         // skip those that are not in the subset
670         let ai = match order.find(&a) {
671             Some(i) => i,
672             None => continue,
673         };
674         let bi = match order.find(&b) {
675             Some(i) => i,
676             None => continue,
677         };
678         if ai >= bi {
679             println!("{:?} > {:?} ", a, b);
680             return false;
681         }
682     }
683     true
684 }
685 
686 #[test]
full_topo()687 fn full_topo() {
688     fn prop(DAG(gr): DAG<()>) -> bool {
689         let order = toposort(&gr, None).unwrap();
690         is_topo_order(&gr, &order)
691     }
692     quickcheck::quickcheck(prop as fn(_) -> bool);
693 }
694 
695 #[test]
full_topo_generic()696 fn full_topo_generic() {
697     fn prop_generic(DAG(mut gr): DAG<usize>) -> bool {
698         assert!(!is_cyclic_directed(&gr));
699         let mut index = 0;
700         let mut topo = Topo::new(&gr);
701         while let Some(nx) = topo.next(&gr) {
702             gr[nx] = index;
703             index += 1;
704         }
705 
706         let mut order = Vec::new();
707         index = 0;
708         let mut topo = Topo::new(&gr);
709         while let Some(nx) = topo.next(&gr) {
710             order.push(nx);
711             assert_eq!(gr[nx], index);
712             index += 1;
713         }
714         if !is_topo_order(&gr, &order) {
715             println!("{:?}", gr);
716             return false;
717         }
718 
719         {
720             order.clear();
721             let mut topo = Topo::new(&gr);
722             while let Some(nx) = topo.next(&gr) {
723                 order.push(nx);
724             }
725             if !is_topo_order(&gr, &order) {
726                 println!("{:?}", gr);
727                 return false;
728             }
729         }
730 
731         {
732             order.clear();
733             let init_nodes = gr.node_identifiers().filter(|n| {
734                 gr.neighbors_directed(n.clone(), Direction::Incoming)
735                     .next()
736                     .is_none()
737             });
738             let mut topo = Topo::with_initials(&gr, init_nodes);
739             while let Some(nx) = topo.next(&gr) {
740                 order.push(nx);
741             }
742             if !is_topo_order(&gr, &order) {
743                 println!("{:?}", gr);
744                 return false;
745             }
746         }
747 
748         {
749             order.clear();
750             let mut topo = Topo::with_initials(&gr, gr.node_identifiers());
751             while let Some(nx) = topo.next(&gr) {
752                 order.push(nx);
753             }
754             if !is_topo_order(&gr, &order) {
755                 println!("{:?}", gr);
756                 return false;
757             }
758         }
759         true
760     }
761     quickcheck::quickcheck(prop_generic as fn(_) -> bool);
762 }
763 
764 quickcheck! {
765     // checks that the distances computed by dijkstra satisfy the triangle
766     // inequality.
767     fn dijkstra_triangle_ineq(g: Graph<u32, u32>, node: usize) -> bool {
768         if g.node_count() == 0 {
769             return true;
770         }
771         let v = node_index(node % g.node_count());
772         let distances = dijkstra(&g, v, None, |e| *e.weight());
773         for v2 in distances.keys() {
774             let dv2 = distances[v2];
775             // triangle inequality:
776             // d(v,u) <= d(v,v2) + w(v2,u)
777             for edge in g.edges(*v2) {
778                 let u = edge.target();
779                 let w = edge.weight();
780                 if distances.contains_key(&u) && distances[&u] > dv2 + w {
781                     return false;
782                 }
783             }
784         }
785         true
786     }
787 }
788 
789 quickcheck! {
790     // checks that the distances computed by k'th shortest path is always greater or equal compared to their dijkstra computation
791     fn k_shortest_path_(g: Graph<u32, u32>, node: usize) -> bool {
792         if g.node_count() == 0 {
793             return true;
794         }
795         let v = node_index(node % g.node_count());
796         let second_best_distances = k_shortest_path(&g, v, None, 2, |e| *e.weight());
797         let dijkstra_distances = dijkstra(&g, v, None, |e| *e.weight());
798         for v in second_best_distances.keys() {
799             if second_best_distances[&v] < dijkstra_distances[&v] {
800                 return false;
801             }
802         }
803         true
804     }
805 }
806 
807 quickcheck! {
808     // checks floyd_warshall against dijkstra results
809     fn floyd_warshall_(g: Graph<u32, u32>) -> bool {
810         if g.node_count() == 0 {
811             return true;
812         }
813 
814         let fw_res = floyd_warshall(&g, |e| *e.weight()).unwrap();
815 
816         for node1 in g.node_identifiers() {
817             let dijkstra_res = dijkstra(&g, node1, None, |e| *e.weight());
818 
819             for node2 in g.node_identifiers() {
820                 // if dijkstra found a path then the results must be same
821                 if let Some(distance) = dijkstra_res.get(&node2) {
822                     let floyd_distance = fw_res.get(&(node1, node2)).unwrap();
823                     if distance != floyd_distance {
824                         return false;
825                     }
826                 } else {
827                     // if there are no path between two nodes then floyd_warshall will return maximum value possible
828                     if *fw_res.get(&(node1, node2)).unwrap() != u32::MAX {
829                         return false;
830                     }
831                 }
832             }
833          }
834         true
835     }
836 }
837 
838 quickcheck! {
839     // checks that the complement of the complement is the same as the input if the input does not contain self-loops
840     fn complement_(g: Graph<u32, u32>, _node: usize) -> bool {
841         if g.node_count() == 0 {
842             return true;
843         }
844         for x in g.node_indices() {
845             if g.contains_edge(x, x) {
846                 return true;
847             }
848         }
849         let mut complement_graph: Graph<u32, u32>  = Graph::new();
850         let mut result: Graph<u32, u32> = Graph::new();
851         complement(&g, &mut complement_graph, 0);
852         complement(&complement_graph, &mut result, 0);
853 
854         for x in g.node_indices() {
855             for y in g.node_indices() {
856                 if g.contains_edge(x, y) != result.contains_edge(x, y){
857                     return false;
858                 }
859             }
860         }
861         true
862     }
863 }
864 
set<I>(iter: I) -> HashSet<I::Item> where I: IntoIterator, I::Item: Hash + Eq,865 fn set<I>(iter: I) -> HashSet<I::Item>
866 where
867     I: IntoIterator,
868     I::Item: Hash + Eq,
869 {
870     iter.into_iter().collect()
871 }
872 
873 quickcheck! {
874     fn dfs_visit(gr: Graph<(), ()>, node: usize) -> bool {
875         use petgraph::visit::{Visitable, VisitMap};
876         use petgraph::visit::DfsEvent::*;
877         use petgraph::visit::{Time, depth_first_search};
878         if gr.node_count() == 0 {
879             return true;
880         }
881         let start_node = node_index(node % gr.node_count());
882 
883         let invalid_time = Time(!0);
884         let mut discover_time = vec![invalid_time; gr.node_count()];
885         let mut finish_time = vec![invalid_time; gr.node_count()];
886         let mut has_tree_edge = gr.visit_map();
887         let mut edges = HashSet::new();
888         depth_first_search(&gr, Some(start_node).into_iter().chain(gr.node_indices()),
889                            |evt| {
890             match evt {
891                 Discover(n, t) => discover_time[n.index()] = t,
892                 Finish(n, t) => finish_time[n.index()] = t,
893                 TreeEdge(u, v) => {
894                     // v is an ancestor of u
895                     assert!(has_tree_edge.visit(v), "Two tree edges to {:?}!", v);
896                     assert!(discover_time[v.index()] == invalid_time);
897                     assert!(discover_time[u.index()] != invalid_time);
898                     assert!(finish_time[u.index()] == invalid_time);
899                     edges.insert((u, v));
900                 }
901                 BackEdge(u, v) => {
902                     // u is an ancestor of v
903                     assert!(discover_time[v.index()] != invalid_time);
904                     assert!(finish_time[v.index()] == invalid_time);
905                     edges.insert((u, v));
906                 }
907                 CrossForwardEdge(u, v) => {
908                     edges.insert((u, v));
909                 }
910             }
911         });
912         assert!(discover_time.iter().all(|x| *x != invalid_time));
913         assert!(finish_time.iter().all(|x| *x != invalid_time));
914         assert_eq!(edges.len(), gr.edge_count());
915         assert_eq!(edges, set(gr.edge_references().map(|e| (e.source(), e.target()))));
916         true
917     }
918 }
919 
920 quickcheck! {
921     fn test_bellman_ford(gr: Graph<(), f32>) -> bool {
922         let mut gr = gr;
923         for elt in gr.edge_weights_mut() {
924             *elt = elt.abs();
925         }
926         if gr.node_count() == 0 {
927             return true;
928         }
929         for (i, start) in gr.node_indices().enumerate() {
930             if i >= 10 { break; } // testing all is too slow
931             bellman_ford(&gr, start).unwrap();
932         }
933         true
934     }
935 }
936 
937 quickcheck! {
938     fn test_find_negative_cycle(gr: Graph<(), f32>) -> bool {
939         let gr = gr;
940         if gr.node_count() == 0 {
941             return true;
942         }
943         for (i, start) in gr.node_indices().enumerate() {
944             if i >= 10 { break; } // testing all is too slow
945             if let Some(path) = find_negative_cycle(&gr, start) {
946                 assert!(path.len() >= 1);
947             }
948         }
949         true
950     }
951 }
952 
953 quickcheck! {
954     fn test_bellman_ford_undir(gr: Graph<(), f32, Undirected>) -> bool {
955         let mut gr = gr;
956         for elt in gr.edge_weights_mut() {
957             *elt = elt.abs();
958         }
959         if gr.node_count() == 0 {
960             return true;
961         }
962         for (i, start) in gr.node_indices().enumerate() {
963             if i >= 10 { break; } // testing all is too slow
964             bellman_ford(&gr, start).unwrap();
965         }
966         true
967     }
968 }
969 
970 defmac!(iter_eq a, b => a.eq(b));
971 defmac!(nodes_eq ref a, ref b => a.node_references().eq(b.node_references()));
972 defmac!(edgew_eq ref a, ref b => a.edge_references().eq(b.edge_references()));
973 defmac!(edges_eq ref a, ref b =>
974         iter_eq!(
975             a.edge_references().map(|e| (e.source(), e.target())),
976             b.edge_references().map(|e| (e.source(), e.target()))));
977 
978 quickcheck! {
979     fn test_di_from(gr1: DiGraph<i32, i32>) -> () {
980         let sgr = StableGraph::from(gr1.clone());
981         let gr2 = Graph::from(sgr);
982 
983         assert!(nodes_eq!(&gr1, &gr2));
984         assert!(edgew_eq!(&gr1, &gr2));
985         assert!(edges_eq!(&gr1, &gr2));
986     }
987     fn test_un_from(gr1: UnGraph<i32, i32>) -> () {
988         let sgr = StableGraph::from(gr1.clone());
989         let gr2 = Graph::from(sgr);
990 
991         assert!(nodes_eq!(&gr1, &gr2));
992         assert!(edgew_eq!(&gr1, &gr2));
993         assert!(edges_eq!(&gr1, &gr2));
994     }
995 
996     fn test_graph_from_stable_graph(gr1: StableDiGraph<usize, usize>) -> () {
997         let mut gr1 = gr1;
998         let gr2 = Graph::from(gr1.clone());
999 
1000         // renumber the stablegraph nodes and put the new index in the
1001         // associated data
1002         let mut index = 0;
1003         for i in 0..gr1.node_bound() {
1004             let ni = node_index(i);
1005             if gr1.contains_node(ni) {
1006                 gr1[ni] = index;
1007                 index += 1;
1008             }
1009         }
1010         if let Some(edge_bound) = gr1.edge_references().next_back()
1011             .map(|ed| ed.id().index() + 1)
1012         {
1013             index = 0;
1014             for i in 0..edge_bound {
1015                 let ni = edge_index(i);
1016                 if gr1.edge_weight(ni).is_some() {
1017                     gr1[ni] = index;
1018                     index += 1;
1019                 }
1020             }
1021         }
1022 
1023         assert_equal(
1024             // Remap the stablegraph to compact indices
1025             gr1.edge_references().map(|ed| (edge_index(*ed.weight()), gr1[ed.source()], gr1[ed.target()])),
1026             gr2.edge_references().map(|ed| (ed.id(), ed.source().index(), ed.target().index()))
1027         );
1028     }
1029 
1030     fn stable_di_graph_map_id(gr1: StableDiGraph<usize, usize>) -> () {
1031         let gr2 = gr1.map(|_, &nw| nw, |_, &ew| ew);
1032         assert!(nodes_eq!(&gr1, &gr2));
1033         assert!(edgew_eq!(&gr1, &gr2));
1034         assert!(edges_eq!(&gr1, &gr2));
1035     }
1036 
1037     fn stable_un_graph_map_id(gr1: StableUnGraph<usize, usize>) -> () {
1038         let gr2 = gr1.map(|_, &nw| nw, |_, &ew| ew);
1039         assert!(nodes_eq!(&gr1, &gr2));
1040         assert!(edgew_eq!(&gr1, &gr2));
1041         assert!(edges_eq!(&gr1, &gr2));
1042     }
1043 
1044     fn stable_di_graph_filter_map_id(gr1: StableDiGraph<usize, usize>) -> () {
1045         let gr2 = gr1.filter_map(|_, &nw| Some(nw), |_, &ew| Some(ew));
1046         assert!(nodes_eq!(&gr1, &gr2));
1047         assert!(edgew_eq!(&gr1, &gr2));
1048         assert!(edges_eq!(&gr1, &gr2));
1049     }
1050 
1051     fn test_stable_un_graph_filter_map_id(gr1: StableUnGraph<usize, usize>) -> () {
1052         let gr2 = gr1.filter_map(|_, &nw| Some(nw), |_, &ew| Some(ew));
1053         assert!(nodes_eq!(&gr1, &gr2));
1054         assert!(edgew_eq!(&gr1, &gr2));
1055         assert!(edges_eq!(&gr1, &gr2));
1056     }
1057 
1058     fn stable_di_graph_filter_map_remove(gr1: Small<StableDiGraph<i32, i32>>,
1059                                          nodes: Vec<usize>,
1060                                          edges: Vec<usize>) -> ()
1061     {
1062         let gr2 = gr1.filter_map(|ix, &nw| {
1063             if !nodes.contains(&ix.index()) { Some(nw) } else { None }
1064         },
1065         |ix, &ew| {
1066             if !edges.contains(&ix.index()) { Some(ew) } else { None }
1067         });
1068         let check_nodes = &set(gr1.node_indices()) - &set(cloned(&nodes).map(node_index));
1069         let mut check_edges = &set(gr1.edge_indices()) - &set(cloned(&edges).map(edge_index));
1070         // remove all edges with endpoint in removed nodes
1071         for edge in gr1.edge_references() {
1072             if nodes.contains(&edge.source().index()) ||
1073                 nodes.contains(&edge.target().index()) {
1074                 check_edges.remove(&edge.id());
1075             }
1076         }
1077         // assert maintained
1078         for i in check_nodes {
1079             assert_eq!(gr1[i], gr2[i]);
1080         }
1081         for i in check_edges {
1082             assert_eq!(gr1[i], gr2[i]);
1083             assert_eq!(gr1.edge_endpoints(i), gr2.edge_endpoints(i));
1084         }
1085 
1086         // assert removals
1087         for i in nodes {
1088             assert!(gr2.node_weight(node_index(i)).is_none());
1089         }
1090         for i in edges {
1091             assert!(gr2.edge_weight(edge_index(i)).is_none());
1092         }
1093     }
1094 }
1095 
naive_closure_foreach<G, F>(g: G, mut f: F) where G: Visitable + IntoNeighbors + IntoNodeIdentifiers, F: FnMut(G::NodeId, G::NodeId),1096 fn naive_closure_foreach<G, F>(g: G, mut f: F)
1097 where
1098     G: Visitable + IntoNeighbors + IntoNodeIdentifiers,
1099     F: FnMut(G::NodeId, G::NodeId),
1100 {
1101     let mut dfs = Dfs::empty(&g);
1102     for i in g.node_identifiers() {
1103         dfs.reset(&g);
1104         dfs.move_to(i);
1105         while let Some(nx) = dfs.next(&g) {
1106             if i != nx {
1107                 f(i, nx);
1108             }
1109         }
1110     }
1111 }
1112 
naive_closure<G>(g: G) -> Vec<(G::NodeId, G::NodeId)> where G: Visitable + IntoNodeIdentifiers + IntoNeighbors,1113 fn naive_closure<G>(g: G) -> Vec<(G::NodeId, G::NodeId)>
1114 where
1115     G: Visitable + IntoNodeIdentifiers + IntoNeighbors,
1116 {
1117     let mut res = Vec::new();
1118     naive_closure_foreach(g, |a, b| res.push((a, b)));
1119     res
1120 }
1121 
naive_closure_edgecount<G>(g: G) -> usize where G: Visitable + IntoNodeIdentifiers + IntoNeighbors,1122 fn naive_closure_edgecount<G>(g: G) -> usize
1123 where
1124     G: Visitable + IntoNodeIdentifiers + IntoNeighbors,
1125 {
1126     let mut res = 0;
1127     naive_closure_foreach(g, |_, _| res += 1);
1128     res
1129 }
1130 
1131 quickcheck! {
1132     fn test_tred(g: DAG<()>) -> bool {
1133         let acyclic = g.0;
1134         println!("acyclic graph {:#?}", &acyclic);
1135         let toposort = toposort(&acyclic, None).unwrap();
1136         println!("Toposort:");
1137         for (new, old) in toposort.iter().enumerate() {
1138             println!("{} -> {}", old.index(), new);
1139         }
1140         let (toposorted, revtopo): (petgraph::adj::List<(), usize>, _) =
1141             petgraph::algo::tred::dag_to_toposorted_adjacency_list(&acyclic, &toposort);
1142         println!("checking revtopo");
1143         for (i, ix) in toposort.iter().enumerate() {
1144             assert_eq!(i, revtopo[ix.index()]);
1145         }
1146         println!("toposorted adjacency list: {:#?}", &toposorted);
1147         let (tred, tclos) = petgraph::algo::tred::dag_transitive_reduction_closure(&toposorted);
1148         println!("tred: {:#?}", &tred);
1149         println!("tclos: {:#?}", &tclos);
1150         if tred.node_count() != tclos.node_count() {
1151             println!("Different node count");
1152             return false;
1153         }
1154         if acyclic.node_count() != tclos.node_count() {
1155             println!("Different node count from original graph");
1156             return false;
1157         }
1158         // check the closure
1159         let mut clos_edges: Vec<(_, _)> = tclos.edge_references().map(|i| (i.source(), i.target())).collect();
1160         clos_edges.sort();
1161         let mut tred_closure = naive_closure(&tred);
1162         tred_closure.sort();
1163         if tred_closure != clos_edges {
1164             println!("tclos is not the transitive closure of tred");
1165             return false
1166         }
1167         // check the transitive reduction is a transitive reduction
1168         for i in tred.edge_references() {
1169             let filtered = EdgeFiltered::from_fn(&tred, |edge| {
1170                 edge.source() !=i.source() || edge.target() != i.target()
1171             });
1172             let new = naive_closure_edgecount(&filtered);
1173             if new >= clos_edges.len() {
1174                 println!("when removing ({} -> {}) the transitive closure does not shrink",
1175                          i.source().index(), i.target().index());
1176                 return false
1177             }
1178         }
1179         // check that the transitive reduction is included in the original graph
1180         for i in tred.edge_references() {
1181             if acyclic.find_edge(toposort[i.source().index()], toposort[i.target().index()]).is_none() {
1182                 println!("tred is not included in the original graph");
1183                 return false
1184             }
1185         }
1186         println!("ok!");
1187         true
1188     }
1189 }
1190 
1191 quickcheck! {
1192     fn greedy_fas_remaining_graph_is_acyclic(g: StableDiGraph<(), ()>) -> bool {
1193         let mut g = g;
1194         let fas: Vec<EdgeIndex> = greedy_feedback_arc_set(&g).map(|e| e.id()).collect();
1195 
1196         for edge_id in fas {
1197             g.remove_edge(edge_id);
1198         }
1199 
1200         !is_cyclic_directed(&g)
1201     }
1202 
1203     /// Assert that the size of the feedback arc set of a tournament does not exceed
1204     /// **|E| / 2 - |V| / 6**
1205     fn greedy_fas_performance_within_bound(t: Tournament<(), ()>) -> bool {
1206         let Tournament(g) = t;
1207 
1208         let expected_bound = if g.node_count() < 2 {
1209             0
1210         } else {
1211             ((g.edge_count() as f64) / 2.0 - (g.node_count() as f64) / 6.0) as usize
1212         };
1213 
1214         let fas_size = greedy_feedback_arc_set(&g).count();
1215 
1216         fas_size <= expected_bound
1217     }
1218 }
1219 
is_valid_matching<G: NodeIndexable>(m: &Matching<G>) -> bool1220 fn is_valid_matching<G: NodeIndexable>(m: &Matching<G>) -> bool {
1221     // A set of edges is a matching if no two edges from the matching share an
1222     // endpoint.
1223     for (s1, t1) in m.edges() {
1224         for (s2, t2) in m.edges() {
1225             if s1 == s2 && t1 == t2 {
1226                 continue;
1227             }
1228 
1229             if s1 == s2 || s1 == t2 || t1 == s2 || t1 == t2 {
1230                 // Two edges share an endpoint.
1231                 return false;
1232             }
1233         }
1234     }
1235 
1236     true
1237 }
1238 
is_maximum_matching<G: NodeIndexable + IntoEdges + IntoNodeIdentifiers + Visitable>( g: G, m: &Matching<G>, ) -> bool1239 fn is_maximum_matching<G: NodeIndexable + IntoEdges + IntoNodeIdentifiers + Visitable>(
1240     g: G,
1241     m: &Matching<G>,
1242 ) -> bool {
1243     // Berge's lemma: a matching is maximum iff there is no augmenting path (a
1244     // path that starts and ends in unmatched vertices, and alternates between
1245     // matched and unmatched edges). Thus if we find an augmenting path, the
1246     // matching is not maximum.
1247     //
1248     // Start with an unmatched node and traverse the graph alternating matched
1249     // and unmatched edges. If an unmatched node is found, then an augmenting
1250     // path was found.
1251     for unmatched in g.node_identifiers().filter(|u| !m.contains_node(*u)) {
1252         let visited = &mut g.visit_map();
1253         let mut stack = Vec::new();
1254 
1255         stack.push((unmatched, false));
1256         while let Some((u, do_matched_edges)) = stack.pop() {
1257             if visited.visit(u) {
1258                 for e in g.edges(u) {
1259                     if e.source() == e.target() {
1260                         // Ignore self-loops.
1261                         continue;
1262                     }
1263 
1264                     let is_matched = m.contains_edge(e.source(), e.target());
1265 
1266                     if do_matched_edges && is_matched || !do_matched_edges && !is_matched {
1267                         stack.push((e.target(), !do_matched_edges));
1268 
1269                         // Found another free node (other than the starting one)
1270                         // that is unmatched - an augmenting path.
1271                         if !is_matched && !m.contains_node(e.target()) && e.target() != unmatched {
1272                             return false;
1273                         }
1274                     }
1275                 }
1276             }
1277         }
1278     }
1279 
1280     true
1281 }
1282 
is_perfect_matching<G: NodeCount + NodeIndexable>(g: G, m: &Matching<G>) -> bool1283 fn is_perfect_matching<G: NodeCount + NodeIndexable>(g: G, m: &Matching<G>) -> bool {
1284     // By definition.
1285     g.node_count() % 2 == 0 && m.edges().count() == g.node_count() / 2
1286 }
1287 
1288 quickcheck! {
1289     fn matching(g: Graph<(), (), Undirected>) -> bool {
1290         let m1 = greedy_matching(&g);
1291         let m2 = maximum_matching(&g);
1292 
1293         assert!(is_valid_matching(&m1), "greedy_matching returned an invalid matching");
1294         assert!(is_valid_matching(&m2), "maximum_matching returned an invalid matching");
1295         assert!(is_maximum_matching(&g, &m2), "maximum_matching returned a matching that is not maximum");
1296         assert_eq!(m1.is_perfect(), is_perfect_matching(&g, &m1), "greedy_matching incorrectly determined whether the matching is perfect");
1297         assert_eq!(m2.is_perfect(), is_perfect_matching(&g, &m2), "maximum_matching incorrectly determined whether the matching is perfect");
1298 
1299         true
1300     }
1301 
1302     fn matching_in_stable_graph(g: StableGraph<(), (), Undirected>) -> bool {
1303         let m1 = greedy_matching(&g);
1304         let m2 = maximum_matching(&g);
1305 
1306         assert!(is_valid_matching(&m1), "greedy_matching returned an invalid matching");
1307         assert!(is_valid_matching(&m2), "maximum_matching returned an invalid matching");
1308         assert!(is_maximum_matching(&g, &m2), "maximum_matching returned a matching that is not maximum");
1309         assert_eq!(m1.is_perfect(), is_perfect_matching(&g, &m1), "greedy_matching incorrectly determined whether the matching is perfect");
1310         assert_eq!(m2.is_perfect(), is_perfect_matching(&g, &m2), "maximum_matching incorrectly determined whether the matching is perfect");
1311 
1312         true
1313     }
1314 }
1315 
1316 quickcheck! {
1317     // The ranks are probabilities,
1318     // as such they are positive and they should sum up to 1.
1319     fn test_page_rank_proba(gr: Graph<(), f32>) -> bool {
1320         if gr.node_count() == 0 {
1321             return true;
1322         }
1323         let tol = 1e-10;
1324         let ranks: Vec<f64> = page_rank(&gr, 0.85_f64, 5);
1325         let at_least_one_neg_rank = ranks.iter().any(|rank| *rank < 0.);
1326         let not_sumup_to_one = (ranks.iter().sum::<f64>() - 1.).abs() > tol;
1327         if  at_least_one_neg_rank | not_sumup_to_one{
1328             return false;
1329         }
1330         true
1331     }
1332 }
1333 
sum_flows<N, F: std::iter::Sum + Copy>( gr: &Graph<N, F>, flows: &[F], node: NodeIndex, dir: Direction, ) -> F1334 fn sum_flows<N, F: std::iter::Sum + Copy>(
1335     gr: &Graph<N, F>,
1336     flows: &[F],
1337     node: NodeIndex,
1338     dir: Direction,
1339 ) -> F {
1340     gr.edges_directed(node, dir)
1341         .map(|edge| flows[EdgeIndexable::to_index(&gr, edge.id())])
1342         .sum::<F>()
1343 }
1344 
1345 quickcheck! {
1346     // 1. (Capacity)
1347     //    The flows should be <= capacities
1348     // 2. (Flow conservation)
1349     //    For every internal node (i.e a node different from the
1350     //    source node and the destination (or sink) node), the sum
1351     //    of incoming flows (i.e flows of incoming edges) is equal
1352     //    to the sum of the outgoing flows (i.e flows of outgoing edges).
1353     // 3. (Maximum flow)
1354     //    It is equal to the sum of the destination node incoming flows and
1355     //    also the sum of the outgoing flows of the source node.
1356     fn test_ford_fulkerson_flows(gr: Graph<usize, u32>) -> bool {
1357         if gr.node_count() <= 1 || gr.edge_count() == 0 {
1358             return true;
1359         }
1360         let source = NodeIndex::from(0);
1361         let destination = NodeIndex::from(gr.node_count() as u32 / 2);
1362         let (max_flow, flows) = ford_fulkerson(&gr, source, destination);
1363         let capacity_constraint = flows
1364             .iter()
1365             .enumerate()
1366             .all(|(ix, flow)| flow <= gr.edge_weight(EdgeIndexable::from_index(&gr, ix)).unwrap());
1367         let flow_conservation_constraint = (0..gr.node_count()).all(|ix| {
1368             let node = NodeIndexable::from_index(&gr, ix);
1369             if (node != source) && (node != destination){
1370             sum_flows(&gr, &flows, node, Direction::Outgoing)
1371                 == sum_flows(&gr, &flows, node, Direction::Incoming)
1372             } else {true}
1373         });
1374         let max_flow_constaint = (sum_flows(&gr, &flows, source, Direction::Outgoing) == max_flow)
1375             && (sum_flows(&gr, &flows, destination, Direction::Incoming) == max_flow);
1376         return capacity_constraint && flow_conservation_constraint && max_flow_constaint;
1377     }
1378 }
1379