orx-priority-queue
This crate aims to address the following:
- To provide priority queue traits for two goals:
- to separate simple and decrease key queues, and
- to enable developing functions or algorithms which are generic over the actual queue type.
- To provide d-ary heap implementations, which is generic over
d
:- the implementation makes use of the const-generics which conveniently allows to take advantage of bit operations for the cases where
d
is a power of two, while having a general implementation for others.
- the implementation makes use of the const-generics which conveniently allows to take advantage of bit operations for the cases where
Traits
This crate defines two priority queue traits for (node, key) pairs with the following features:
PriorityQueue<N, K>
: providing basic priority queue functionalities.PriorityQueueDecKey<N, K>
: extends thePriorityQueue<N, K>
by allowing methods to mutate keys of existing items.
The differences can be summarized as follows:
- A decrease key queue is also a simple priority queue; with additonal operations such as
decrease_key
andupdate_key
, etc. - A simple queue has a lower initial memory requirement; while the decrease key queues need an additional internal data structure to keep track of positions.
- On the other hand, a decrease key queue provides a better space complexity than a simple queue in many algorithms.
- For instance, a Dijkstra's shortest path algorithm implementation with a simple queue has a space complexity of O(n^2) due to the fact that every node can enter the node n times, where n is the number of nodes.
- However, the same algorithm using a decrease key queue requires a space complexity of O(n) since each node will enter the queue at most once, and its key will be updated if the same node is observed more than once.
Choice of the Queue
This crate provides three kinds of queue implementations. You may find below their differences and the situations each could be a better fit.
OrxDaryHeap
is a simplePriorityQueue
implemented as a heap.- Benefits from its simplicity.
- Could be considered as the default queue implementation where the memory efficiency is not very critical.
OrxDaryHeapOfIndices
is aPriorityQueueDecKey
which aims to be performant while requiring the items that can enter the queue to implementHasIndex
trait, which simply has the single methodfn index(&self) -> usize
. The implementation is a heap parallel to a mapping of items to positions on the heap.- Particularly useful in performance critical algorithms which additionally requires memory efficiency.
- Requires that the size of the closed set of candidates that can enter the queue is known. This is not a strong limitation in many algorithms. For instance, for most network traversal algorithms, this equals to the number of nodes in the graph.
OrxDaryHeapWithMap
is also aPriorityQueueDecKey
which aims to be flexible requiring the items to implementHash + Eq
. It has a similar implementation with the prior except that it utilizes a map to keep track of item positions on the heap.- This can be considered as the alternative to
OrxDaryHeapOfIndices
in memory critical situations, where it is not possible to satisfy the requirement on knowing the size of the closed set of candidates.
- This can be considered as the alternative to
Note that each of the above kinds is generic over d
, leading to a large number of possible queue choices. The traits come handy here allowing to write algorithms generic over the queue, which then can be benchmarked with different concrete types to find the most performant implementation for the problem. In the next section, we summarize such an experiment.
Experiments on Shortest Path Algorithm
Using the traits, we can write algorithms which are generic over the queues. This allows to conveniently benchmark over the relevant data to find the best fitting queue implementation. You may see such an example exercise in the repository https://github.com/orxfun/orx-bench-shortest-path which allows to compare different shortest path algorithm implementations. From our current experiments using random and real life networks, the following table can be consulted.
Queue Trait | Queue Type | |||
---|---|---|---|---|
Memory Critical? | yes | PriorityQueueDecKey |
||
- Is Graph Sparse? | yes | OrxDaryHeapOfIndices |
||
no | OrxDaryHeapOfIndices |
|||
. | ||||
Memory Critical? | no | PriorityQueue |
||
- Is Graph Sparse? | yes | OrxDaryHeap |
||
no | OrxDaryHeap or std::collections::BinaryHeap |
Example
use *;
// d-ary heap generic over const d
const D: usize = 4;
test_priority_queue;
test_priority_queue;
test_priority_queue;
test_priority_queue_deckey;
test_priority_queue_deckey;
// or type aliases for common heaps to simplify signature
// Binary, Ternary or Quarternary to fix D of Dary
test_priority_queue;
test_priority_queue;
test_priority_queue;
test_priority_queue_deckey;
test_priority_queue_deckey;
test_priority_queue;
test_priority_queue;
test_priority_queue;
test_priority_queue_deckey;
test_priority_queue_deckey;
test_priority_queue;
test_priority_queue;
test_priority_queue;
test_priority_queue_deckey;
test_priority_queue_deckey;
License
This library is licensed under MIT license. See LICENSE for details.