From d2c1e6d422bf4dd0707c0a4847c4188d3f4ea273 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sat, 24 Feb 2024 17:11:37 +0100 Subject: [PATCH] Add fibonacci_heap implementation --- examples/priority_queue_test.rs | 40 +++ examples/solve_belt2.rs | 32 -- src/belt_finding/mod.rs | 6 +- src/graph/wheighted_graph/shortest_path.rs | 10 +- src/priority_queue/fibonacci_heap.rs | 394 +++++++++++++-------- src/priority_queue/mod.rs | 8 +- 6 files changed, 303 insertions(+), 187 deletions(-) create mode 100644 examples/priority_queue_test.rs delete mode 100644 examples/solve_belt2.rs diff --git a/examples/priority_queue_test.rs b/examples/priority_queue_test.rs new file mode 100644 index 0000000..a8a739b --- /dev/null +++ b/examples/priority_queue_test.rs @@ -0,0 +1,40 @@ +use factorio_blueprint::priority_queue::{fibonacci_heap::FibonacciHeap, PriorityQueue}; +use std::fmt::Debug; + +fn test_loop

() +where + P: PriorityQueue + Debug, +{ + let mut input = String::new(); + + let mut p = P::new(); + + let mut handles = Vec::new(); + + loop { + input.clear(); + std::io::stdin().read_line(&mut input); + + let (cmd, arg) = input.trim().split_once(' ').unwrap_or((input.trim(), "")); + // dbg!(cmd, arg); + + match cmd { + "i" => handles.push(p.insert(arg.parse::().unwrap())), + "m" => println!("{:?}", p.pop_min()), + "d" => { + let (a, b) = arg.split_once(' ').unwrap(); + let h = &handles[a.parse::().unwrap()]; + let n = b.parse::().unwrap(); + p.decrease_key(h, |f| *f = n); + } + "p" => { + dbg!(&p); + } + _ => println!("Unknown command."), + } + } +} + +fn main() { + test_loop::>() +} diff --git a/examples/solve_belt2.rs b/examples/solve_belt2.rs deleted file mode 100644 index 5b88e0d..0000000 --- a/examples/solve_belt2.rs +++ /dev/null @@ -1,32 +0,0 @@ -use factorio_blueprint::belt_finding::{common::Position, Problem}; - -fn main() { - let mut p = Problem::new(33, 13); - - p.set_blocked_range(1, 3, 2, 5, true); - p.set_blocked_range(1, 7, 2, 9, true); - - p.set_blocked(0, 3, true); - p.set_blocked(0, 8, true); - - p.set_blocked_range(10, 0, 21, 2, true); - p.set_blocked_range(10, 5, 21, 7, true); - p.set_blocked_range(10, 10, 21, 12, true); - - p.set_blocked_range(30, 3, 31, 5, true); - p.set_blocked_range(30, 7, 31, 9, true); - p.set_blocked(32, 3, true); - p.set_blocked(32, 9, true); - - p.add_connection(Position::new(3, 3), Position::new(29, 7)); - p.add_connection(Position::new(3, 4), Position::new(29, 9)); - p.add_connection(Position::new(3, 5), Position::new(29, 8)); - - p.add_connection(Position::new(3, 7), Position::new(29, 3)); - p.add_connection(Position::new(3, 8), Position::new(29, 5)); - p.add_connection(Position::new(3, 9), Position::new(29, 4)); - - println!("{p}"); - p.find_path(); - println!("{p}"); -} diff --git a/src/belt_finding/mod.rs b/src/belt_finding/mod.rs index 666fc8b..feb017f 100644 --- a/src/belt_finding/mod.rs +++ b/src/belt_finding/mod.rs @@ -1,7 +1,9 @@ -use crate::graph::wheighted_graph::shortest_path::dijkstra; use crate::graph::wheighted_graph::WheightedGraph; use crate::misc::Map; use crate::priority_queue::BinaryHeap; +use crate::{ + graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap, +}; use std::ops::Index; use termcolor::{Color, ColorSpec}; @@ -208,7 +210,7 @@ impl Problem { for i in 0..self.start.len() { self.calculate_wheights(i); let m = MapInternal { map: &self.map }; - let p = dijkstra::>(&m, self.start[i], self.end[i]); + let p = dijkstra::>(&m, self.start[i], self.end[i]); if let Some(p) = p { self.path[i] = p; diff --git a/src/graph/wheighted_graph/shortest_path.rs b/src/graph/wheighted_graph/shortest_path.rs index a6142ce..27887f1 100644 --- a/src/graph/wheighted_graph/shortest_path.rs +++ b/src/graph/wheighted_graph/shortest_path.rs @@ -119,7 +119,7 @@ mod test { graph::wheighted_graph::{ adjacency_list::WheightedAdjacencyList, shortest_path::dijkstra, WheightedGraph, }, - priority_queue::BinaryHeap, + priority_queue::{fibonacci_heap::FibonacciHeap, BinaryHeap}, }; #[test] @@ -162,6 +162,14 @@ mod test { 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 { diff --git a/src/priority_queue/fibonacci_heap.rs b/src/priority_queue/fibonacci_heap.rs index dca5da5..a181df0 100644 --- a/src/priority_queue/fibonacci_heap.rs +++ b/src/priority_queue/fibonacci_heap.rs @@ -1,186 +1,280 @@ +use std::fmt::Debug; + use crate::misc::{Arena, ArenaKey}; use super::PriorityQueue; -#[derive(Debug)] -struct FibonacciHeapObject { - left: ArenaKey, - right: ArenaKey, - parent: Option, - child: Option, - rank: usize, - marked: bool, - data: T, +type Index = u32; + +pub struct FibonacciHeap { + min: Option, + data: Vec>>, + free: Vec, + temp: [Option; 64], +} + +impl std::fmt::Debug for FibonacciHeap { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + struct PrintData<'a, I>(&'a Vec>>); + impl<'a, I: Debug> Debug for PrintData<'a, I> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_map() + .entries(self.0.iter().enumerate().filter_map(|d| { + if let (i, Some(c)) = d { + Some((i, c)) + } else { + None + } + })) + .finish() + } + } + f.debug_struct("FibonacciHeap") + .field("min", &self.min) + .field("data", &PrintData(&self.data)) + .field("free", &self.free) + .finish() + } } #[derive(Debug)] -pub struct FibonacciHeap { - arena: Arena>, - min: Option, - update_rank: Vec>, +pub struct FibonacciHeapHandle(Index); + +#[derive(Debug)] +struct Node { + item: I, + parent: Index, + left: Index, + right: Index, + child: Index, + mark: bool, + rank: u16, } -pub struct FibonacciHeapHandle(ArenaKey); +impl Node { + fn new(item: I) -> Self { + Self { + item, + parent: 0, + left: 0, + right: 0, + child: 0, + mark: false, + rank: 0, + } + } +} -impl PriorityQueue for FibonacciHeap +impl FibonacciHeap where - T: std::cmp::Ord, + I: PartialOrd, +{ + fn add_to_list(&mut self, list: Index, i: Index) { + let right = self.get(list).right; + let n = self.get_mut(i); + n.right = right; + n.left = list; + self.get_mut(right).left = i; + self.get_mut(list).right = i; + } + + fn remove_from_list(&mut self, i: Index) -> Option { + let left = self.get(i).left; + if left == i { + return None; + } + + let right = self.get(i).right; + + self.get_mut(left).right = right; + self.get_mut(right).left = left; + + Some(right) + } + + fn insert_tree(&mut self, i: Index) { + if let Some(min) = self.min { + self.add_to_list(min, i); + + self.get_mut(i).parent = i; + + if self.get(i).item < self.get(min).item { + self.min = Some(i); + } + } else { + let m = self.get_mut(i); + m.parent = i; + m.left = i; + m.right = i; + self.min = Some(i); + } + } + + fn union(&mut self, a: Index, b: Index) -> Index { + let min; + let max; + + if self.get(a).item < self.get(b).item { + min = a; + max = b; + } else { + min = b; + max = a; + } + + if self.get(min).rank == 0 { + self.get_mut(min).child = max; + self.get_mut(min).rank = 1; + let m = self.get_mut(max); + m.parent = min; + m.left = max; + m.right = max; + } else { + self.get_mut(max).parent = min; + self.add_to_list(self.get(min).child, max); + self.get_mut(min).rank += 1; + } + + min + } + fn insert_temp(&mut self, i: Index) { + let rank = self.get(i).rank; + if let Some(t) = self.temp[rank as usize].take() { + let m = self.union(t, i); + + self.insert_temp(m); + } else { + self.temp[rank as usize] = Some(i); + } + } + + fn insert_data(&mut self, data: I) -> Index { + if let Some(i) = self.free.pop() { + self.data[i as usize] = Some(Node::new(data)); + i + } else { + let i = self.data.len() as Index; + self.data.push(Some(Node::new(data))); + i + } + } + + fn get(&self, i: Index) -> &Node { + self.data.get(i as usize).unwrap().as_ref().unwrap() + } + + fn get_mut(&mut self, i: Index) -> &mut Node { + self.data.get_mut(i as usize).unwrap().as_mut().unwrap() + } + + fn remove_data(&mut self, i: Index) -> I { + let n = self.data[i as usize].take().unwrap(); + + self.free.push(i); + + n.item + } + + fn cut(&mut self, i: Index) { + if self.get(i).item < self.get(self.min.unwrap()).item { + self.min = Some(i); + } + let parent = self.get(i).parent; + if parent == i { + return; + } + let c = self.remove_from_list(i); + if self.get(parent).rank > 1 { + self.get_mut(parent).child = c.unwrap(); + } + self.get_mut(parent).rank -= 1; + + self.add_to_list(self.min.unwrap(), i); + self.get_mut(i).mark = false; + self.get_mut(i).parent = i; + + if self.get(parent).mark { + self.cut(parent); + } else { + self.get_mut(parent).mark = true; + } + } +} + +impl PriorityQueue for FibonacciHeap +where + I: PartialOrd, { type Handle = FibonacciHeapHandle; fn new() -> Self { - todo!() + FibonacciHeap { + min: None, + data: Vec::new(), + free: Vec::new(), + temp: [None; 64], + } } - fn insert(&mut self, item: T) -> Self::Handle { - let h = self.arena.insert(FibonacciHeapObject { - left: ArenaKey::default(), - right: ArenaKey::default(), - parent: None, - child: None, - rank: 0, - marked: false, - data: item, - }); + fn insert(&mut self, item: I) -> Self::Handle { + let i = self.insert_data(item); - self.insert_tree(h); + self.insert_tree(i); - FibonacciHeapHandle(h) + FibonacciHeapHandle(i) } - fn pop_min(&mut self) -> Option { - if let Some(k) = self.min.take() { - let o = self.arena.remove(k); - - if let Some(child) = o.child { - let mut p = child; + fn pop_min(&mut self) -> Option { + if let Some(min) = self.min.take() { + if self.get(min).rank != 0 { + let mut c = self.get(min).child; loop { - self.arena.get_mut(&p).parent = None; - self.arena.get_mut(&p).marked = false; - let t = self.arena.get(&p).right; - - self.insert_tree(p); - - p = t; - - if p == child { + let t = c; + c = self.get(c).right; + self.add_to_list(min, t); + self.get_mut(t).parent = t; + self.get_mut(t).mark = false; + if c == self.get(min).child { break; } } } + if let Some(m) = self.remove_from_list(min) { + let mut c = m; + loop { + let t = c; + c = self.get(c).right; + self.insert_temp(t); + if c == m { + break; + } + } - if o.left != o.right { - self.arena.get_mut(&o.left).right = o.right; - self.arena.get_mut(&o.right).left = o.left; - self.update_min(o.left); + for i in 0..self.temp.len() { + if let Some(i) = self.temp[i].take() { + if let Some(min) = self.min { + self.add_to_list(min, i); + if self.get(i).item < self.get(min).item { + self.min = Some(i); + } + } else { + self.get_mut(i).left = i; + self.get_mut(i).right = i; + self.min = Some(i); + } + } + } } - Some(o.data) + Some(self.remove_data(min)) } else { None } } - fn decrease_key(&mut self, _handle: &Self::Handle, _f: impl Fn(&mut T)) { - todo!() - } -} - -impl FibonacciHeap -where - T: std::cmp::Ord, -{ - fn insert_tree(&mut self, h: ArenaKey) { - if let Some(h_min) = self.min { - let h_last = self.arena.get(&h_min).left; - - self.arena.get_mut(&h_min).left = h; - - self.arena.get_mut(&h).left = h_last; - self.arena.get_mut(&h).right = h_min; - - self.arena.get_mut(&h_last).right = h; - - if self.arena.get(&h).data < self.arena.get(&h_min).data { - self.min = Some(h) - } - } else { - self.arena.get_mut(&h).left = h; - self.arena.get_mut(&h).right = h; - - self.min = Some(h); - } - } - - fn update_min(&mut self, mut h: ArenaKey) { - let h_start = h; - - loop { - let next_h = self.arena.get(&h).right; - - self.add_to_update_rank(h); - - h = next_h; - if h == h_start { - break; - } - } - - let mut prev = None; - // let mut start = None; - - for h in &mut self.update_rank { - if let Some(h) = h.take() { - if let Some(p) = prev { - self.arena.get_mut(&h).left = p; - self.arena.get_mut(&p).right = h; - } else { - prev = Some(h); - // start = Some(h); - } - if let Some(m) = self.min { - if self.arena.get(&h).data < self.arena.get(&m).data { - self.min = Some(h); - } - } else { - self.min = Some(h); - } - } - } - } - - fn add_to_update_rank(&mut self, h: ArenaKey) { - let rank = self.arena.get(&h).rank; - - while self.update_rank.len() + 1 < rank { - self.update_rank.push(None) - } - - if let Some(o) = self.update_rank.get_mut(rank).unwrap().take() { - if let Some(child) = self.arena.get(&h).child { - let last = self.arena.get(&child).left; - - self.arena.get_mut(&child).left = h; - self.arena.get_mut(&last).right = h; - - self.arena.get_mut(&o).parent = Some(h); - self.arena.get_mut(&o).marked = false; - self.arena.get_mut(&o).left = last; - self.arena.get_mut(&o).right = child; - } else { - self.arena.get_mut(&h).child = Some(o); - - self.arena.get_mut(&o).parent = Some(h); - self.arena.get_mut(&o).marked = false; - self.arena.get_mut(&o).left = o; - self.arena.get_mut(&o).right = o; - } - - self.arena.get_mut(&h).rank += 1; - - self.add_to_update_rank(h); - } else { - *self.update_rank.get_mut(rank).unwrap() = Some(h); - } + fn decrease_key(&mut self, handle: &Self::Handle, f: impl Fn(&mut I)) { + let h = self.get_mut(handle.0); + f(&mut h.item); + self.cut(handle.0); } } diff --git a/src/priority_queue/mod.rs b/src/priority_queue/mod.rs index 7a960a7..b622c6b 100644 --- a/src/priority_queue/mod.rs +++ b/src/priority_queue/mod.rs @@ -100,6 +100,8 @@ where #[cfg(test)] mod tests { + use super::fibonacci_heap::FibonacciHeap; + use super::BinaryHeap; use super::PriorityQueue; macro_rules! test_generics { @@ -124,12 +126,14 @@ mod tests { #[test] fn $fun() { - super::$fun::>(); + super::super::$fun::>(); } } } - test_generics!(basic_generic decrease_key_generic; BinaryHeap); + mod test_macro { + test_generics!(basic_generic decrease_key_generic; BinaryHeap FibonacciHeap); + } fn basic_generic>() { let mut q = T::new();