SimdQuickHeap:
Ragnar {Groot Koerkamp} Link to heading
- Did IMO & ICPC; currently head-of-jury for NWERC.
- Some time at Google.
- Quit and solved all of projecteuler.net (700+) during Covid.
- PhD on high throughput bioinformatics @ ETH Zurich.
- Now postdoc @ KIT Karlsruhe.
- Lots of sequenced DNA that needs processing.
- Many static datasets, e.g. a 3GB human genome.
- Revisiting basic algorithms and optimizing them to the limit.
- Good in theory \(\neq\) fast in practice.
- Last year’s talk on 40x faster binary search: https://curiouscoding.nl/slides/p99
\[ \newcommand{\push}{\mathsf{push}} \newcommand{\pop}{\mathsf{pop}} \]
Motivation: spite Link to heading
- \(O(m \log^{2/3} n)\) shortest path is nice, but how about a faster queue?

Problem Statement: Priority Queues Link to heading
Operations:
- \(\push(x)\): Push the value \(x\) onto the priority queue.
- \(\pop()\): Remove the smallest value from the priority queue.
| |
Binary Heaps: probably worse than you thought Link to heading
Both \(\push\) and \(\pop\):
- \(O(\log_2 n)\) operations, but
- \(O(\log_2 n)\) I/O complexity for \(\pop\)!
- Each \(\pop\) requires a random access to \(O(n)\) memory!
- 80ns cache miss to RAM if we’re unlucky
(todo figure & plot)
Quad/Oct Heap: fewer layers, but still bad Link to heading
(todo figure & plot)
Good \(O(1/B)\) I/O complexity is possible Link to heading
Move a cache line worth of elements at a time into/out of RAM.
- Radix Heap (Johnson 1977)
- Sequence Heap (Sanders 2000)
- QuickHeap (Navarro and Paredes 2010; Navarro et al. 2011)
(todo plot)
The QuickHeap Link to heading
- Use in-place quick select (Hoare 1961) to find the smallest element.
- Store the pivots.
- To \(\push\), bubble down the new element through all pivots
- To \(\pop\), recursively partition the smallest part and return the leftmost element.
(todo fig & plot)
The SimdQuickHeap Link to heading
- Store each partition in its own layer
- use SIMD
_mm256_permutevar8x32_epi32or AVX-612_mm512_maskz_compress_epi64instructions for the partitioning - Use SIMD-based linear-search over pivots to find the layer/partition to append to.
(todo fig & animated demo)
Synthethic benchmarks Link to heading
Graph benchmarks Link to heading
Conclusion Link to heading
With XX input:
- 2x speedup over radix heap
- YY speedup over rust
collections::BinaryHeap - ZZ ns per push/pop operation, down of AA
Not limited by RAM (?)
RAM is slow, caches are fast.
Theoretical big-O complexities are useless here, since caches invalidate the RAM-model assumptions of constant-time access.
P99 CONF Link to heading

Bibliography Link to heading
References Link to heading
Hoare, C. A. R. 1961. “Algorithm 65: Find.” Communications of the Acm 4 (7): 321–22. https://doi.org/10.1145/366622.366644.
Johnson, D. B. 1977. “Efficient Special-Purpose Priority Queues.” In Proceedings of the 15th Annual Allerton Conference on Communications, Control, and Computing, 1–7.
Navarro, Gonzalo, Rodrigo Paredes, Patricio V. Poblete, and Peter Sanders. 2011. “Stronger Quickheaps.” International Journal of Foundations of Computer Science 22 (04): 945–69. https://doi.org/10.1142/s0129054111008507.
Navarro, Gonzalo, and Rodrigo Paredes. 2010. “On Sorting, Heaps, and Minimum Spanning Trees.” Algorithmica 57 (4): 585–620. https://doi.org/10.1007/s00453-010-9400-6.
Sanders, Peter. 2000. “Fast Priority Queues for Cached Memory.” Acm Journal of Experimental Algorithmics 5 (December): 7. https://doi.org/10.1145/351827.384249.