summaryrefslogtreecommitdiffstats
path: root/vendor/petgraph/src/quickcheck.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/petgraph/src/quickcheck.rs')
-rw-r--r--vendor/petgraph/src/quickcheck.rs216
1 files changed, 216 insertions, 0 deletions
diff --git a/vendor/petgraph/src/quickcheck.rs b/vendor/petgraph/src/quickcheck.rs
new file mode 100644
index 000000000..0c7ce6b2e
--- /dev/null
+++ b/vendor/petgraph/src/quickcheck.rs
@@ -0,0 +1,216 @@
+extern crate quickcheck;
+use self::quickcheck::{Arbitrary, Gen};
+
+use crate::graph::{node_index, IndexType};
+#[cfg(feature = "stable_graph")]
+use crate::stable_graph::StableGraph;
+use crate::{EdgeType, Graph};
+
+#[cfg(feature = "graphmap")]
+use crate::graphmap::{GraphMap, NodeTrait};
+use crate::visit::NodeIndexable;
+
+/// Return a random float in the range [0, 1.)
+fn random_01<G: Gen>(g: &mut G) -> f64 {
+ // from rand
+ let bits = 53;
+ let scale = 1. / ((1u64 << bits) as f64);
+ let x = g.next_u64();
+ (x >> (64 - bits)) as f64 * scale
+}
+
+/// `Arbitrary` for `Graph` creates a graph by selecting a node count
+/// and a probability for each possible edge to exist.
+///
+/// The result will be simple graph or digraph, self loops
+/// possible, no parallel edges.
+///
+/// The exact properties of the produced graph is subject to change.
+///
+/// Requires crate feature `"quickcheck"`
+impl<N, E, Ty, Ix> Arbitrary for Graph<N, E, Ty, Ix>
+where
+ N: Arbitrary,
+ E: Arbitrary,
+ Ty: EdgeType + Send + 'static,
+ Ix: IndexType + Send,
+{
+ fn arbitrary<G: Gen>(g: &mut G) -> Self {
+ let nodes = usize::arbitrary(g);
+ if nodes == 0 {
+ return Graph::with_capacity(0, 0);
+ }
+ // use X² for edge probability (bias towards lower)
+ let edge_prob = random_01(g) * random_01(g);
+ let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
+ let mut gr = Graph::with_capacity(nodes, edges);
+ for _ in 0..nodes {
+ gr.add_node(N::arbitrary(g));
+ }
+ for i in gr.node_indices() {
+ for j in gr.node_indices() {
+ if !gr.is_directed() && i > j {
+ continue;
+ }
+ let p: f64 = random_01(g);
+ if p <= edge_prob {
+ gr.add_edge(i, j, E::arbitrary(g));
+ }
+ }
+ }
+ gr
+ }
+
+ // shrink the graph by splitting it in two by a very
+ // simple algorithm, just even and odd node indices
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ let self_ = self.clone();
+ Box::new((0..2).filter_map(move |x| {
+ let gr = self_.filter_map(
+ |i, w| {
+ if i.index() % 2 == x {
+ Some(w.clone())
+ } else {
+ None
+ }
+ },
+ |_, w| Some(w.clone()),
+ );
+ // make sure we shrink
+ if gr.node_count() < self_.node_count() {
+ Some(gr)
+ } else {
+ None
+ }
+ }))
+ }
+}
+
+#[cfg(feature = "stable_graph")]
+/// `Arbitrary` for `StableGraph` creates a graph by selecting a node count
+/// and a probability for each possible edge to exist.
+///
+/// The result will be simple graph or digraph, with possible
+/// self loops, no parallel edges.
+///
+/// The exact properties of the produced graph is subject to change.
+///
+/// Requires crate features `"quickcheck"` and `"stable_graph"`
+impl<N, E, Ty, Ix> Arbitrary for StableGraph<N, E, Ty, Ix>
+where
+ N: Arbitrary,
+ E: Arbitrary,
+ Ty: EdgeType + Send + 'static,
+ Ix: IndexType + Send,
+{
+ fn arbitrary<G: Gen>(g: &mut G) -> Self {
+ let nodes = usize::arbitrary(g);
+ if nodes == 0 {
+ return StableGraph::with_capacity(0, 0);
+ }
+ // use X² for edge probability (bias towards lower)
+ let edge_prob = random_01(g) * random_01(g);
+ let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
+ let mut gr = StableGraph::with_capacity(nodes, edges);
+ for _ in 0..nodes {
+ gr.add_node(N::arbitrary(g));
+ }
+ for i in 0..gr.node_count() {
+ for j in 0..gr.node_count() {
+ let i = node_index(i);
+ let j = node_index(j);
+ if !gr.is_directed() && i > j {
+ continue;
+ }
+ let p: f64 = random_01(g);
+ if p <= edge_prob {
+ gr.add_edge(i, j, E::arbitrary(g));
+ }
+ }
+ }
+ if bool::arbitrary(g) {
+ // potentially remove nodes to make holes in nodes & edge sets
+ let n = u8::arbitrary(g) % (gr.node_count() as u8);
+ for _ in 0..n {
+ let ni = node_index(usize::arbitrary(g) % gr.node_bound());
+ if gr.node_weight(ni).is_some() {
+ gr.remove_node(ni);
+ }
+ }
+ }
+ gr
+ }
+
+ // shrink the graph by splitting it in two by a very
+ // simple algorithm, just even and odd node indices
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ let self_ = self.clone();
+ Box::new((0..2).filter_map(move |x| {
+ let gr = self_.filter_map(
+ |i, w| {
+ if i.index() % 2 == x {
+ Some(w.clone())
+ } else {
+ None
+ }
+ },
+ |_, w| Some(w.clone()),
+ );
+ // make sure we shrink
+ if gr.node_count() < self_.node_count() {
+ Some(gr)
+ } else {
+ None
+ }
+ }))
+ }
+}
+
+/// `Arbitrary` for `GraphMap` creates a graph by selecting a node count
+/// and a probability for each possible edge to exist.
+///
+/// The result will be simple graph or digraph, self loops
+/// possible, no parallel edges.
+///
+/// The exact properties of the produced graph is subject to change.
+///
+/// Requires crate features `"quickcheck"` and `"graphmap"`
+#[cfg(feature = "graphmap")]
+impl<N, E, Ty> Arbitrary for GraphMap<N, E, Ty>
+where
+ N: NodeTrait + Arbitrary,
+ E: Arbitrary,
+ Ty: EdgeType + Clone + Send + 'static,
+{
+ fn arbitrary<G: Gen>(g: &mut G) -> Self {
+ let nodes = usize::arbitrary(g);
+ if nodes == 0 {
+ return GraphMap::with_capacity(0, 0);
+ }
+ let mut nodes = (0..nodes).map(|_| N::arbitrary(g)).collect::<Vec<_>>();
+ nodes.sort();
+ nodes.dedup();
+
+ // use X² for edge probability (bias towards lower)
+ let edge_prob = random_01(g) * random_01(g);
+ let edges = ((nodes.len() as f64).powi(2) * edge_prob) as usize;
+ let mut gr = GraphMap::with_capacity(nodes.len(), edges);
+ for &node in &nodes {
+ gr.add_node(node);
+ }
+ for (index, &i) in nodes.iter().enumerate() {
+ let js = if Ty::is_directed() {
+ &nodes[..]
+ } else {
+ &nodes[index..]
+ };
+ for &j in js {
+ let p: f64 = random_01(g);
+ if p <= edge_prob {
+ gr.add_edge(i, j, E::arbitrary(g));
+ }
+ }
+ }
+ gr
+ }
+}