Skip to main content

Fast single-source shortest paths with a Rust core (PyO3 + maturin): production Dijkstra plus a faithful, benchmarked implementation of the Duan-Mao-Mao-Shu-Yin sorting-barrier BMSSP algorithm

Project description

logtwothirds

DOI

A verified, honestly benchmarked Rust implementation of the 2025 algorithm that broke the sorting barrier for shortest paths — packaged as a small Python library (Rust core via PyO3 + maturin), and measured against plain Dijkstra to answer the question the theory leaves open: is it actually faster?

New to shortest paths? There's a guided tour that assumes nothing and ends at this repository's verdict: start at docs/00-why-shortest-paths.md.

The sorting barrier, and the algorithm that broke it

Dijkstra's algorithm settles vertices in order of increasing distance from the source. That ordering is the whole trick — and also a tax. Producing n numbers in sorted order costs Ω(n log n) comparisons, so any shortest-path algorithm that hands you vertices in distance order inherits that log n factor. On a sparse graph — m edges with m close to n — that sorting term is what dominates the clock. For sixty years this looked fundamental: to find shortest paths you seemed to have to sort, and sorting has a floor. Call it the sorting barrier.

In 2025, Duan, Mao, Mao, Shu, and Yin broke it. Their algorithm — Breaking the Sorting Barrier for Directed Single-Source Shortest Paths (arXiv:2504.17033) — finds the same shortest paths in O(m log^(2/3) n) time, strictly below Dijkstra's O(m + n log n) on sparse graphs. The idea is to stop fully sorting. Rather than pulling vertices one at a time in distance order, it recursively shrinks the frontier: a FindPivots step picks a small set of vertices whose settlement unlocks everything behind them, and a divide-and-conquer recursion (BMSSP) settles whole blocks of vertices without ever materializing the complete sorted sequence. The log^(2/3) is what the bookkeeping costs once you no longer pay for the sort. The "two-thirds" in the exponent is where this project's name comes from. (The result keeps moving: in February 2026 four of the five authors sharpened the bound again, to O(m √(log n · log log n)) on sparse graphs — arXiv:2602.07868. This repository studies the original algorithm; the practical question below applies to any successor.)

This repository implements that algorithm, checks it against the paper line by line, and then asks the question the asymptotics don't: does breaking the barrier make anything run faster? The honest answer — measured, not asserted — is no, not at any size you can actually run. The faithful implementation is 26–128× slower than a good Dijkstra; the most aggressively engineered variant closes that to ~1.1–2×, but never crosses over. The asymptotic advantage is real and it does narrow with n roughly as log^(2/3) n vs log n predicts — it just doesn't pay off until somewhere around n ≈ 2^400000, a graph too large to store even at one vertex per atom of the observable universe (roughly 2^266 of them). That gap between what the theory promises and what the hardware delivers is the actual subject of this repo, documented honestly below and in BENCHMARKS.md.

So the library ships Dijkstra as the thing you should use, and keeps the BMSSP engines as instrumented, verified research objects — the sharpest way to state precisely where the algorithm's constant factor lives.

Install (from source)

python -m venv .venv
. .venv/Scripts/activate          # Windows; use bin/activate on POSIX
pip install maturin numpy scipy pytest
maturin develop --release

API

from logtwothirds import shortest_paths, shortest_paths_multi

dist, pred = shortest_paths(graph, source)                     # method="auto"
dist, pred = shortest_paths(graph, source, method="bmssp")     # research
dists, preds = shortest_paths_multi(graph, [s0, s1, s2])       # parallel (rayon)
  • graph: a scipy.sparse matrix (any format) or a CSR triple (indptr: int64, indices: int32, weights: float64). The CSR arrays are borrowed into Rust zero-copy via rust-numpy.
  • source: source vertex index. Out of range raises IndexError.
  • Returns (distances: float64[n], predecessors: int32[n]) — for shortest_paths_multi, shape (k, n), row i bit-identical to the single-source call for sources[i]. Unreachable vertices have inf distance; the source and unreachable vertices have predecessor -1. A negative edge weight raises ValueError.

Methods

method what it is when to use it
"auto" (default) selects "dijkstra", always always
"dijkstra" 4-ary SoA heap Dijkstra the fastest method at every measured size
"bmssp" BMSSP, faithful to the paper studying the algorithm (settlement logs, counters, differential-tested vs the Python reference)
"bmssp-fast" the fastest BMSSP instantiation found (VARIANTS.md) research: the sharpest statement of the BMSSP-vs-Dijkstra verdict
"bmssp-<name>" single-delta research variants (tuned, hybrid, simpleq, lazypiv, notransform) research: isolating where BMSSP's constant factor lives

