|
morton-arithmetic 0.1.0
Fast Morton (Z-order) codes with O(1) arithmetic
|
Short answer: the individual ideas are not new, but the packaging is useful and, as far as I can tell, not offered as a unit by any popular library. The honest picture, including where the speed advantage does and does not materialise, is below.
| Library | Lang | Encode/decode | Per-axis arithmetic | Z-order range query | Notes |
|---|---|---|---|---|---|
| libmorton | C++ header-only | ✅ (LUT + BMI2 + AVX512) | ❌ | ❌ | The de-facto standard. Fastest encode/decode; nothing else. |
| morton-nd | C++17 header-only | ✅ (constexpr, N-dim, BMI2) | ❌ | ❌ | Elegant arbitrary-dimension encode/decode. No arithmetic. |
| pymorton | Python | ✅ | ❌ (only via decode/encode) | ❌ | Pure Python, slow. |
numpy-based snippets / [morton-py] | Python | ✅ (vectorised magic bits) | ❌ | ❌ | Encode/decode only. |
| this library | C++17 header-only + Python | ✅ (BMI2 + sw fallback) | ✅ inc/dec/add/sub/neighbour | ✅ BIGMIN row-major + Z-order | The combination is the contribution. |
So on encode/decode alone this library has no advantage over libmorton — it is at parity (same PDEP/PEXT instructions), and libmorton additionally has an AVX-512 batch path this library does not. If all you need is encode/decode, use libmorton.
No. Doing integer arithmetic on a single dilated/interleaved coordinate while leaving the others in place is dilated integer arithmetic, known since at least the 1990s:
(code | ~mask) + 1 neighbour trick used here.The legacy prototype in legacy/ already used the carry-propagation idea (on an arbitrary-width bit array). What this library adds over that prototype is making it fast (single-word, BMI2, branchless, O(1) instead of O(width) ripple loops) and general (any Dim, any Bits ≤ 64, both 2D and 3D, software fallback).
A single, modern, header-only, dependency-free C++17 library that combines, with a tested and benchmarked implementation:
plus a vectorised NumPy binding that carries the same arithmetic advantage into Python — where the gap is widest because the Python ecosystem's Morton options are encode/decode-only and often pure-Python.
To my knowledge no widely-used library ships (1)+(2)+(3) together. That is a real, if modest, gap to fill.
From benchmarks/morton_bench (x86-64, BMI2, g++ 14 -O3, 2D 32-bit):
The decisive finding from profiling:
PDEPs pipeline across the superscalar core while the arithmetic walk is a serial dependency chain (each cell depends on the previous one) with a per-cell carry branch. for_each_in_box is therefore offered for convenience and for the Z-order variant, not as the fast path for dense fills.This nuance is the kind of thing that only shows up under measurement, and it shapes the honest pitch: this is a navigation library, not a faster encoder.
The library is worth keeping and polishing as a niche, well-scoped tool for code that traverses Z-ordered data (octrees/quadtrees, stencil solvers on space-filling-curve layouts, spatial indexes). It should not be marketed as a faster encoder — libmorton owns that — but as "libmorton + the arithmetic and range-query operations it deliberately leaves out." See `ROADMAP.md` for the concrete plan.