scirs2_graph/algorithms/
properties.rs1use crate::algorithms::shortest_path::dijkstra_path;
6use crate::base::{EdgeWeight, Graph, IndexType, Node};
7use std::hash::Hash;
8
9#[allow(dead_code)]
14pub fn diameter<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Option<f64>
15where
16 N: Node + Clone + Hash + Eq + std::fmt::Debug,
17 E: EdgeWeight
18 + Into<f64>
19 + Clone
20 + scirs2_core::numeric::Zero
21 + scirs2_core::numeric::One
22 + std::cmp::PartialOrd
23 + std::fmt::Debug
24 + Copy
25 + Default,
26 Ix: IndexType,
27{
28 let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
29 let n = nodes.len();
30
31 if n == 0 {
32 return None;
33 }
34
35 let mut max_distance = 0.0;
36
37 for i in 0..n {
39 for j in i + 1..n {
40 match dijkstra_path(graph, &nodes[i], &nodes[j]) {
41 Ok(Some(path)) => {
42 let distance: f64 = path.total_weight.into();
43 if distance > max_distance {
44 max_distance = distance;
45 }
46 }
47 Ok(None) => return None, Err(_) => return None, }
50 }
51 }
52
53 Some(max_distance)
54}
55
56#[allow(dead_code)]
62pub fn radius<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Option<f64>
63where
64 N: Node + Clone + Hash + Eq + std::fmt::Debug,
65 E: EdgeWeight
66 + Into<f64>
67 + Clone
68 + scirs2_core::numeric::Zero
69 + scirs2_core::numeric::One
70 + std::cmp::PartialOrd
71 + std::fmt::Debug
72 + Copy
73 + Default,
74 Ix: IndexType,
75{
76 let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
77 let n = nodes.len();
78
79 if n == 0 {
80 return None;
81 }
82
83 let mut min_eccentricity = f64::INFINITY;
84
85 for i in 0..n {
87 let mut max_distance_from_i = 0.0;
88
89 for j in 0..n {
90 if i != j {
91 match dijkstra_path(graph, &nodes[i], &nodes[j]) {
92 Ok(Some(path)) => {
93 let distance: f64 = path.total_weight.into();
94 if distance > max_distance_from_i {
95 max_distance_from_i = distance;
96 }
97 }
98 Ok(None) => return None, Err(_) => return None, }
101 }
102 }
103
104 if max_distance_from_i < min_eccentricity {
105 min_eccentricity = max_distance_from_i;
106 }
107 }
108
109 Some(min_eccentricity)
110}
111
112#[allow(dead_code)]
117pub fn center_nodes<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Vec<N>
118where
119 N: Node + Clone + Hash + Eq + std::fmt::Debug,
120 E: EdgeWeight
121 + Into<f64>
122 + Clone
123 + scirs2_core::numeric::Zero
124 + scirs2_core::numeric::One
125 + std::cmp::PartialOrd
126 + std::fmt::Debug
127 + Copy
128 + Default,
129 Ix: IndexType,
130{
131 let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
132 let n = nodes.len();
133
134 if n == 0 {
135 return vec![];
136 }
137
138 let mut eccentricities = vec![0.0; n];
139 let mut min_eccentricity = f64::INFINITY;
140
141 for i in 0..n {
143 let mut max_distance_from_i = 0.0;
144
145 for j in 0..n {
146 if i != j {
147 match dijkstra_path(graph, &nodes[i], &nodes[j]) {
148 Ok(Some(path)) => {
149 let distance: f64 = path.total_weight.into();
150 if distance > max_distance_from_i {
151 max_distance_from_i = distance;
152 }
153 }
154 Ok(None) => return vec![], Err(_) => return vec![], }
157 }
158 }
159
160 eccentricities[i] = max_distance_from_i;
161
162 if max_distance_from_i < min_eccentricity {
163 min_eccentricity = max_distance_from_i;
164 }
165 }
166
167 nodes
169 .into_iter()
170 .enumerate()
171 .filter(|(i, _)| (eccentricities[*i] - min_eccentricity).abs() < f64::EPSILON)
172 .map(|(_, node)| node)
173 .collect()
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179 use crate::error::Result as GraphResult;
180 use crate::generators::create_graph;
181
182 #[test]
183 fn test_diameter_radius_center() -> GraphResult<()> {
184 let mut path = create_graph::<i32, f64>();
186 path.add_edge(0, 1, 1.0)?;
187 path.add_edge(1, 2, 1.0)?;
188 path.add_edge(2, 3, 1.0)?;
189 path.add_edge(3, 4, 1.0)?;
190
191 assert_eq!(diameter(&path), Some(4.0));
193
194 assert_eq!(radius(&path), Some(2.0));
196
197 let centers = center_nodes(&path);
199 assert_eq!(centers.len(), 1);
200 assert_eq!(centers[0], 2);
201
202 Ok(())
203 }
204
205 #[test]
206 fn test_stargraph() -> GraphResult<()> {
207 let mut star = create_graph::<i32, f64>();
209 star.add_edge(0, 1, 1.0)?;
210 star.add_edge(0, 2, 1.0)?;
211 star.add_edge(0, 3, 1.0)?;
212 star.add_edge(0, 4, 1.0)?;
213
214 assert_eq!(diameter(&star), Some(2.0));
216
217 assert_eq!(radius(&star), Some(1.0));
219
220 let centers = center_nodes(&star);
222 assert_eq!(centers.len(), 1);
223 assert_eq!(centers[0], 0);
224
225 Ok(())
226 }
227
228 #[test]
229 fn test_disconnectedgraph() -> GraphResult<()> {
230 let mut graph = create_graph::<i32, f64>();
232 graph.add_edge(0, 1, 1.0)?;
233 graph.add_edge(2, 3, 1.0)?;
234
235 assert_eq!(diameter(&graph), None);
237 assert_eq!(radius(&graph), None);
238 assert!(center_nodes(&graph).is_empty());
239
240 Ok(())
241 }
242}