Add fibonacci_heap implementation

This commit is contained in:
hal8174 2024-02-24 17:11:37 +01:00
parent 6cbb389ee7
commit d2c1e6d422
6 changed files with 303 additions and 187 deletions

View file

@ -0,0 +1,40 @@
use factorio_blueprint::priority_queue::{fibonacci_heap::FibonacciHeap, PriorityQueue};
use std::fmt::Debug;
fn test_loop<P>()
where
P: PriorityQueue<u16> + 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::<u16>().unwrap())),
"m" => println!("{:?}", p.pop_min()),
"d" => {
let (a, b) = arg.split_once(' ').unwrap();
let h = &handles[a.parse::<usize>().unwrap()];
let n = b.parse::<u16>().unwrap();
p.decrease_key(h, |f| *f = n);
}
"p" => {
dbg!(&p);
}
_ => println!("Unknown command."),
}
}
}
fn main() {
test_loop::<FibonacciHeap<u16>>()
}

View file

@ -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}");
}

View file

@ -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::<MapInternal, BinaryHeap<_>>(&m, self.start[i], self.end[i]);
let p = dijkstra::<MapInternal, FibonacciHeap<_>>(&m, self.start[i], self.end[i]);
if let Some(p) = p {
self.path[i] = p;

View file

@ -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::<WheightedAdjacencyList, BinaryHeap<_>>(&a, 0, 6),
None
);
assert_eq!(
dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>>(&a, 0, 4),
Some(vec![0, 1, 2, 5, 4])
);
assert_eq!(
dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>>(&a, 0, 6),
None
);
}
struct Grid {

View file

@ -1,186 +1,280 @@
use std::fmt::Debug;
use crate::misc::{Arena, ArenaKey};
use super::PriorityQueue;
#[derive(Debug)]
struct FibonacciHeapObject<T> {
left: ArenaKey,
right: ArenaKey,
parent: Option<ArenaKey>,
child: Option<ArenaKey>,
rank: usize,
marked: bool,
data: T,
type Index = u32;
pub struct FibonacciHeap<I> {
min: Option<Index>,
data: Vec<Option<Node<I>>>,
free: Vec<Index>,
temp: [Option<Index>; 64],
}
impl<I: std::fmt::Debug> std::fmt::Debug for FibonacciHeap<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
struct PrintData<'a, I>(&'a Vec<Option<Node<I>>>);
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<T> {
arena: Arena<FibonacciHeapObject<T>>,
min: Option<ArenaKey>,
update_rank: Vec<Option<ArenaKey>>,
pub struct FibonacciHeapHandle(Index);
#[derive(Debug)]
struct Node<I> {
item: I,
parent: Index,
left: Index,
right: Index,
child: Index,
mark: bool,
rank: u16,
}
pub struct FibonacciHeapHandle(ArenaKey);
impl<I> Node<I> {
fn new(item: I) -> Self {
Self {
item,
parent: 0,
left: 0,
right: 0,
child: 0,
mark: false,
rank: 0,
}
}
}
impl<T> PriorityQueue<T> for FibonacciHeap<T>
impl<I> FibonacciHeap<I>
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<Index> {
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<I> {
self.data.get(i as usize).unwrap().as_ref().unwrap()
}
fn get_mut(&mut self, i: Index) -> &mut Node<I> {
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<I> PriorityQueue<I> for FibonacciHeap<I>
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<T> {
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<I> {
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 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);
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;
}
}
Some(o.data)
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(self.remove_data(min))
} else {
None
}
}
fn decrease_key(&mut self, _handle: &Self::Handle, _f: impl Fn(&mut T)) {
todo!()
}
}
impl<T> FibonacciHeap<T>
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);
}
}

View file

@ -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::$gen<usize>>();
super::super::$fun::<super::super::$gen<usize>>();
}
}
}
test_generics!(basic_generic decrease_key_generic; BinaryHeap);
mod test_macro {
test_generics!(basic_generic decrease_key_generic; BinaryHeap FibonacciHeap);
}
fn basic_generic<T: PriorityQueue<usize>>() {
let mut q = T::new();