"auto" selecting Dijkstra unconditionally is a measured verdict, not a stub. Median-of-5 benchmarks (BENCHMARKS.md, fixed seeds, distances cross-checked across five implementations):

graph lt-dijkstra bmssp (faithful) bmssp-fast¹ scipy rustworkx
random m=4n, n=10⁶ 854 ms 24.6 s (29×) 0.95 s (~1.24×) 806 ms 1.59 s
random m=4n, n=10⁷ 13.3 s 345 s (26×) 14.9 s (1.12×) 10.7 s
Barabási–Albert, n=10⁶ 1.28 s 43.9 s (34×) 1.79 s (1.4×)² 1.06 s 1.86 s
USA-road-d.NY 25.9 ms 1.65 s (64×) 57 ms (~2.0×) 40.7 ms 126 ms

¹ Re-measured after the second engineering pass (OPTIMIZATION.md, "Second pass") with examples/bench_fast.rs: same-process medians of 5, distances cross-checked in-binary; the ratio is against the Dijkstra run in the same process. Other columns are the BENCHMARKS.md matrix. ² Predates the second pass (not yet re-measured on Barabási–Albert).

The faithful gap narrows with n roughly as O(m log^(2/3) n) vs O(m log n) predicts, but extrapolates to a crossover near n ≈ 2^400000; the maximally-engineered bmssp-fast is structurally a Dijkstra run carrying BMSSP's heavier labels, so its remaining ~1.1–2× gap is a constant factor, not a vanishing one. There is no practical size at which any BMSSP engine wins — bmssp and bmssp-fast are provided for research and verification. Full story, methodology, and the variant ladder: BENCHMARKS.md (final matrix and verdict), VARIANTS.md (the algorithm-level variant study), and OPTIMIZATION.md (the low-level pass that produced the shipping bmssp-fast).

Implementation

src/dijkstra.rs implements Dijkstra with an implicit 4-ary min-heap using lazy deletion (stale entries are skipped on pop). The heap is structure-of-arrays (keys / vertex-ids in parallel arrays) and pre-reserved, so the relaxation loop performs no allocations. Neighbor dist[v] slots are software-prefetched to overlap the random-access cache misses that dominate the runtime.

src/bmssp.rs + src/block_queue.rs implement BMSSP as a semantically 1:1 port of the pure-Python reference python/logtwothirds/_reference.py (see ALGORITHM.md / SPEC.md): the constant-degree transform, the path-key total order, FindPivots / BaseCase / BMSSP, and the block data structure D, reproducing the reference's observable orders exactly (Python-dict insertion order in D's blocks, insertion-ordered result sets, an explicit SplitMix64 for the quickselect pivots). The differential test tests/differential.rs checks distances and settlement order bit-for-bit against the reference on 200 random graphs via tests/diff_driver.py; tests/property_vs_dijkstra.rs checks distances against Rust Dijkstra up to 10^6 edges; tests/not_dijkstra.rs ports the suite's non-sorted-settlement acceptance check. This mainline is frozen as the reference engine.

src/variants/ holds the research variants behind method="bmssp-<name>": a shared engine (engine.rs) that keeps the paper's correctness contracts (label total order, <= relaxation, the Lemma 3.1 oracle contract) while making the transform, queue, base-case oracle, and (k, t) configurable. Every variant is gated on tests/variants_correctness.rs: ≥520 property graphs (zero weights, ties, integer weights, self-loops, parallel edges) plus a 10⁶-edge stress graph, bit-exact distances vs Dijkstra plus predecessor consistency. Engine instrumentation is compiled out unless built with --features phase-timer; invariant checks upgrade from debug_assert! to hard asserts with --features verify.

Tests & benchmark

pytest -q                         # Python API tests (vs scipy + edge cases)
cargo test                        # Rust unit + differential + property tests
cargo test --release --test variants_correctness   # variant distance gate
cargo clippy --all-targets -- -D warnings
cargo clippy --all-targets --features python -- -D warnings
python benchmarks/run.py          # full benchmark matrix (~1.5 h)

The differential test needs a Python interpreter to run the reference; it uses .venv next to Cargo.toml (or LOGTWOTHIRDS_PYTHON) and skips with a notice if neither exists.

Documents

The research record, in reading order:

