1use std::borrow::Borrow;
4use std::ops::Add;
5
6use num_traits::Zero;
7use rayon::prelude::*;
8
9use h3ron::collections::hashbrown::hash_map::Entry;
10use h3ron::collections::{H3CellMap, H3Treemap, HashMap};
11use h3ron::iter::change_resolution;
12use h3ron::{H3Cell, HasH3Resolution};
13
14use crate::algorithm::dijkstra::edge_dijkstra;
15use crate::algorithm::path::Path;
16use crate::algorithm::NearestGraphNodes;
17use crate::error::Error;
18use crate::graph::{GetCellEdges, GetCellNode};
19
20pub trait ShortestPathOptions {
24 fn max_distance_to_graph(&self) -> u32 {
30 0
31 }
32
33 fn num_destinations_to_reach(&self) -> Option<usize> {
37 None
38 }
39}
40
41#[derive(Default)]
44pub struct DefaultShortestPathOptions {}
45
46impl ShortestPathOptions for DefaultShortestPathOptions {}
47
48impl DefaultShortestPathOptions {
49 pub fn new() -> Self {
50 Default::default()
51 }
52}
53
54pub trait ShortestPath<W> {
61 fn shortest_path<I, OPT: ShortestPathOptions>(
62 &self,
63 origin_cell: H3Cell,
64 destination_cells: I,
65 options: &OPT,
66 ) -> Result<Vec<Path<W>>, Error>
67 where
68 I: IntoIterator,
69 I::Item: Borrow<H3Cell>;
70}
71
72pub trait ShortestPathManyToMany<W>
75where
76 W: Send + Sync + Ord + Copy,
77{
78 #[inline]
82 fn shortest_path_many_to_many<I, OPT>(
83 &self,
84 origin_cells: I,
85 destination_cells: I,
86 options: &OPT,
87 ) -> Result<H3CellMap<Vec<Path<W>>>, Error>
88 where
89 I: IntoIterator,
90 I::Item: Borrow<H3Cell>,
91 OPT: ShortestPathOptions + Send + Sync,
92 {
93 self.shortest_path_many_to_many_map(origin_cells, destination_cells, options, Ok)
94 }
95
96 fn shortest_path_many_to_many_map<I, OPT, PM, O>(
104 &self,
105 origin_cells: I,
106 destination_cells: I,
107 options: &OPT,
108 path_transform_fn: PM,
109 ) -> Result<H3CellMap<Vec<O>>, Error>
110 where
111 I: IntoIterator,
112 I::Item: Borrow<H3Cell>,
113 OPT: ShortestPathOptions + Send + Sync,
114 PM: Fn(Path<W>) -> Result<O, Error> + Send + Sync,
115 O: Send + Ord + Clone;
116}
117
118impl<W, G> ShortestPathManyToMany<W> for G
119where
120 G: GetCellEdges<EdgeWeightType = W> + GetCellNode + HasH3Resolution + NearestGraphNodes + Sync,
121 W: PartialOrd + PartialEq + Add + Copy + Send + Ord + Zero + Sync,
122{
123 fn shortest_path_many_to_many_map<I, OPT, PM, O>(
124 &self,
125 origin_cells: I,
126 destination_cells: I,
127 options: &OPT,
128 path_transform_fn: PM,
129 ) -> Result<H3CellMap<Vec<O>>, Error>
130 where
131 I: IntoIterator,
132 I::Item: Borrow<H3Cell>,
133 OPT: ShortestPathOptions + Send + Sync,
134 PM: Fn(Path<W>) -> Result<O, Error> + Send + Sync,
135 O: Send + Ord + Clone,
136 {
137 let filtered_origin_cells = substitute_origin_cells(
138 self,
139 options.max_distance_to_graph(),
140 origin_cells,
141 true, )?;
143 if filtered_origin_cells.is_empty() {
144 return Ok(Default::default());
145 }
146
147 let destination_substmap = {
148 let origins_treemap: H3Treemap<H3Cell> =
149 filtered_origin_cells.iter().map(|(k, _)| *k).collect();
150
151 substitute_destination_cells(
152 self,
153 options.max_distance_to_graph(),
154 destination_cells,
155 &origins_treemap,
156 )?
157 };
158
159 if destination_substmap.0.is_empty() {
160 return Ok(Default::default());
161 }
162
163 let destination_treemap =
164 H3Treemap::from_iter_with_sort(destination_substmap.0.keys().copied());
165
166 log::debug!(
167 "shortest_path many-to-many: from {} cells to {} cells at resolution {} with max_distance_to_graph = {}",
168 filtered_origin_cells.len(),
169 destination_substmap.0.len(),
170 self.h3_resolution(),
171 options.max_distance_to_graph()
172 );
173
174 let mut cellmap: HashMap<H3Cell, Vec<O>> = Default::default();
175 for par_result in filtered_origin_cells
176 .par_iter()
177 .map(|(graph_connected_origin_cell, output_origin_cells)| {
178 shortest_path_many_worker(
179 self,
180 graph_connected_origin_cell,
181 output_origin_cells.as_slice(),
182 &destination_treemap,
183 &destination_substmap,
184 options,
185 |path| {
186 let origin_cell = path.origin_cell;
187 path_transform_fn(path).map(|transformed| (origin_cell, transformed))
188 },
189 )
190 })
191 .collect::<Result<Vec<_>, _>>()?
192 {
193 for (origin_cell, transformed) in par_result {
194 match cellmap.entry(origin_cell) {
195 Entry::Occupied(mut entry) => entry.get_mut().push(transformed),
196 Entry::Vacant(entry) => {
197 entry.insert(vec![transformed]);
198 }
199 }
200 }
201 }
202 Ok(cellmap)
203 }
204}
205
206impl<W, G> ShortestPath<W> for G
207where
208 G: GetCellEdges<EdgeWeightType = W> + GetCellNode + HasH3Resolution + NearestGraphNodes,
209 W: PartialOrd + PartialEq + Add + Copy + Ord + Zero,
210{
211 fn shortest_path<I, OPT>(
212 &self,
213 origin_cell: H3Cell,
214 destination_cells: I,
215 options: &OPT,
216 ) -> Result<Vec<Path<W>>, Error>
217 where
218 I: IntoIterator,
219 I::Item: Borrow<H3Cell>,
220 OPT: ShortestPathOptions,
221 {
222 let (graph_connected_origin_cell, requested_origin_cells) = {
223 let mut filtered_origin_cells = substitute_origin_cells(
224 self,
225 options.max_distance_to_graph(),
226 std::iter::once(origin_cell),
227 false, )?;
229 if filtered_origin_cells.is_empty() {
230 return Ok(Default::default());
231 } else {
232 filtered_origin_cells.remove(0)
233 }
234 };
235
236 let destination_substmap = {
237 let mut origins_treemap: H3Treemap<H3Cell> = Default::default();
238 origins_treemap.insert(graph_connected_origin_cell);
239 substitute_destination_cells(
240 self,
241 options.max_distance_to_graph(),
242 destination_cells,
243 &origins_treemap,
244 )?
245 };
246
247 if destination_substmap.0.is_empty() {
248 return Ok(Default::default());
249 }
250
251 let destination_treemap =
252 H3Treemap::from_iter_with_sort(destination_substmap.0.keys().copied());
253
254 shortest_path_many_worker(
255 self,
256 &graph_connected_origin_cell,
257 requested_origin_cells.as_slice(),
258 &destination_treemap,
259 &destination_substmap,
260 options,
261 Ok,
262 )
263 }
264}
265
266fn shortest_path_many_worker<G, W, OPT, PM, O>(
267 graph: &G,
268 origin_cell: &H3Cell,
269 requested_origin_cells: &[H3Cell],
270 destination_cells: &H3Treemap<H3Cell>,
271 destination_substmap: &SubstituteMap,
272 options: &OPT,
273 path_transform_fn: PM,
274) -> Result<Vec<O>, Error>
275where
276 G: GetCellEdges<EdgeWeightType = W>,
277 W: Add + Copy + Ord + Zero,
278 PM: Fn(Path<W>) -> Result<O, Error>,
279 O: Clone,
280 OPT: ShortestPathOptions,
281{
282 let found_paths = edge_dijkstra(
283 graph,
284 origin_cell,
285 destination_cells,
286 options.num_destinations_to_reach(),
287 )?;
288
289 let mut transformed_paths = Vec::with_capacity(found_paths.len());
290
291 for path in found_paths.into_iter() {
292 for destination_cell in destination_substmap.cells_substituted_by(&path.destination_cell) {
293 for origin_cell in requested_origin_cells {
294 let mut this_path = path.clone();
295 this_path.origin_cell = *origin_cell;
296 this_path.destination_cell = *destination_cell;
297
298 transformed_paths.push(path_transform_fn(this_path)?);
299 }
300 }
301 }
302 Ok(transformed_paths)
303}
304
305#[derive(Default)]
308struct SubstituteMap(H3CellMap<Vec<H3Cell>>);
309
310impl SubstituteMap {
311 fn cells_substituted_by(&self, cell: &H3Cell) -> &[H3Cell] {
313 self.0
314 .get(cell)
315 .map_or_else(|| &[] as &[H3Cell], |sub| sub.as_slice())
316 }
317
318 fn add_substitute(&mut self, cell: H3Cell, substituted_by: H3Cell) {
320 match self.0.entry(substituted_by) {
321 Entry::Occupied(mut occupied) => occupied.get_mut().push(cell),
322 Entry::Vacant(vacant) => {
323 vacant.insert(vec![cell]);
324 }
325 }
326 }
327
328 fn is_empty(&self) -> bool {
329 self.0.is_empty()
330 }
331}
332
333fn substitute_destination_cells<G, I>(
342 graph: &G,
343 max_distance_to_graph: u32,
344 destination_cells: I,
345 origins_treemap: &H3Treemap<H3Cell>,
346) -> Result<SubstituteMap, Error>
347where
348 G: GetCellNode + NearestGraphNodes + HasH3Resolution,
349 I: IntoIterator,
350 I::Item: Borrow<H3Cell>,
351{
352 let mut destination_substmap = SubstituteMap::default();
355
356 for destination in change_resolution(destination_cells, graph.h3_resolution()) {
357 let destination_cell = destination?;
358 for (graph_cell, node_type, _) in
359 graph.nearest_graph_nodes(&destination_cell, max_distance_to_graph)?
360 {
361 if node_type.is_destination() || origins_treemap.contains(&graph_cell) {
364 destination_substmap.add_substitute(destination_cell, graph_cell);
365 break;
366 }
367 }
368 }
369
370 if destination_substmap.is_empty() {
371 return Err(Error::DestinationsNotInGraph);
372 }
373 Ok(destination_substmap)
374}
375
376fn substitute_origin_cells<G, I>(
385 graph: &G,
386 max_distance_to_graph: u32,
387 origin_cells: I,
388 return_sorted: bool,
389) -> Result<Vec<(H3Cell, Vec<H3Cell>)>, Error>
390where
391 G: GetCellNode + NearestGraphNodes + HasH3Resolution,
392 I: IntoIterator,
393 I::Item: Borrow<H3Cell>,
394{
395 let mut origin_substmap = SubstituteMap::default();
398
399 for cell in change_resolution(origin_cells, graph.h3_resolution()) {
400 let cell = cell?;
401 for (graph_cell, node_type, _) in graph.nearest_graph_nodes(&cell, max_distance_to_graph)? {
402 if node_type.is_origin() {
403 origin_substmap.add_substitute(cell, graph_cell);
404 break;
405 }
406 }
407 }
408
409 let mut out_vec: Vec<_> = origin_substmap.0.drain().collect();
410 if return_sorted {
411 out_vec.sort_unstable_by_key(|v| v.0);
412 }
413 Ok(out_vec)
414}
415
416#[cfg(test)]
417mod tests {
418 use std::convert::TryInto;
419
420 use geo_types::Coord;
421
422 use h3ron::H3Cell;
423
424 use crate::algorithm::shortest_path::{DefaultShortestPathOptions, ShortestPathManyToMany};
425 use crate::graph::{H3EdgeGraph, PreparedH3EdgeGraph};
426
427 #[test]
428 fn test_shortest_path_same_origin_and_destination() {
429 let res = 8;
430 let origin = H3Cell::from_coordinate(Coord::from((23.3, 12.3)), res).unwrap();
431 let edge = origin.directed_edges().unwrap().first().unwrap();
432 let destination = edge.destination_cell().unwrap();
433
434 let prepared_graph: PreparedH3EdgeGraph<_> = {
436 let mut graph = H3EdgeGraph::new(res);
437 graph.add_edge(edge, 5_u32).unwrap();
438 graph.try_into().unwrap()
439 };
440
441 let paths = prepared_graph
442 .shortest_path_many_to_many(
443 &vec![origin],
444 &vec![origin, destination],
446 &DefaultShortestPathOptions::default(),
447 )
448 .unwrap();
449
450 assert_eq!(paths.len(), 1);
451 let path_vec = paths.get(&origin).unwrap();
452 assert_eq!(path_vec.len(), 2);
453 for path in path_vec.iter() {
454 if path.destination_cell == origin {
455 assert!(path.is_empty());
456 assert_eq!(path.cost, 0);
457 } else if path.destination_cell == destination {
458 assert!(!path.is_empty());
459 assert_eq!(path.cost, 5);
460 } else {
461 unreachable!()
462 }
463 }
464 }
465}