use std::{collections::HashMap, fmt::Debug, hash::Hash, hash::Hasher}; use crate::priority_queue::PriorityQueue; use super::WheightedGraph; #[derive(Debug, Clone, Copy)] pub struct QueueObject { node: N, score: f64, } impl QueueObject { fn new(node: N, score: f64) -> Self { Self { node, score } } } impl PartialOrd for QueueObject { fn partial_cmp(&self, other: &Self) -> Option { self.score.partial_cmp(&other.score) } } impl PartialEq for QueueObject { fn eq(&self, other: &Self) -> bool { self.score == other.score } } impl Hash for QueueObject where N: Hash, { fn hash(&self, state: &mut H) { self.node.hash(state); } } #[derive(Debug)] struct MapObject { parent: N, score: f64, key: Option, } impl MapObject { fn new(parent: N, score: f64, key: H) -> Self { Self { parent, score, key: Some(key), } } } pub fn dijkstra(graph: &G, start: G::Node, end: G::Node) -> Option> where P: PriorityQueue> + Debug, P::Handle: Debug, G::Node: Eq + Hash + Clone + Debug, G: WheightedGraph, { if start == end { return Some(vec![start]); } let mut map: HashMap> = HashMap::new(); let mut q = P::new(); q.insert(QueueObject::new(start.clone(), 0.0)); while let Some(o) = q.pop_min() { if let Some(m) = map.get_mut(&o.node) { m.key = None; } if o.node == end { break; } for (node, wheight) in graph.edge_iter(&o.node) { let score = o.score + wheight; if let Some(n) = map.get_mut(&node) { if let Some(h) = &n.key { if score < n.score { n.parent = o.node.clone(); n.score = score; q.decrease_key(h, |i| i.score = score); } } } else { let h = q.insert(QueueObject::new(node.clone(), o.score + wheight)); map.insert(node, MapObject::new(o.node.clone(), o.score + wheight, h)); } } // dbg!(&q); } map.get(&end)?; let mut result = vec![end]; // dbg!(&map); loop { let parent = map.get(result.last().expect("last")).expect("get"); result.push(parent.parent.clone()); if parent.parent == start { break; } } result.reverse(); Some(result) } #[cfg(test)] mod test { use crate::{ graph::wheighted_graph::{ adjacency_list::WheightedAdjacencyList, shortest_path::dijkstra, WheightedGraph, }, priority_queue::{fibonacci_heap::FibonacciHeap, BinaryHeap}, }; #[test] fn trivial() { let a = WheightedAdjacencyList { nodes: vec![0, 1], edges: vec![(1, 1.0)], }; assert_eq!( dijkstra::>(&a, 0, 1), Some(vec![0, 1]) ); } #[test] fn simple() { let a = WheightedAdjacencyList { nodes: vec![0, 2, 3, 5, 5, 7, 10], edges: vec![ (1, 2.0), (4, 10.0), (2, 3.0), (3, 2.0), (5, 1.0), (0, 4.0), (2, 5.0), (2, 9.0), (3, 8.0), (4, 0.0), (5, 7.0), ], }; assert_eq!( dijkstra::>(&a, 0, 4), Some(vec![0, 1, 2, 5, 4]) ); assert_eq!( dijkstra::>(&a, 0, 6), None ); assert_eq!( dijkstra::>(&a, 0, 4), Some(vec![0, 1, 2, 5, 4]) ); assert_eq!( dijkstra::>(&a, 0, 6), None ); } struct Grid { width: usize, height: usize, } impl WheightedGraph for Grid { type Node = (usize, usize); fn num_edges(&self, node: &Self::Node) -> usize { let mut c = 0; if node.0 > 0 { c += 1 } if node.0 < self.width - 1 { c += 1 } if node.1 > 0 { c += 1 } if node.1 < self.height - 1 { c += 1 } c } fn edge(&self, node: &Self::Node, num: usize) -> Option<(Self::Node, f64)> { dbg!(&node); let edges = [ (node.0 > 0).then_some((node.0.saturating_sub(1), node.1)), (node.0 < self.width - 1).then_some((node.0 + 1, node.1)), (node.1 > 0).then_some((node.0, node.1.saturating_sub(1))), (node.1 < self.height - 1).then_some((node.0, node.1 + 1)), ]; edges.iter().flatten().nth(num).map(|&p| (p, 1.0)) } } #[test] fn grid() { let g = Grid { width: 600, height: 600, }; dbg!(dijkstra::>( &g, (0, 0), (g.width - 1, g.height - 1) )); } }