1use std::hash::Hash;
14
15use petgraph::algo::Measure;
16use petgraph::visit::{
17 IntoEdges, IntoNodeIdentifiers, NodeCount, NodeIndexable, VisitMap, Visitable,
18};
19
20#[derive(Debug, PartialEq, Eq)]
22pub struct NodeNotReachedError;
23
24pub fn greedy_routing_success_rate<G, F, K>(graph: G, distance: F) -> f64
47where
48 G: IntoEdges + NodeCount + NodeIndexable + IntoNodeIdentifiers + Visitable,
49 G::NodeId: Eq + Hash,
50 F: Fn(G::NodeId, G::NodeId) -> K,
51 K: Measure + Copy,
52{
53 let num_vertices = graph.node_count() as f64;
54 let num_successes = graph
55 .node_identifiers()
56 .flat_map(|u| graph.node_identifiers().map(move |v| (u, v)))
57 .map(|(u, v)| ((u != v) && greedy_routing(graph, u, v, &distance).is_ok()) as u32)
58 .sum::<u32>() as f64;
59 num_successes / (num_vertices * num_vertices - num_vertices)
60}
61
62pub fn greedy_routing<G, F, K>(
91 graph: G,
92 source: G::NodeId,
93 destination: G::NodeId,
94 distance: F,
95) -> Result<(Vec<G::NodeId>, K), NodeNotReachedError>
96where
97 G: IntoEdges + NodeCount + NodeIndexable + Visitable,
98 G::NodeId: Eq + Hash,
99 F: Fn(G::NodeId, G::NodeId) -> K,
100 K: Measure + Copy,
101{
102 if source == destination {
103 return Ok((vec![source], distance(source, destination)));
104 }
105 let mut visitmap = graph.visit_map();
106 let mut path: Vec<G::NodeId> = vec![source];
107 let mut total_distance = K::default();
108
109 let mut current_vertex = source;
110 while current_vertex != destination {
111 if visitmap.is_visited(¤t_vertex) {
112 return Err(NodeNotReachedError {});
113 }
114 visitmap.visit(current_vertex);
115
116 let mut min_distance = None;
117 let mut next = current_vertex;
118 for neighbor in graph.neighbors(current_vertex) {
119 let d = distance(neighbor, destination);
120 if min_distance.is_none() || d < min_distance.unwrap() {
121 next = neighbor;
122 min_distance = Some(d);
123 }
124 }
125 if min_distance.is_none() {
126 return Err(NodeNotReachedError {});
127 }
128 total_distance = total_distance + distance(current_vertex, next);
129 current_vertex = next;
130 path.push(current_vertex);
131 }
132 Ok((path, total_distance))
133}
134
135#[cfg(test)]
136mod tests {
137 use super::{NodeNotReachedError, greedy_routing, greedy_routing_success_rate};
138 use crate::geometry::distances;
139 use crate::petgraph::graph::UnGraph;
140 use petgraph::Graph;
141 use petgraph::visit::NodeIndexable;
142
143 fn distance1d<G>(graph: &G, positions: &[f64], u: G::NodeId, v: G::NodeId) -> f64
144 where
145 G: NodeIndexable,
146 {
147 distances::lp_distance(
148 &[positions[graph.to_index(u)]],
149 &[positions[graph.to_index(v)]],
150 1,
151 )
152 .unwrap()
153 }
154 fn distance2d<G>(graph: &G, positions: &[[f64; 2]], u: G::NodeId, v: G::NodeId) -> f64
155 where
156 G: NodeIndexable,
157 {
158 distances::euclidean_distance(&positions[graph.to_index(u)], &positions[graph.to_index(v)])
159 .unwrap()
160 }
161
162 #[test]
163 fn test_unreachable_destination_error() {
164 let mut graph: UnGraph<(), ()> = Graph::with_capacity(4, 2);
166
167 let a = graph.add_node(());
168 let b = graph.add_node(());
169
170 let positions = vec![1., 2.];
171 assert_eq!(
172 greedy_routing(&graph, a, b, |u, v| distance1d(&graph, &positions, u, v)),
173 Err(NodeNotReachedError {})
174 )
175 }
176
177 #[test]
178 fn test_greedy_loop_error() {
179 let mut graph: UnGraph<(), ()> = Graph::with_capacity(4, 2);
181
182 let a = graph.add_node(());
183 let b = graph.add_node(());
184 let c = graph.add_node(());
185 let d = graph.add_node(());
186
187 graph.extend_with_edges([(a, b), (b, c), (c, d)]);
188
189 let positions = vec![[0., 0.], [1., 0.], [10., 0.], [4., 0.]];
190 assert_eq!(
191 greedy_routing(&graph, a, d, |u, v| distance2d(&graph, &positions, u, v)),
192 Err(NodeNotReachedError {})
193 )
194 }
195
196 #[test]
197 fn test_correct_greedy_path() {
198 let mut graph: UnGraph<(), ()> = Graph::with_capacity(7, 7);
202
203 let a = graph.add_node(());
204 let b = graph.add_node(());
205 let c = graph.add_node(());
206 let d = graph.add_node(());
207 let e = graph.add_node(());
208 let f = graph.add_node(());
209 let g = graph.add_node(());
210
211 graph.extend_with_edges([(a, b), (b, c), (c, d), (b, e), (e, f), (c, f), (f, g)]);
212
213 let positions = vec![
214 [0., 0.],
215 [1., 0.],
216 [2., 0.],
217 [2.5, 0.],
218 [1., 1.],
219 [2., 1.],
220 [3., 1.],
221 ];
222 let (path, dist) =
223 greedy_routing(&graph, a, d, |u, v| distance2d(&graph, &positions, u, v)).unwrap();
224 assert_eq!(path, vec![a, b, c, d]);
225 assert!((dist - (1. + 1. + 0.5)).abs() < 1e-15);
226
227 let (path, dist) =
228 greedy_routing(&graph, a, g, |u, v| distance2d(&graph, &positions, u, v)).unwrap();
229 assert_eq!(path, vec![a, b, c, f, g]);
230 assert!((dist - (1. + 1. + 1. + 1.)).abs() < 1e-15);
231 }
232
233 #[test]
234 fn test_correct_greedy_success_rate() {
235 let mut graph: UnGraph<(), ()> = Graph::with_capacity(6, 6);
239
240 let b = graph.add_node(());
241 let c = graph.add_node(());
242 let d = graph.add_node(());
243 let e = graph.add_node(());
244 let f = graph.add_node(());
245 let g = graph.add_node(());
246
247 graph.extend_with_edges([(b, c), (c, d), (b, e), (e, f), (c, f), (f, g)]);
248
249 let positions = vec![
250 [1., 0.],
251 [2., 3.],
252 [3., 0.],
253 [1., -1.],
254 [2., -1.],
255 [3., -1.],
256 ];
257 let success_rate =
258 greedy_routing_success_rate(&graph, |u, v| distance2d(&graph, &positions, u, v));
259 assert!((success_rate - 26. / 30.).abs() < 1e-15);
261 }
262}