1use 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
12pub 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
38pub 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
68pub 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
103pub fn center<G>(graph: G) -> Vec<G::NodeId>
119where
120 G: Visitable + NodeIndexable + IntoEdges + IntoNodeIdentifiers,
121{
122 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
139pub fn periphery<G>(graph: G) -> Vec<G::NodeId>
154where
155 G: Visitable + NodeIndexable + IntoEdges + IntoNodeIdentifiers,
156{
157 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![], 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
174pub 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
233pub 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; }
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
296pub 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; }
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
363pub 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![]; }
411
412 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 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
433pub 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![]; }
481
482 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 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
503pub 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}