blob: 118352e885b836f148b34072b31ef57fc3d8ddb0 [file] [log] [blame]
use alloc::collections::BinaryHeap;
use core::cmp::Ordering;
use petgraph_core::{
node::NodeId,
storage::{
auxiliary::{BooleanGraphStorage, FrequencyHint, Hints, OccupancyHint, PerformanceHint},
AuxiliaryGraphStorage,
},
};
pub(in crate::shortest_paths) struct PriorityQueueItem<T> {
pub(in crate::shortest_paths) node: NodeId,
pub(in crate::shortest_paths) priority: T,
}
impl<T> PartialEq for PriorityQueueItem<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
other.priority.eq(&self.priority)
}
}
impl<T> Eq for PriorityQueueItem<T> where T: Eq {}
impl<T> PartialOrd for PriorityQueueItem<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
other.priority.partial_cmp(&self.priority)
}
}
impl<T> Ord for PriorityQueueItem<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
other.priority.cmp(&self.priority)
}
}
pub(in crate::shortest_paths) struct PriorityQueue<'graph, S, T>
where
S: AuxiliaryGraphStorage + 'graph,
T: Ord,
{
heap: BinaryHeap<PriorityQueueItem<T>>,
pub(crate) check_admissibility: bool,
flags: S::BooleanNodeStorage<'graph>,
}
impl<'graph, S, T> PriorityQueue<'graph, S, T>
where
S: AuxiliaryGraphStorage + 'graph,
T: Ord,
{
#[inline]
pub(in crate::shortest_paths) fn new(storage: &'graph S) -> Self {
Self {
heap: BinaryHeap::new(),
check_admissibility: true,
flags: storage.boolean_node_storage(Hints {
performance: PerformanceHint {
read: FrequencyHint::Frequent,
write: FrequencyHint::Infrequent,
},
occupancy: OccupancyHint::Dense,
}),
}
}
pub(in crate::shortest_paths) fn push(&mut self, node: NodeId, priority: T) {
self.heap.push(PriorityQueueItem { node, priority });
}
pub(in crate::shortest_paths) fn visit(&mut self, id: NodeId) {
self.flags.set(id, true);
}
#[inline]
pub(in crate::shortest_paths) fn has_been_visited(&self, id: NodeId) -> bool {
self.flags.get(id).unwrap_or(false)
}
#[inline]
pub(in crate::shortest_paths) fn decrease_priority(&mut self, node: NodeId, priority: T) {
if self.check_admissibility && self.has_been_visited(node) {
return;
}
self.heap.push(PriorityQueueItem { node, priority });
}
#[inline]
pub(in crate::shortest_paths) fn pop_min(&mut self) -> Option<PriorityQueueItem<T>> {
loop {
let item = self.heap.pop()?;
if self.check_admissibility && self.has_been_visited(item.node) {
continue;
}
self.visit(item.node);
return Some(item);
}
}
}