graphalgs/
metrics.rs

1//! Basic graph characteristics based on the concept of distance between vertices.
2
3use std::collections::{HashSet, VecDeque};
4
5use crate::shortest_path::{floyd_warshall, shortest_distances};
6use petgraph::algo::{bellman_ford, FloatMeasure};
7use petgraph::visit::{
8    GraphProp, IntoEdgeReferences, IntoEdges, IntoNeighbors, IntoNodeIdentifiers, NodeCount,
9    NodeIndexable, Visitable,
10};
11
12/// Vertex eccentricity.
13///
14/// Calculate the eccentricity of a vertex ```node``` of the graph ```graph```.
15///
16/// # Examples
17///
18/// ```
19/// use graphalgs::metrics::eccentricity;
20/// use petgraph::Graph;
21///
22/// let graph = Graph::<(), ()>::from_edges(&[(0, 1), (1, 0), (1, 2)]);
23///
24/// assert_eq!(eccentricity(&graph, 0.into()), 2.0);
25/// assert_eq!(eccentricity(&graph, 1.into()), 1.0);
26/// assert_eq!(eccentricity(&graph, 2.into()), f32::INFINITY);
27/// ```
28pub fn eccentricity<G>(graph: G, node: G::NodeId) -> f32
29where
30    G: Visitable + NodeIndexable + IntoEdges + IntoNeighbors,
31{
32    *shortest_distances(graph, node)
33        .iter()
34        .max_by(|x, y| x.partial_cmp(y).unwrap())
35        .unwrap()
36}
37
38/// Graph radius.
39///
40/// Calculate the radius of a graph ```graph```.
41/// Returns ```Option<f32>```, ```None``` will be in case there are no vertices in the graph.
42/// If the graph radius is infinity, then the result of the algorithm will be ```f32::INFINITY```.
43///
44/// # Examples
45///
46/// ```
47/// use graphalgs::metrics::radius;
48/// use petgraph::Graph;
49///
50/// let graph = Graph::<(), ()>::from_edges(&[(0, 1), (1, 0), (1, 2)]);
51///
52/// assert_eq!(radius(&graph), Some(1.0));
53/// ```
54pub fn radius<G>(graph: G) -> Option<f32>
55where
56    G: Visitable + NodeIndexable + IntoEdges + IntoNeighbors + IntoNodeIdentifiers + NodeCount,
57{
58    if graph.node_count() == 0 {
59        return None;
60    }
61
62    graph
63        .node_identifiers()
64        .map(|i| eccentricity(graph, i))
65        .min_by(|x, y| x.partial_cmp(y).unwrap())
66}
67
68/// Graph diameter.
69///
70/// Calculate the diameter of a graph ```graph```.
71/// Returns ```Option<f32>```, ```None``` will be in case there are no vertices in the graph.
72/// If the graph diameter is infinity, then the result of the algorithm will be ```f32::INFINITY```.
73///
74/// # Examples
75///
76/// ```
77/// use graphalgs::metrics::diameter;
78/// use petgraph::Graph;
79///
80/// let graph = Graph::<(), ()>::from_edges(&[(0, 1), (1, 0), (1, 2)]);
81///
82/// assert_eq!(diameter(&graph), Some(f32::INFINITY));
83/// ```
84pub fn diameter<G>(graph: G) -> Option<f32>
85where
86    G: Visitable + NodeIndexable + IntoEdges + IntoNeighbors + IntoNodeIdentifiers + NodeCount,
87{
88    if graph.node_count() == 0 {
89        return None;
90    }
91
92    let mut diam = 0f32;
93    for i in graph.node_identifiers() {
94        diam = diam.max(eccentricity(graph, i));
95        if diam == f32::INFINITY {
96            break;
97        }
98    }
99
100    Some(diam)
101}
102
103/// Central vertices of the graph.
104///
105/// Returns a vector of indices of the central vertices of the graph.
106/// Here, the central vertices are the vertices with the minimum eccentricity.
107///
108/// # Examples
109///
110/// ```
111/// use graphalgs::metrics::center;
112/// use petgraph::Graph;
113///
114/// let graph = Graph::<(), ()>::from_edges(&[(0, 1), (1, 0), (1, 2)]);
115///
116/// assert_eq!(center(&graph), vec![1.into()]);
117/// ```
118pub fn center<G>(graph: G) -> Vec<G::NodeId>
119where
120    G: Visitable + NodeIndexable + IntoEdges + IntoNodeIdentifiers,
121{
122    // Vector of vertex eccentricities to avoid repeated computation.
123    let ecc = graph
124        .node_identifiers()
125        .map(|i| eccentricity(graph, i))
126        .collect::<Vec<f32>>();
127
128    match ecc.iter().min_by(|x, y| x.partial_cmp(y).unwrap()) {
129        None => vec![],
130        Some(&r) => graph
131            .node_identifiers()
132            .enumerate()
133            .filter(|(i, _)| ecc[*i] == r)
134            .map(|(_, node_id)| node_id)
135            .collect(),
136    }
137}
138
139/// Peripheral graph vertices.
140///
141/// Returns a vector of indices of the peripheral vertices of the graph.
142///
143/// # Examples
144///
145/// ```
146/// use graphalgs::metrics::periphery;
147/// use petgraph::Graph;
148///
149/// let graph = Graph::<(), ()>::from_edges(&[(0, 1), (1, 0), (1, 2)]);
150///
151/// assert_eq!(periphery(&graph), vec![2.into()]);
152/// ```
153pub fn periphery<G>(graph: G) -> Vec<G::NodeId>
154where
155    G: Visitable + NodeIndexable + IntoEdges + IntoNodeIdentifiers,
156{
157    // Vector of vertex eccentricities to avoid repeated computation.
158    let ecc = graph
159        .node_identifiers()
160        .map(|i| eccentricity(graph, i))
161        .collect::<Vec<f32>>();
162
163    match ecc.iter().max_by(|x, y| x.partial_cmp(y).unwrap()) {
164        None => vec![], // There are no vertices in the graph.
165        Some(&d) => graph
166            .node_identifiers()
167            .enumerate()
168            .filter(|(i, _)| ecc[*i] == d)
169            .map(|(_, node_id)| node_id)
170            .collect(),
171    }
172}
173
174/// Weighted eccentricity.
175///
176/// Calculate the distance to the node farthest from `start`, given the edge weights.
177/// The function is based on the [Bellman-Ford algorithm](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)
178/// and has a time complexity of **O(|V|*|E|)**. So if edge weight is not important it is better to use `eccentricity()` function.
179///
180/// ## Arguments
181/// * `graph`: weighted graph.
182/// * `start`: node whose eccentricity is to be calculated.
183///
184/// ## Returns
185/// * `Some(G::EdgeWeight)`: the eccentricity.
186/// * `None`: if graph contains negative cycle.
187///
188/// # Examples
189///
190/// ```
191/// use graphalgs::metrics::weighted_eccentricity;
192/// use petgraph::Graph;
193///
194/// let inf = f32::INFINITY;
195///
196/// let graph = Graph::<(), f32>::from_edges(&[
197///     (0, 1, 2.0), (1, 2, 10.0), (1, 3, -5.0),
198///     (3, 2, 2.0), (2, 3, 20.0),
199/// ]);
200///
201/// assert_eq!(weighted_eccentricity(&graph, 0.into()), Some(2.0));
202/// assert_eq!(weighted_eccentricity(&graph, 1.into()), Some(inf));
203/// assert_eq!(weighted_eccentricity(&graph, 2.into()), Some(inf));
204/// assert_eq!(weighted_eccentricity(&graph, 3.into()), Some(inf));
205///
206/// // Negative cycle.
207/// let graph = Graph::<(), f32>::from_edges(&[
208///     (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)
209/// ]);
210///
211/// assert_eq!(weighted_eccentricity(&graph, 0.into()), None);
212/// assert_eq!(weighted_eccentricity(&graph, 1.into()), None);
213/// assert_eq!(weighted_eccentricity(&graph, 2.into()), None);
214/// ```
215pub fn weighted_eccentricity<G>(graph: G, start: G::NodeId) -> Option<G::EdgeWeight>
216where
217    G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable,
218    G::EdgeWeight: FloatMeasure,
219{
220    if let Ok(bm_res) = bellman_ford(graph, start) {
221        Some(
222            bm_res
223                .distances
224                .into_iter()
225                .max_by(|&x, &y| x.partial_cmp(&y).unwrap())
226                .unwrap(),
227        )
228    } else {
229        None
230    }
231}
232
233/// Weighted graph radius.
234///
235/// Calculate the radius of the graph given the edge weights.
236/// The function is based on the [Floyd–Warshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
237/// and has a time complexity of **O(|V|^3)**.
238/// So if edge weights is not important it is better to use `radius()` function.
239///
240/// ## Arguments
241/// * `graph`: weighted graph.
242/// * `edge_cost`: closure that returns weight of a particular edge.
243///
244/// ## Returns
245/// * `Some`: the radius of the graph.
246/// * `None`: if the graph contains a negative cycle or has no vertices.
247///
248/// # Examples
249///
250/// ```
251/// use graphalgs::metrics::weighted_radius;
252/// use petgraph::Graph;
253///
254/// let graph = Graph::<(), f32>::from_edges(&[
255///     (0, 1, 2.0), (1, 2, 10.0), (1, 3, -5.0),
256///     (3, 2, 2.0), (2, 3, 20.0),
257/// ]);
258///
259/// assert_eq!(weighted_radius(&graph, |edge| *edge.weight()), Some(2.0));
260///
261/// // Negative cycle.
262/// let graph = Graph::<(), f32>::from_edges(&[
263///     (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)
264/// ]);
265///
266/// assert_eq!(weighted_radius(&graph, |edge| *edge.weight()), None);
267/// ```
268pub fn weighted_radius<G, F, K>(graph: G, edge_cost: F) -> Option<K>
269where
270    G: IntoEdgeReferences + IntoNodeIdentifiers + NodeIndexable + NodeCount + GraphProp,
271    F: FnMut(G::EdgeRef) -> K,
272    K: FloatMeasure,
273{
274    if graph.node_count() == 0 {
275        return None;
276    }
277
278    let distances = floyd_warshall(graph, edge_cost);
279
280    if distances.is_err() {
281        return None; // The graph contains a negative cycle.
282    }
283
284    distances
285        .unwrap()
286        .iter()
287        .map(|dist| {
288            *dist
289                .iter()
290                .max_by(|x, y| x.partial_cmp(y).unwrap())
291                .unwrap()
292        })
293        .min_by(|x, y| x.partial_cmp(y).unwrap())
294}
295
296/// Weighted graph diameter.
297///
298/// Calculate the diameter of the graph given the edge weights.
299/// The function is based on the [Floyd–Warshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
300/// and has a time complexity of **O(|V|^3)**.
301/// So if edge weights is not important it is better to use `diameter()` function.
302///
303/// ## Arguments
304/// * `graph`: weighted graph.
305/// * `edge_cost`: closure that returns weight of a particular edge.
306///
307/// ## Returns
308/// * `Some`: the diameter of the graph.
309/// * `None`: if the graph contains a negative cycle or has no vertices.
310///
311/// # Examples
312///
313/// ```
314/// use graphalgs::metrics::weighted_diameter;
315/// use petgraph::Graph;
316///
317/// let inf = f32::INFINITY;
318///
319/// let graph = Graph::<(), f32>::from_edges(&[
320///     (0, 1, 2.0), (1, 2, 10.0), (1, 3, -5.0),
321///     (3, 2, 2.0), (2, 3, 20.0),
322/// ]);
323///
324/// assert_eq!(weighted_diameter(&graph, |edge| *edge.weight()), Some(inf));
325///
326/// // Negative cycle.
327/// let graph = Graph::<(), f32>::from_edges(&[
328///     (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)
329/// ]);
330///
331/// assert_eq!(weighted_diameter(&graph, |edge| *edge.weight()), None);
332/// ```
333pub fn weighted_diameter<G, F, K>(graph: G, edge_cost: F) -> Option<K>
334where
335    G: IntoEdgeReferences + IntoNodeIdentifiers + NodeIndexable + NodeCount + GraphProp,
336    F: FnMut(G::EdgeRef) -> K,
337    K: FloatMeasure,
338{
339    if graph.node_count() == 0 {
340        return None;
341    }
342
343    let distances = floyd_warshall(graph, edge_cost);
344
345    if distances.is_err() {
346        return None; // The graph contains a negative cycle.
347    }
348
349    let mut diam = K::zero();
350    for dist in distances.unwrap().iter() {
351        for d in dist.iter() {
352            if *d == K::infinite() {
353                return Some(*d);
354            } else if *d > diam {
355                diam = *d;
356            }
357        }
358    }
359
360    Some(diam)
361}
362
363/// Center of a weighted graph.
364///
365/// Calculate the central nodes of the graph given the edge weights.
366/// The function is based on the [Floyd–Warshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
367/// and has a time complexity of **O(|V|^3)**.
368/// So if edge weights is not important it is better to use `center()` function.
369///
370/// ## Arguments
371/// * `graph`: weighted graph.
372/// * `edge_cost`: closure that returns weight of a particular edge.
373///
374/// ## Returns
375/// * A vector of indices of central vertices.
376/// * `vec![]`: if the graph contains a negative cycle.
377///
378/// ```
379/// use graphalgs::metrics::weighted_center;
380/// use petgraph::Graph;
381///
382/// let graph = Graph::<(), f32>::from_edges(&[
383///     (0, 1, 2.0), (1, 2, 10.0), (1, 3, -5.0),
384///     (3, 2, 2.0), (2, 3, 20.0), (3, 0, 3.0),
385/// ]);
386///
387/// assert_eq!(weighted_center(&graph, |edge| *edge.weight()), vec![1.into()]);
388///
389/// // Negative cycle.
390/// let graph = Graph::<(), f32>::from_edges(&[
391///     (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)
392/// ]);
393///
394/// assert_eq!(weighted_center(&graph, |edge| *edge.weight()), vec![]);
395/// ```
396pub fn weighted_center<G, F, K>(graph: G, edge_cost: F) -> Vec<G::NodeId>
397where
398    G: IntoEdgeReferences + IntoNodeIdentifiers + NodeIndexable + NodeCount + GraphProp,
399    F: FnMut(G::EdgeRef) -> K,
400    K: FloatMeasure,
401{
402    if graph.node_count() == 0 {
403        return vec![];
404    }
405
406    let distances = floyd_warshall(graph, edge_cost);
407
408    if distances.is_err() {
409        return vec![]; // The graph contains a negative cycle.
410    }
411
412    // Vector of node eccentricities.
413    let ecc = distances
414        .unwrap()
415        .iter()
416        .map(|dist| {
417            *dist
418                .iter()
419                .max_by(|x, y| x.partial_cmp(y).unwrap())
420                .unwrap()
421        })
422        .collect::<Vec<K>>();
423
424    // Graph radius.
425    let rad = *ecc.iter().min_by(|x, y| x.partial_cmp(y).unwrap()).unwrap();
426
427    (0..graph.node_bound())
428        .filter(|i| ecc[*i] == rad)
429        .map(|i| graph.from_index(i))
430        .collect()
431}
432
433/// Peripheral vertices of a weighted graph.
434///
435/// Calculate the peripheral vertices of the graph given the edge weights.
436/// The function is based on the [Floyd–Warshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
437/// and has a time complexity of **O(|V|^3)**.
438/// So if edge weights is not important it is better to use `periphery()` function.
439///
440/// ## Arguments
441/// * `graph`: weighted graph.
442/// * `edge_cost`: closure that returns weight of a particular edge.
443///
444/// ## Returns
445/// * A vector of indices of peripheral vertices.
446/// * `vec![]`: if the graph contains a negative cycle.
447///
448/// ```
449/// use graphalgs::metrics::weighted_periphery;
450/// use petgraph::Graph;
451///
452/// let graph = Graph::<(), f32>::from_edges(&[
453///     (0, 1, 2.0), (1, 2, 10.0), (1, 3, -5.0),
454///     (3, 2, 2.0), (2, 3, 20.0), (3, 0, 3.0),
455/// ]);
456///
457/// assert_eq!(weighted_periphery(&graph, |edge| *edge.weight()), vec![2.into()]);
458///
459/// // Negative cycle.
460/// let graph = Graph::<(), f32>::from_edges(&[
461///     (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)
462/// ]);
463///
464/// assert_eq!(weighted_periphery(&graph, |edge| *edge.weight()), vec![]);
465/// ```
466pub fn weighted_periphery<G, F, K>(graph: G, edge_cost: F) -> Vec<G::NodeId>
467where
468    G: IntoEdgeReferences + IntoNodeIdentifiers + NodeIndexable + NodeCount + GraphProp,
469    F: FnMut(G::EdgeRef) -> K,
470    K: FloatMeasure,
471{
472    if graph.node_count() == 0 {
473        return vec![];
474    }
475
476    let distances = floyd_warshall(graph, edge_cost);
477
478    if distances.is_err() {
479        return vec![]; // The graph contains a negative cycle.
480    }
481
482    // Vector of node eccentricities.
483    let ecc = distances
484        .unwrap()
485        .iter()
486        .map(|dist| {
487            *dist
488                .iter()
489                .max_by(|x, y| x.partial_cmp(y).unwrap())
490                .unwrap()
491        })
492        .collect::<Vec<K>>();
493
494    // Graph diameter.
495    let diam = *ecc.iter().max_by(|x, y| x.partial_cmp(y).unwrap()).unwrap();
496
497    (0..graph.node_bound())
498        .filter(|i| ecc[*i] == diam)
499        .map(|i| graph.from_index(i))
500        .collect()
501}
502
503/// Girth of a simple graph.
504///
505/// Calculate the girth of a simple graph (directed or undirected).
506///
507/// # Examples
508///
509/// ```
510/// use graphalgs::metrics::girth;
511/// use petgraph::graph::{ Graph, UnGraph };
512///
513/// // Create the following graph:
514/// // 1 --- 2
515/// // |     |
516/// // 0     3
517///
518/// let mut g = UnGraph::new_undirected();
519/// let n0 = g.add_node(());
520/// let n1 = g.add_node(());
521/// let n2 = g.add_node(());
522/// let n3 = g.add_node(());
523/// g.add_edge(n0, n1, ());
524/// g.add_edge(n1, n2, ());
525/// g.add_edge(n2, n3, ());
526///
527/// // The graph is acyclic and its girth is infinite.
528/// assert_eq!(girth(&g), f32::INFINITY);
529///
530/// // Add an edge {3, 0} and create a cycle in the graph.
531/// g.add_edge(n3, n0, ());
532/// assert_eq!(girth(&g), 4.0);
533/// ```
534pub fn girth<G>(graph: G) -> f32
535where
536    G: Visitable + NodeIndexable + IntoEdges + IntoNodeIdentifiers + GraphProp,
537{
538    let mut best = f32::INFINITY;
539
540    if graph.is_directed() {
541        let mut stack = Vec::<usize>::new();
542        let mut used = vec![false; graph.node_bound()];
543
544        for start in 0..graph.node_bound() {
545            if used[start] {
546                continue;
547            }
548
549            stack.push(start);
550            let mut depth = vec![0usize; graph.node_bound()];
551            let mut predecessors = (0..graph.node_bound())
552                .map(|_| HashSet::<usize>::new())
553                .collect::<Vec<HashSet<usize>>>();
554
555            while let Some(current) = stack.pop() {
556                if !used[current] {
557                    used[current] = true;
558                    let d = depth[current];
559
560                    for nb in graph.neighbors(graph.from_index(current)) {
561                        let v = graph.to_index(nb);
562                        if used[v] {
563                            if predecessors[current].contains(&v) {
564                                best = best.min((depth[current] - depth[v] + 1) as f32);
565                            }
566                        } else {
567                            depth[v] = d + 1;
568                            stack.push(v);
569                            predecessors[v] = predecessors[v]
570                                .union(&predecessors[current])
571                                .cloned()
572                                .collect();
573                            predecessors[v].insert(current);
574                        }
575                    }
576                }
577                if best == 2.0 {
578                    return 2.0;
579                }
580            }
581        }
582    } else {
583        for start in 0..graph.node_bound() {
584            let mut queue = VecDeque::<usize>::new();
585            queue.push_back(start);
586
587            let mut used = vec![false; graph.node_bound()];
588            let mut depth = vec![0usize; graph.node_bound()];
589            let mut inp = vec![None; graph.node_bound()];
590
591            while !queue.is_empty() {
592                let current = queue.pop_front().unwrap();
593                let d = depth[current] + 1;
594
595                for nb in graph.neighbors(graph.from_index(current)) {
596                    let v = graph.to_index(nb);
597                    if used[v] {
598                        if inp[current] == Some(v) {
599                            continue;
600                        }
601                        if depth[v] == d - 1 {
602                            best = best.min((d * 2 - 1) as f32);
603                        } else if depth[v] == d {
604                            best = best.min((d * 2) as f32);
605                        }
606                    } else {
607                        used[v] = true;
608                        queue.push_back(v);
609                        depth[v] = d;
610                        inp[v] = Some(current);
611                    }
612                }
613            }
614
615            if best == 3.0 {
616                return 3.0;
617            }
618        }
619    }
620
621    best
622}
623
624#[cfg(test)]
625mod tests {
626    use super::*;
627    use petgraph::graph::{Graph, UnGraph};
628
629    fn graph1() -> Graph<(), ()> {
630        let mut graph = Graph::<(), ()>::new();
631        let n0 = graph.add_node(());
632        let n1 = graph.add_node(());
633        let n2 = graph.add_node(());
634        let n3 = graph.add_node(());
635        let n4 = graph.add_node(());
636        let n5 = graph.add_node(());
637        let n6 = graph.add_node(());
638        let n7 = graph.add_node(());
639        let n8 = graph.add_node(());
640        let n9 = graph.add_node(());
641        let n10 = graph.add_node(());
642        let n11 = graph.add_node(());
643
644        graph.add_edge(n0, n1, ());
645        graph.add_edge(n0, n2, ());
646        graph.add_edge(n2, n3, ());
647        graph.add_edge(n2, n5, ());
648        graph.add_edge(n3, n4, ());
649        graph.add_edge(n4, n8, ());
650        graph.add_edge(n5, n9, ());
651        graph.add_edge(n5, n6, ());
652        graph.add_edge(n6, n3, ());
653        graph.add_edge(n6, n7, ());
654        graph.add_edge(n6, n10, ());
655        graph.add_edge(n7, n8, ());
656        graph.add_edge(n7, n11, ());
657        graph.add_edge(n8, n11, ());
658        graph.add_edge(n9, n1, ());
659        graph.add_edge(n9, n10, ());
660        graph.add_edge(n10, n6, ());
661        graph.add_edge(n11, n6, ());
662        graph.add_edge(n11, n10, ());
663        graph.add_edge(n0, n9, ());
664
665        graph
666    }
667
668    fn graph2() -> Graph<(), ()> {
669        let mut graph = Graph::<(), ()>::new();
670        let n0 = graph.add_node(());
671        let n1 = graph.add_node(());
672        let n2 = graph.add_node(());
673        let n3 = graph.add_node(());
674        let n4 = graph.add_node(());
675        let n5 = graph.add_node(());
676        let n6 = graph.add_node(());
677
678        graph.add_edge(n0, n6, ());
679        graph.add_edge(n0, n1, ());
680        graph.add_edge(n1, n0, ());
681        graph.add_edge(n1, n2, ());
682        graph.add_edge(n1, n5, ());
683        graph.add_edge(n1, n6, ());
684        graph.add_edge(n2, n1, ());
685        graph.add_edge(n2, n3, ());
686        graph.add_edge(n3, n2, ());
687        graph.add_edge(n3, n4, ());
688        graph.add_edge(n4, n3, ());
689        graph.add_edge(n4, n5, ());
690        graph.add_edge(n5, n2, ());
691        graph.add_edge(n5, n6, ());
692        graph.add_edge(n5, n1, ());
693        graph.add_edge(n5, n4, ());
694        graph.add_edge(n6, n0, ());
695        graph.add_edge(n6, n1, ());
696        graph.add_edge(n6, n5, ());
697        graph.add_edge(n2, n5, ());
698
699        graph
700    }
701
702    fn graph3() -> Graph<(), f32> {
703        let mut graph = Graph::<(), f32>::new();
704        graph.add_node(());
705        graph
706    }
707
708    fn graph4() -> Graph<(), f32> {
709        Graph::<(), f32>::new()
710    }
711
712    fn graph5() -> Graph<(), f32> {
713        let mut graph = Graph::new();
714        let n0 = graph.add_node(());
715        let n1 = graph.add_node(());
716        let n2 = graph.add_node(());
717        let n3 = graph.add_node(());
718        let n4 = graph.add_node(());
719        let n5 = graph.add_node(());
720
721        graph.add_edge(n1, n0, 10.0);
722        graph.add_edge(n1, n0, 10.0);
723        graph.add_edge(n0, n3, 14.0);
724        graph.add_edge(n3, n0, 14.0);
725        graph.add_edge(n1, n2, 5.0);
726        graph.add_edge(n2, n1, -5.0);
727        graph.add_edge(n2, n3, 1.0);
728        graph.add_edge(n3, n2, 1.0);
729        graph.add_edge(n2, n4, 3.0);
730        graph.add_edge(n4, n2, 3.0);
731        graph.add_edge(n3, n5, -1.0);
732
733        graph
734    }
735
736    fn graph6() -> Graph<(), f32> {
737        let mut graph = Graph::new();
738        graph.add_node(());
739        graph.add_node(());
740
741        graph
742    }
743
744    fn graph7() -> UnGraph<(), ()> {
745        let mut graph = UnGraph::<(), ()>::new_undirected();
746        let n0 = graph.add_node(());
747        let n1 = graph.add_node(());
748        let n2 = graph.add_node(());
749        let n3 = graph.add_node(());
750        let n4 = graph.add_node(());
751        let n5 = graph.add_node(());
752        let n6 = graph.add_node(());
753
754        graph.add_edge(n0, n6, ());
755        graph.add_edge(n0, n1, ());
756        graph.add_edge(n1, n2, ());
757        graph.add_edge(n1, n5, ());
758        graph.add_edge(n2, n3, ());
759        graph.add_edge(n3, n4, ());
760        graph.add_edge(n4, n5, ());
761        graph.add_edge(n5, n2, ());
762        graph.add_edge(n6, n1, ());
763        graph.add_edge(n6, n5, ());
764
765        graph
766    }
767
768    #[test]
769    fn test_eccentricity() {
770        let inf = f32::INFINITY;
771
772        let g = graph1();
773        assert_eq!(eccentricity(&g, 0.into()), 5.0);
774        for i in 1..12 {
775            assert_eq!(eccentricity(&g, i.into()), inf);
776        }
777
778        let g = graph2();
779        assert_eq!(eccentricity(&g, 0.into()), 3.0);
780        assert_eq!(eccentricity(&g, 1.into()), 2.0);
781        assert_eq!(eccentricity(&g, 2.into()), 2.0);
782        assert_eq!(eccentricity(&g, 3.into()), 3.0);
783        assert_eq!(eccentricity(&g, 4.into()), 3.0);
784        assert_eq!(eccentricity(&g, 5.into()), 2.0);
785        assert_eq!(eccentricity(&g, 6.into()), 3.0);
786
787        let g = graph3();
788        assert_eq!(eccentricity(&g, 0.into()), 0.0);
789    }
790
791    #[test]
792    fn test_radius() {
793        let inf = f32::INFINITY;
794
795        assert_eq!(radius(&graph1()), Some(5.0));
796        assert_eq!(radius(&graph2()), Some(2.0));
797        assert_eq!(radius(&graph3()), Some(0.0));
798        assert_eq!(radius(&graph4()), None);
799        assert_eq!(radius(&graph5()), Some(2.0));
800        assert_eq!(radius(&graph6()), Some(inf));
801    }
802
803    #[test]
804    fn test_diameter() {
805        let inf = f32::INFINITY;
806
807        assert_eq!(diameter(&graph1()), Some(inf));
808        assert_eq!(diameter(&graph2()), Some(3.0));
809        assert_eq!(diameter(&graph3()), Some(0.0));
810        assert_eq!(diameter(&graph4()), None);
811        assert_eq!(diameter(&graph5()), Some(inf));
812        assert_eq!(diameter(&graph6()), Some(inf));
813    }
814
815    #[test]
816    fn test_center() {
817        assert_eq!(center(&graph1()), vec![0.into()]);
818        assert_eq!(center(&graph2()), vec![1.into(), 2.into(), 5.into()]);
819        assert_eq!(center(&graph3()), vec![0.into()]);
820        assert_eq!(center(&graph4()), vec![]);
821        assert_eq!(center(&graph5()), vec![2.into(), 3.into()]);
822        assert_eq!(center(&graph6()), vec![0.into(), 1.into()]);
823    }
824
825    #[test]
826    fn test_periphery() {
827        assert_eq!(
828            periphery(&graph1()),
829            vec![
830                1.into(),
831                2.into(),
832                3.into(),
833                4.into(),
834                5.into(),
835                6.into(),
836                7.into(),
837                8.into(),
838                9.into(),
839                10.into(),
840                11.into()
841            ]
842        );
843        assert_eq!(
844            periphery(&graph2()),
845            vec![0.into(), 3.into(), 4.into(), 6.into()]
846        );
847        assert_eq!(periphery(&graph3()), vec![0.into()]);
848        assert_eq!(periphery(&graph4()), vec![]);
849        assert_eq!(periphery(&graph5()), vec![5.into()]);
850        assert_eq!(periphery(&graph6()), vec![0.into(), 1.into()]);
851    }
852
853    #[test]
854    fn test_weighted_eccentricity() {
855        let inf = f32::INFINITY;
856
857        let g = graph3();
858        assert_eq!(weighted_eccentricity(&g, 0.into()), Some(0.0));
859
860        let graph = graph5();
861        assert_eq!(weighted_eccentricity(&graph, 0.into()), Some(18.0));
862        assert_eq!(weighted_eccentricity(&graph, 1.into()), Some(10.0));
863        assert_eq!(weighted_eccentricity(&graph, 2.into()), Some(5.0));
864        assert_eq!(weighted_eccentricity(&graph, 3.into()), Some(6.0));
865        assert_eq!(weighted_eccentricity(&graph, 4.into()), Some(8.0));
866        assert_eq!(weighted_eccentricity(&graph, 5.into()), Some(inf));
867    }
868
869    #[test]
870    fn test_weighted_radius() {
871        let inf = f32::INFINITY;
872
873        assert_eq!(weighted_radius(&graph1(), |_| 1.0), Some(5.0));
874        assert_eq!(weighted_radius(&graph2(), |_| 2.0), Some(4.0));
875        assert_eq!(weighted_radius(&graph3(), |edge| *edge.weight()), Some(0.0));
876        assert_eq!(weighted_radius(&graph4(), |edge| *edge.weight()), None);
877        assert_eq!(weighted_radius(&graph5(), |edge| *edge.weight()), Some(5.0));
878        assert_eq!(weighted_radius(&graph6(), |edge| *edge.weight()), Some(inf));
879    }
880
881    #[test]
882    fn test_weighted_diameter() {
883        let inf = f32::INFINITY;
884
885        assert_eq!(weighted_diameter(&graph1(), |_| 1.0), Some(inf));
886        assert_eq!(weighted_diameter(&graph2(), |_| 2.0), Some(6.0));
887        assert_eq!(
888            weighted_diameter(&graph3(), |edge| *edge.weight()),
889            Some(0.0)
890        );
891        assert_eq!(weighted_diameter(&graph4(), |edge| *edge.weight()), None);
892        assert_eq!(
893            weighted_diameter(&graph5(), |edge| *edge.weight()),
894            Some(inf)
895        );
896        assert_eq!(
897            weighted_diameter(&graph6(), |edge| *edge.weight()),
898            Some(inf)
899        );
900    }
901
902    #[test]
903    fn test_weighted_center() {
904        assert_eq!(weighted_center(&graph1(), |_| 1.0), vec![0.into()]);
905        assert_eq!(
906            weighted_center(&graph2(), |_| 2.0),
907            vec![1.into(), 2.into(), 5.into()]
908        );
909        assert_eq!(
910            weighted_center(&graph3(), |edge| *edge.weight()),
911            vec![0.into()]
912        );
913        assert_eq!(weighted_center(&graph4(), |edge| *edge.weight()), vec![]);
914        assert_eq!(
915            weighted_center(&graph5(), |edge| *edge.weight()),
916            vec![2.into()]
917        );
918        assert_eq!(
919            weighted_center(&graph6(), |edge| *edge.weight()),
920            vec![0.into(), 1.into()]
921        );
922    }
923
924    #[test]
925    fn test_weighted_periphery() {
926        assert_eq!(
927            weighted_periphery(&graph1(), |_| 1.0),
928            vec![
929                1.into(),
930                2.into(),
931                3.into(),
932                4.into(),
933                5.into(),
934                6.into(),
935                7.into(),
936                8.into(),
937                9.into(),
938                10.into(),
939                11.into()
940            ]
941        );
942        assert_eq!(
943            weighted_periphery(&graph2(), |_| 2.0),
944            vec![0.into(), 3.into(), 4.into(), 6.into()]
945        );
946        assert_eq!(
947            weighted_periphery(&graph3(), |edge| *edge.weight()),
948            vec![0.into()]
949        );
950        assert_eq!(weighted_periphery(&graph4(), |edge| *edge.weight()), vec![]);
951        assert_eq!(
952            weighted_periphery(&graph5(), |edge| *edge.weight()),
953            vec![5.into()]
954        );
955        assert_eq!(
956            weighted_periphery(&graph6(), |edge| *edge.weight()),
957            vec![0.into(), 1.into()]
958        );
959    }
960
961    #[test]
962    fn test_girth() {
963        assert_eq!(girth(&Graph::<(), ()>::new()), f32::INFINITY);
964        assert_eq!(girth(&UnGraph::<(), ()>::new_undirected()), f32::INFINITY);
965        assert_eq!(girth(&graph1()), 2.0);
966        assert_eq!(girth(&graph5()), 2.0);
967        assert_eq!(girth(&graph7()), 3.0);
968
969        let mut g = Graph::<i32, ()>::new();
970        let n0 = g.add_node(0);
971        assert_eq!(girth(&g), f32::INFINITY);
972        let n1 = g.add_node(1);
973        assert_eq!(girth(&g), f32::INFINITY);
974        g.add_edge(n0, n1, ());
975        assert_eq!(girth(&g), f32::INFINITY);
976        g.add_edge(n0, n1, ());
977        assert_eq!(girth(&g), f32::INFINITY);
978        g.add_edge(n1, n0, ());
979        assert_eq!(girth(&g), 2.0);
980
981        let mut g = UnGraph::<i32, ()>::new_undirected();
982        let n0 = g.add_node(0);
983        assert_eq!(girth(&g), f32::INFINITY);
984        let n1 = g.add_node(1);
985        assert_eq!(girth(&g), f32::INFINITY);
986        g.add_edge(n0, n1, ());
987        assert_eq!(girth(&g), f32::INFINITY);
988        let n2 = g.add_node(2);
989        g.add_edge(n0, n2, ());
990        assert_eq!(girth(&g), f32::INFINITY);
991        g.add_edge(n2, n1, ());
992        assert_eq!(girth(&g), 3.0);
993
994        let mut g = Graph::<i32, ()>::new();
995        let n0 = g.add_node(0);
996        g.add_edge(n0, n0, ());
997        assert_eq!(girth(&g), f32::INFINITY);
998    }
999}