file what it is
ALGORITHM.md self-contained distillation of the Duan–Mao–Mao–Shu–Yin paper (the source of truth all lemma references point into)
SPEC.md engineering spec for the pure-Python reference (python/logtwothirds/_reference.py); defers to ALGORITHM.md on any conflict
AUDIT.md line-by-line audit of the Python reference against the paper (zero blockers; findings F1–F14)
QUESTIONS.md / FAILCASE.md the four resolved paper-interpretation questions, and the worked failure case that motivated the settled-vertex filter
VARIANTS.md algorithm-level variant study (src/variants/) that produced bmssp-fast; ranks the variants and proves each delta correctness-preserving
OPTIMIZATION.md two low-level engineering passes that tightened bmssp-fast (2.13 s → 1.21 s at n=10⁶, then ~1.49× → ~1.24× of Dijkstra by same-process ratio, ~1.12× at 10⁷); distinct from the mainline pass in BENCHMARKS.md
BENCHMARKS.md final cross-implementation matrix and the honest verdict (Dijkstra wins everywhere; no crossover) — the authoritative wall-clock numbers

Numbers across these are consistent as of 2026-07-02; where a research-phase table (VARIANTS.md) and the final matrix (BENCHMARKS.md) differ for bmssp-fast, BENCHMARKS.md is authoritative and the older table is marked as superseded in place, with the second-pass ratios recorded in OPTIMIZATION.md.

Author & citing

Written by Nikolai Khobotov (github.com/primaryaesthetics). If you use the library or its benchmark results, cite it via the repository's CITATION.cff (GitHub renders a "Cite this repository" button from it). The algorithm itself is due to Duan, Mao, Mao, Shu and Yin (arXiv:2504.17033); this project is an independent implementation and experimental study.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

logtwothirds-0.1.0.tar.gz (655.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

logtwothirds-0.1.0-cp39-abi3-win_amd64.whl (316.8 kB view details)

Uploaded CPython 3.9+Windows x86-64

logtwothirds-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl (430.9 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

logtwothirds-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446.1 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

logtwothirds-0.1.0-cp39-abi3-macosx_11_0_arm64.whl (397.1 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

logtwothirds-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl (414.8 kB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file logtwothirds-0.1.0.tar.gz.

File metadata

  • Download URL: logtwothirds-0.1.0.tar.gz
  • Upload date:
  • Size: 655.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for logtwothirds-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a9a90b1920257d81f4e96d25b35f4c77600f2ba401d2e324a2e6dff0a0960bcc
MD5 aff192d240b9f42fd6c6ff1d48a42eb2
BLAKE2b-256 53c19e5276f9cf4dbc86ca456f55b86842dedda6b6574b6e7ec78012d14cb5f7

See more details on using hashes here.

File details

Details for the file logtwothirds-0.1.0-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for logtwothirds-0.1.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 64ee9c22b88194141e57e864592e779050a0bc55951159fd9eaad0204a064f1e
MD5 555bb3cf3101b0917942b5e94de7d403
BLAKE2b-256 3a26ad8518641139a5535f9478cafc3e3ebe23680294eca16b707823a06cc3e2

See more details on using hashes here.

File details

Details for the file logtwothirds-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for logtwothirds-0.1.0-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 a4069d031e59057fb2b3d401980530b3ef627ecec36d2db2ee1f8011bfea1b70
MD5 c070fb08f48a888ef7840d5258a07352
BLAKE2b-256 be3d7241cc11f8704b97bf6c657c9a68f8576f19b4109f93304feeece415954d

See more details on using hashes here.

File details

Details for the file logtwothirds-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for logtwothirds-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 329d1f3d28e3ddf108379753e216bf226191ecbf688c89ee1969ae00551ac0d1
MD5 a247523ae4b5dd3c099a93584eab5177
BLAKE2b-256 7ec364d4d32cd30a0262670a800e2f3582838c236b9018bb342e29590ed3b913

See more details on using hashes here.

File details

Details for the file logtwothirds-0.1.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for logtwothirds-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 10ff0c41861ff934b1d0ad12cebe1ffa7daa751880b9d7d5feca99d805a853f6
MD5 e6ce4ce1abaefb56af3dd61a649c2d68
BLAKE2b-256 05d5293a398bf46f9dd5c92889eb734a5873b7b330dac9fd5277244c7cf39b6a

See more details on using hashes here.

File details

Details for the file logtwothirds-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for logtwothirds-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 949e464b5df57480ad73304fd8157b22fec198a7734976a79bdb18ed5a287a76
MD5 1e794a24030d25f0d2561a3ff4a325d6
BLAKE2b-256 f5625be6e409414699a5e57a93b820f0c308dd127db6d6aa89aefcb48c58822b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page