fera_graph/
builder.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5//! Builder to create user defined, standard and random graphs.
6//!
7//! This module offers an abstract way (independent of the graph type) to create graphs. To support
8//! graph building a graph type must implement the [`WithBuilder`] trait, which requires defining a
9//! type that implements the [`Builder`] trait. Each graph type has its own vertex and edge
10//! representation, but the [`Builder`] trait works with numeric vertices.
11//!
12//! # Examples
13//!
14//! Creating a literal graph:
15//!
16//! ```
17//! use fera_graph::prelude::*;
18//!
19//! // Creates a graph builder for a graph with 4 vertices and initial capacity for 5 edges
20//! let mut builder = StaticGraph::builder(4, 5);
21//! builder.add_edge(0, 1);
22//! builder.add_edge(1, 2);
23//! builder.add_edge(1, 3);
24//! builder.add_edge(2, 3);
25//! builder.add_edge(3, 0);
26//! // Note that we can add more than 5 edges
27//! builder.add_edge(2, 0);
28//!
29//! let g = builder.finalize();
30//! assert_eq!(4, g.num_vertices());
31//! assert_eq!(6, g.num_edges());
32//! ```
33//!
34//! The [`graph!`] macro can be used to simplify the creation of literal graphs.
35//!
36//! Creating standard graphs (see also [`Complete`]):
37//!
38//! ```
39//! use fera_graph::prelude::*;
40//!
41//! // Creates a complete graph with 4 vertices
42//! let g = StaticGraph::new_complete(4);
43//! assert_eq!(4, g.num_vertices());
44//! assert_eq!(6, g.num_edges());
45//! let edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)];
46//! assert!(edges.iter().all(|&(u, v)| g.get_edge_by_ends(u, v).is_some()));
47//! ```
48//!
49//! Creating random graphs:
50//!
51//! ```
52//! extern crate rand;
53//! extern crate fera_graph;
54//!
55//! use fera_graph::prelude::*;
56//! use fera_graph::algs::{Components, Trees};
57//!
58//! # fn main() {
59//! let mut rng = rand::weak_rng();
60//!
61//! // Creates a connected graph with 10 vertices
62//! let g = StaticGraph::new_gn_connected(10, &mut rng);
63//! assert!(g.is_connected());
64//!
65//! // Creates a graph with 7 vertices that is a tree.
66//! let g = StaticGraph::new_random_tree(7, &mut rng);
67//! assert!(g.is_tree());
68//! # }
69//! ```
70//!
71//! See [`WithBuilder`] for other methods to create standard and random graphs.
72//!
73//! [`graph!`]: ../macro.graph.html
74//! [`Builder`]: trait.Builder.html
75//! [`Complete`]: ../graphs/complete/index.html
76//! [`WithBuilder`]: trait.WithBuilder.html
77
78use algs::{Components, Trees};
79use prelude::*;
80use props::Color;
81use sets::FastVecSet;
82
83use std::cmp;
84use std::mem;
85
86use fera_fun::set;
87use rand::prelude::*;
88use rand::distributions::Range;
89
90/// Creates a new graph with `n` vertices and the specified edges.
91///
92/// The type of the graph that will be created needs to be specified. Any graph that implements
93/// [`Builder`] can be used. There are two forms of this macro:
94///
95/// - Creates a graph with a list of edges:
96///
97/// ```
98/// #[macro_use] extern crate fera_graph;
99/// use fera_graph::prelude::*;
100///
101/// # fn main() {
102/// let g: StaticGraph = graph!{
103///     4,
104///     (0, 2),
105///     (0, 3),
106///     (1, 2)
107/// };
108///
109/// assert_eq!(4, g.num_vertices());
110/// assert_eq!(3, g.num_edges());
111///
112/// for u in 0..4 {
113///     for v in 0..4 {
114///         if [(0, 2), (2, 0), (0, 3), (3, 0), (1, 2), (2, 1)].contains(&(u, v)) {
115///             assert_eq!(g.end_vertices(g.edge_by_ends(u, v)), (u, v));
116///         } else {
117///             assert_eq!(None, g.get_edge_by_ends(u, v));
118///         }
119///     }
120/// }
121/// # }
122/// ```
123///
124/// - Creates a graph with a list of edges and an associated property:
125///
126/// ```
127/// #[macro_use] extern crate fera_graph;
128/// use fera_graph::prelude::*;
129/// use fera_graph::sum_prop;
130///
131/// # fn main() {
132/// let (g, w): (StaticGraph, _) = graph!{
133///     4,
134///     (0, 2) -> 4,
135///     (0, 3) -> 2,
136///     (1, 2) -> 3
137/// };
138///
139/// assert_eq!(9, sum_prop(&w, g.edges()));
140/// # }
141/// ```
142///
143/// In this case, a [`DefaultEdgePropMut`] is created.
144///
145/// [`Builder`]: builder/trait.Builder.html
146/// [`DefaultEdgePropMut`]: graphs/type.DefaultEdgePropMut.html
147// TODO: move to macros.rs
148// TODO: create a vertex_prop macro
149#[macro_export]
150macro_rules! graph {
151    () => (
152        {
153            use $crate::builder::WithBuilder;
154            WithBuilder::new_empty(0)
155        }
156    );
157
158    ($n:expr) => (
159        {
160            use $crate::builder::WithBuilder;
161            WithBuilder::new_empty($n)
162        }
163    );
164
165    ($n:expr, $(($u:expr, $v:expr)),+) => (
166        {
167            let edges = [$(($u, $v)),*];
168            $crate::builder::WithBuilder::new_with_edges($n, edges.iter().cloned())
169        }
170    );
171
172    ($n:expr, $(($u:expr, $v:expr)),+,) => (
173        graph!($n, $(($u, $v)),+)
174    );
175
176    ($n:expr, $(($u:expr, $v:expr) -> $p:expr),+) => (
177        {
178            let edges = [$(($u, $v, $p)),*];
179            $crate::builder::WithBuilder::new_with_edges_prop($n, &edges)
180        }
181    );
182
183    ($n:expr, $(($u:expr, $v:expr) -> $p:expr),+,) => (
184        graph!($n, $(($u, $v) -> $p),+)
185    );
186}
187
188// TODO: rename to GraphBuilder
189/// A builder used to build graphs.
190///
191/// See the [module documentation] for examples.
192///
193/// [module documentation]: index.html
194pub trait Builder {
195    /// The graph type produced by this builder.
196    type Graph: WithEdge;
197
198    /// Creates a new builder for a graph with exactly `n` vertices and initial capacity for `m`
199    /// edges.
200    ///
201    /// This method is generally called through [`WithBuilder::builder`], for example,
202    /// `StaticGraph::builder(10, 26)`.
203    ///
204    /// [`WithBuilder::builder`]: trait.WithBuilder.html#method.builder
205    fn new(n: usize, m: usize) -> Self;
206
207    /// Add `(u, v)` edge to the graph. Support for multiple edges and loops are graph dependent.
208    ///
209    /// # Panics
210    ///
211    /// If `u` or `v` is not a valid vertex, that is `>= num_vertices`.
212    fn add_edge(&mut self, u: usize, v: usize);
213
214    /// Builds the graph.
215    fn finalize(self) -> Self::Graph;
216
217    #[doc(hidden)]
218    fn finalize_(
219        self,
220    ) -> (
221        Self::Graph,
222        Vec<Vertex<Self::Graph>>,
223        Vec<Edge<Self::Graph>>,
224    );
225}
226
227/// A graph that has a [`Builder`].
228///
229/// See the [module documentation] for examples.
230///
231/// [`Builder`]: trait.Builder.html
232/// [module documentation]: index.html
233// TODO: ex: G::new().complete(5), G::new_with_rng(rng).random_tree(10)
234pub trait WithBuilder: WithEdge {
235    /// The builder for this graph type.
236    type Builder: Builder<Graph = Self>;
237
238    /// Creates a new builder for a graph of this type with `n` vertices and initial capacity for
239    /// `m` edges.
240    fn builder(num_vertices: usize, num_edges: usize) -> Self::Builder {
241        Self::Builder::new(num_vertices, num_edges)
242    }
243
244    /// Creates a new graph with `n` vertices from `edges` iterator.
245    ///
246    /// # Panics
247    ///
248    /// If some edges is not valid.
249    fn new_with_edges<I>(n: usize, edges: I) -> Self
250    where
251        I: IntoIterator<Item = (usize, usize)>,
252    {
253        let edges = edges.into_iter();
254        let mut b = Self::Builder::new(n, edges.size_hint().1.unwrap_or(0));
255        for (u, v) in edges {
256            b.add_edge(u, v);
257        }
258        b.finalize()
259    }
260
261    #[doc(hidden)]
262    fn new_with_edges_prop<T>(
263        n: usize,
264        edges: &[(usize, usize, T)],
265    ) -> (Self, DefaultEdgePropMut<Self, T>)
266    where
267        T: Copy + Default,
268        Self: WithEdgeProp<T>,
269    {
270        // TODO: Should this be optimized?
271        let mut b = Self::Builder::new(n, edges.len());
272        for &(ref u, ref v, _) in edges {
273            b.add_edge(*u, *v);
274        }
275        let (g, _, ee) = b.finalize_();
276        let mut p = g.default_edge_prop(T::default());
277        for (e, val) in ee.into_iter().zip(edges.iter().map(|x| x.2)) {
278            p[e] = val;
279        }
280        (g, p)
281    }
282
283    /// Creates a graph with `n` vertices and no edges.
284    fn new_empty(n: usize) -> Self {
285        Self::Builder::new(n, 0).finalize()
286    }
287
288    /// Creates a complete graph with `n` vertices.
289    ///
290    /// A complete graph has an edge between each pair of vertices.
291    fn new_complete(n: usize) -> Self
292    where
293        Self: WithEdge<Kind = Undirected>,
294    {
295        complete::<Self>(n).finalize()
296    }
297
298    /// Creates a graph that is a complete binary tree with height `h`.
299    ///
300    /// In complete binary tree all interior vertices have two children an all leaves have the
301    /// same depth.
302    fn new_complete_binary_tree(h: u32) -> Self
303    where
304        Self: WithEdge<Kind = Undirected>,
305    {
306        complete_binary_tree::<Self>(h).finalize()
307    }
308
309    /// Creates a new `d`-regular graph.
310    ///
311    /// Return `None` if `d >= n` of if `d * n` is not even.
312    ///
313    /// See <https://doi.org/10.1017/S0963548399003867>
314    fn new_regular<R: Rng>(d: usize, n: usize, rng: R) -> Option<Self>
315    where
316        Self: WithEdge<Kind = Undirected>,
317    {
318        regular::<Self, R>(d, n, rng).map(Builder::finalize)
319    }
320
321    /// Creates a graph with `n` vertices that is a tree, that is, is connected and acyclic.
322    ///
323    /// The graph has `n - 1` edges if `n > 0` or zero edges if `n = 0`.
324    ///
325    /// See <https://doi.org/10.1109/SFCS.1989.63516>.
326    fn new_random_tree<R: Rng>(n: usize, rng: R) -> Self {
327        random_tree::<Self, _>(n, rng).finalize()
328    }
329
330    /// Similar to [`new_random_tree`] but creates a tree with diameter `d`. Returns `None`
331    /// if the diameter is invalid.
332    // TODO: describe what is a invalid diameter.
333    fn new_random_tree_with_diameter<R: Rng>(n: u32, d: u32, rng: R) -> Option<Self> {
334        random_tree_with_diameter::<Self, _>(n, d, rng).map(Builder::finalize)
335    }
336
337    /// Creates a random graph with `n` vertices.
338    fn new_gn<R>(n: usize, mut rng: R) -> Self
339    where
340        Self::Kind: UniformEdgeKind,
341        R: Rng,
342    {
343        let m = if n > 1 {
344            rng.gen_range(0, max_num_edges::<Self>(n))
345        } else {
346            0
347        };
348        Self::new_gnm(n, m, rng).unwrap()
349    }
350
351    /// Creates a random connected graph with `n` vertices.
352    fn new_gn_connected<R: Rng>(n: usize, mut rng: R) -> Self
353    where
354        Self::Kind: UniformEdgeKind,
355    {
356        let m = max_num_edges::<Self>(n);
357        let m = if m > n {
358            rng.gen_range(n, m)
359        } else {
360            cmp::min(n, m)
361        };
362        Self::new_gnm_connected(n, m, rng).unwrap()
363    }
364
365    /// Creates a random graph with `n` vertices and `m` edges.
366    ///
367    /// Returns `None` with `m` exceeds the maximum number of edges.
368    fn new_gnm<R>(n: usize, m: usize, rng: R) -> Option<Self>
369    where
370        Self::Kind: UniformEdgeKind,
371        R: Rng,
372    {
373        gnm::<Self, _>(n, m, rng).map(Builder::finalize)
374    }
375
376    /// Creates a random connected graph (weakly connected if `Self` is a digraph) with `n`
377    /// vertices and `m` edges.
378    ///
379    /// Returns `None` if `m` exceeds the maximum number of edges or if `m` is less than `n - 1`.
380    fn new_gnm_connected<R: Rng>(n: usize, m: usize, rng: R) -> Option<Self>
381    where
382        Self::Kind: UniformEdgeKind,
383    {
384        gnm_connected::<Self, _>(n, m, rng).map(Builder::finalize)
385    }
386}
387
388fn complete<G: WithBuilder>(n: usize) -> G::Builder {
389    let mut b = G::builder(n, (n * n - n) / 2);
390    for u in 0..n {
391        for v in u + 1..n {
392            b.add_edge(u, v);
393        }
394    }
395    b
396}
397
398fn complete_binary_tree<G: WithBuilder>(height: u32) -> G::Builder {
399    let num_vertices = 2usize.pow(height + 1) - 1;
400    let mut b = G::builder(num_vertices, num_vertices - 1);
401    for i in 0..2usize.pow(height) - 1 {
402        b.add_edge(i, 2 * i + 1);
403        b.add_edge(i, 2 * i + 2);
404    }
405    b
406}
407
408fn random_tree<G, R>(n: usize, rng: R) -> G::Builder
409where
410    G: WithBuilder,
411    R: Rng,
412{
413    if n == 0 {
414        return G::builder(0, 0);
415    }
416    let mut b = G::builder(n, n - 1);
417    for (u, v) in RandomTreeIter::new(n, rng) {
418        b.add_edge(u, v);
419    }
420    b
421}
422
423fn random_tree_with_diameter<G, R>(n: u32, d: u32, mut rng: R) -> Option<G::Builder>
424where
425    G: WithBuilder,
426    R: Rng,
427{
428    if n == 0 {
429        return if d == 0 { Some(G::builder(0, 0)) } else { None };
430    }
431
432    if d > n - 1 || n > 2 && d < 2 {
433        return None;
434    }
435
436    let mut b = G::builder(n as usize, (n - 1) as usize);
437    let mut vertices: Vec<_> = (0..n).collect();
438    let mut visited = vec![false; n as usize];
439    let mut maxd = vec![0; n as usize];
440    // create a complete graph so we can use graph properties
441    let g = CompleteGraph::new(n);
442    let mut dist = g.default_edge_prop(0);
443    let mut num_edges = 0;
444
445    // create the initial path
446    rng.shuffle(&mut vertices);
447    vertices.truncate(d as usize + 1);
448    for i in 0..vertices.len() - 1 {
449        for j in (i + 1)..vertices.len() {
450            let (u, v) = (vertices[i], vertices[j]);
451            let duv = (j - i) as u32;
452            dist[g.edge_by_ends(u, v)] = duv;
453            maxd[u as usize] = maxd[u as usize].max(duv);
454            maxd[v as usize] = maxd[v as usize].max(duv);
455        }
456        b.add_edge(vertices[i] as usize, vertices[i + 1] as usize);
457        num_edges += 1;
458    }
459
460    if num_edges == n - 1 {
461        return Some(b);
462    }
463
464    // compute good
465    let mut good = FastVecSet::new_vertex_set(&g);
466    for &v in &vertices {
467        visited[v as usize] = true;
468    }
469    for v in 0..n {
470        if maxd[v as usize] != d {
471            good.insert(v);
472        }
473    }
474
475    // complete the tree
476    let mut cur = *good.choose(&mut rng).unwrap();
477    while !visited[cur as usize] {
478        cur = *good.choose(&mut rng).unwrap();
479    }
480    while num_edges != n - 1 {
481        // choose a new edge
482        if !good.contains(cur) {
483            cur = *good.choose(&mut rng).unwrap();
484            while !visited[cur as usize] {
485                cur = *good.choose(&mut rng).unwrap();
486            }
487        }
488        let v = *good.choose(&mut rng).unwrap();
489        if visited[v as usize] || cur == v {
490            cur = v;
491            continue;
492        }
493        assert!(maxd[cur as usize] < d);
494
495        // update dist
496        for i in 0..n {
497            if i == cur {
498                continue;
499            }
500            let dci = dist[g.edge_by_ends(cur, i)];
501            if dci != 0 && v != i {
502                dist[g.edge_by_ends(v, i)] = dci + 1;
503            }
504        }
505
506        // update maxd and good
507        maxd[v as usize] = maxd[cur as usize] + 1;
508        if maxd[v as usize] == d {
509            good.remove(v);
510        }
511        for i in 0..n {
512            if v == i {
513                continue;
514            }
515            maxd[i as usize] = maxd[i as usize].max(dist[g.edge_by_ends(v, i)]);
516            if maxd[i as usize] == d && good.contains(i) {
517                good.remove(i);
518            }
519            assert!(maxd[i as usize] <= d);
520        }
521
522        // update tree
523        b.add_edge(cur as usize, v as usize);
524        num_edges += 1;
525        visited[v as usize] = true;
526
527        // iterate
528        cur = v;
529    }
530
531    Some(b)
532}
533
534fn max_num_edges<G>(n: usize) -> usize
535where
536    G: WithEdge,
537    G::Kind: UniformEdgeKind,
538{
539    if G::Kind::is_directed() {
540        n * n
541    } else {
542        (n * n - n) / 2
543    }
544}
545
546fn gnm_connected<G, R>(n: usize, m: usize, mut rng: R) -> Option<G::Builder>
547where
548    G: WithBuilder,
549    G::Kind: UniformEdgeKind,
550    R: Rng,
551{
552    use std::collections::HashSet;
553
554    if n == 0 {
555        return Some(G::builder(0, 0));
556    }
557
558    if m > max_num_edges::<G>(n) || m < n - 1 {
559        return None;
560    }
561
562    let mut b = G::builder(n, m);
563    let mut set = HashSet::new();
564    for (u, v) in RandomTreeIter::new(n, &mut rng) {
565        set.insert((u, v));
566        b.add_edge(u, v)
567    }
568
569    while set.len() != m {
570        let u = rng.gen_range(0, n);
571        let v = rng.gen_range(0, n);
572        if u == v || set.contains(&(u, v)) || G::Kind::is_undirected() && set.contains(&(v, u)) {
573            continue;
574        }
575        set.insert((u, v));
576        b.add_edge(u, v)
577    }
578
579    Some(b)
580}
581
582fn gnm<G, R>(n: usize, m: usize, mut rng: R) -> Option<G::Builder>
583where
584    G: WithBuilder,
585    G::Kind: UniformEdgeKind,
586    R: Rng,
587{
588    use std::collections::HashSet;
589
590    if m > max_num_edges::<G>(n) {
591        return None;
592    }
593
594    let mut b = G::builder(n, m);
595    let mut set = HashSet::new();
596    while set.len() != m {
597        let u = rng.gen_range(0, n);
598        let v = rng.gen_range(0, n);
599        if u == v || set.contains(&(u, v)) || G::Kind::is_undirected() && set.contains(&(v, u)) {
600            continue;
601        }
602        set.insert((u, v));
603        b.add_edge(u, v)
604    }
605
606    Some(b)
607}
608
609fn regular<G, R>(d: usize, n: usize, mut rng: R) -> Option<G::Builder>
610where
611    G: WithBuilder,
612    R: Rng,
613{
614    use fera_fun::vec;
615    use std::collections::HashSet;
616
617    let dn = d * n;
618
619    if d >= n {
620        return None;
621    }
622
623    if dn % 2 != 0 {
624        return None;
625    }
626
627    if d == 0 {
628        return Some(Builder::new(n, 0));
629    }
630
631    let max_tries = 10 * dn;
632    let mut edges = HashSet::new();
633    let mut u = vec((0..d).flat_map(|_| 0..n));
634    let mut len = u.len();
635    let mut tries = 0;
636    loop {
637        if tries == max_tries {
638            len = u.len();
639            edges.clear();
640            tries = 0;
641        }
642
643        let i = rng.gen_range(0, len);
644        let j = rng.gen_range(0, len);
645
646        if u[i] == u[j] {
647            tries += 1;
648            continue;
649        }
650
651        // sort the pair - this makes easy to use the HashSet
652        let (a, b) = if u[i] < u[j] {
653            (u[i], u[j])
654        } else {
655            (u[j], u[i])
656        };
657
658        if !edges.insert((a, b)) {
659            tries += 1;
660            continue;
661        }
662
663        if edges.len() == dn / 2 {
664            break;
665        }
666
667        if j == len - 1 {
668            u.swap(i, len - 2);
669        } else {
670            u.swap(i, len - 1);
671            u.swap(j, len - 2);
672        }
673        len -= 2;
674    }
675
676    let mut b = G::builder(n, edges.len());
677    for (u, v) in edges {
678        b.add_edge(u, v);
679    }
680    Some(b)
681}
682
683// Iterator
684
685struct RandomTreeIter<R> {
686    visited: Vec<bool>,
687    rem: usize,
688    rng: R,
689    range: Range<usize>,
690    cur: usize,
691}
692
693impl<R: Rng> RandomTreeIter<R> {
694    fn new(n: usize, mut rng: R) -> Self {
695        let range = Range::new(0, n);
696        let cur = range.sample(&mut rng);
697        let mut visited = vec![false; n];
698        visited[cur] = true;
699        RandomTreeIter {
700            visited,
701            rem: n.checked_sub(1).unwrap_or(0),
702            rng,
703            range,
704            cur,
705        }
706    }
707}
708
709impl<R: Rng> Iterator for RandomTreeIter<R> {
710    type Item = (usize, usize);
711
712    fn next(&mut self) -> Option<Self::Item> {
713        if self.rem == 0 {
714            return None;
715        }
716        loop {
717            let v = self.range.sample(&mut self.rng);
718            if self.visited[v] {
719                self.cur = v;
720            } else {
721                self.rem -= 1;
722                self.visited[v] = true;
723                let u = mem::replace(&mut self.cur, v);
724                return Some((u, v));
725            }
726        }
727    }
728}
729
730// Tests
731
732#[doc(hidden)]
733pub trait BuilderTests {
734    type G: WithBuilder + VertexList + EdgeList;
735
736    fn graph_macro() {
737        let g: Self::G = graph!(5, (1, 2), (4, 0),);
738        assert_eq!(5, g.num_vertices());
739        assert_eq!(2, g.num_edges());
740    }
741
742    fn graph_prop_macro()
743    where
744        Self::G: WithEdgeProp<u32>,
745    {
746        let (g, w): (Self::G, _) = graph!(
747            5,
748            (1, 2) -> 3,
749            (4, 0) -> 4,
750        );
751        assert_eq!(5, g.num_vertices());
752        assert_eq!(2, g.num_edges());
753        let mut sum = 0;
754        for e in g.edges() {
755            sum += w[e];
756        }
757        assert_eq!(7, sum);
758    }
759
760    fn complete() {
761        let (g, v, e) = complete::<Self::G>(3).finalize_();
762        assert_eq!((v[0], v[1]), g.ends(e[0]));
763        assert_eq!((v[0], v[2]), g.ends(e[1]));
764        assert_eq!((v[1], v[2]), g.ends(e[2]));
765
766        for (n, &m) in (0..5).zip(&[0, 0, 1, 3, 6, 10]) {
767            let (g, v, _) = complete::<Self::G>(n).finalize_();
768            assert_eq!(n, g.num_vertices());
769            assert_eq!(m, g.num_edges());
770            assert_eq!(set(v), set(g.vertices()));
771        }
772    }
773
774    #[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
775    fn complete_binary_tree()
776    where
777        Self::G: Incidence + WithVertexProp<Color>,
778    {
779        let (g, _, _) = complete_binary_tree::<Self::G>(0).finalize_();
780        assert_eq!(1, g.num_vertices());
781        assert_eq!(0, g.num_edges());
782
783        let (g, v, _) = complete_binary_tree::<Self::G>(1).finalize_();
784        assert_eq!(3, g.num_vertices());
785        assert_eq!(2, g.num_edges());
786        assert_eq!(
787            set(vec![(v[0], v[1]), (v[0], v[2])]),
788            set(g.out_edges_ends(v[0]))
789        );
790
791        for h in 2..10 {
792            let (g, v, _) = complete_binary_tree::<Self::G>(h).finalize_();
793            assert!(g.is_tree());
794            assert_eq!(2, g.out_degree(v[0]));
795            for i in 1..g.num_vertices() / 2 - 1 {
796                assert_eq!(3, g.out_degree(v[i]));
797            }
798            for i in (g.num_vertices() / 2)..g.num_vertices() {
799                assert_eq!(1, g.out_degree(v[i]));
800            }
801        }
802    }
803
804    fn random_tree()
805    where
806        Self::G: Incidence + WithVertexProp<Color>,
807    {
808        let mut rng = SmallRng::from_entropy();
809        for n in 0..100 {
810            for _ in 0..10 {
811                let g = Self::G::new_random_tree(n, &mut rng);
812                assert_eq!(n, g.num_vertices());
813                if n > 0 {
814                    assert_eq!(n - 1, g.num_edges());
815                }
816                assert!(g.is_tree());
817            }
818        }
819    }
820
821    fn gnm()
822    where
823        Self::G: WithEdge + VertexList + EdgeList,
824        <Self::G as WithEdge>::Kind: UniformEdgeKind,
825    {
826        let mut rng = SmallRng::from_entropy();
827
828        assert!(Self::G::new_gnm(4, 20, &mut rng).is_none());
829
830        for n in 0..10 {
831            for m in 0..30 {
832                if let Some(g) = Self::G::new_gnm(n, m, &mut rng) {
833                    assert_eq!(n, g.num_vertices());
834                    assert_eq!(m, g.num_edges());
835                }
836            }
837        }
838    }
839
840    fn gnm_connected()
841    where
842        Self::G: Incidence + WithVertexProp<Color>,
843        <Self::G as WithEdge>::Kind: UniformEdgeKind,
844    {
845        let mut rng = SmallRng::from_entropy();
846
847        assert!(Self::G::new_gnm_connected(4, 20, &mut rng).is_none());
848        assert!(Self::G::new_gnm_connected(4, 2, &mut rng).is_none());
849
850        for n in 1..10 {
851            for m in (n - 1)..30 {
852                if let Some(g) = Self::G::new_gnm_connected(n, m, &mut rng) {
853                    assert!(g.is_connected());
854                    assert_eq!(n, g.num_vertices());
855                    assert_eq!(m, g.num_edges());
856                }
857            }
858        }
859    }
860
861    fn regular()
862    where
863        Self::G: Adjacency + WithEdge<Kind = Undirected> + VertexList,
864    {
865        use algs::degrees::Degrees;
866        let mut rng = SmallRng::from_entropy();
867        for d in 1..9 {
868            for n in (d + 1)..30 {
869                let g = Self::G::new_regular(d, n, &mut rng);
870                if n * d % 2 == 0 {
871                    assert!(g.unwrap().is_k_regular(d));
872                } else {
873                    assert!(g.is_none());
874                }
875            }
876        }
877    }
878}
879
880#[doc(hidden)]
881#[macro_export]
882macro_rules! graph_builder_tests {
883    ($T:ident) => {
884        delegate_tests!{
885            $T,
886            graph_macro,
887            graph_prop_macro,
888            complete,
889            complete_binary_tree,
890            random_tree,
891            gnm,
892            gnm_connected,
893            regular
894        }
895    };
896}
897
898#[cfg(test)]
899mod tests {
900    use super::*;
901
902    #[test]
903    fn random_tree_mean_diameter() {
904        let mut rng = SmallRng::from_entropy();
905        let n = 100;
906        let times = 1000;
907        let sum: Result<usize, _> = (0..times)
908            .map(|_| StaticGraph::new_random_tree(n, &mut rng).tree_diameter())
909            .sum();
910        let mean = sum.unwrap() / times;
911        assert!(27 == mean || 28 == mean || 29 == mean);
912    }
913}