Add FlexibleRTrees and speed up NaturalIndex traversal#431
Merged
Conversation
…le bulk loading
Vendored and restructured from SortTileRecursiveTree.jl: storage is a flat
vector of per-level extent vectors plus a leaf permutation (like
`NaturalIndex` and JTS `HPRtree`), so `RTree{A, E}` is concrete regardless of
depth, works for extents of any dimensionality, and is fully inferrable. The
bulk-load algorithm is a value — `RTree(STR() | HPR() | Unsorted(), data)` —
where `HPR` sorts by Skilling N-dimensional Hilbert codes and adding an
algorithm is one singleton type plus one `loadorder` method. Implements
SpatialTreeInterface, so `depth_first_search` and everything built on it
work unchanged.
Benchmarks: on spatially random collections HPR beats STR by ~20% and
unsorted packing by ~1000x; on ring edges natural order remains fastest,
confirming `NaturalIndex` as the default there.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each per-child operation (`nchild`, `getchild`, `child_indices_extents`) re-chased `parent_index -> levels -> level -> extents` for every child, and profiles showed that pointer chase dominating tree-query time. Hoisting the child-extent vector once per node makes the generic SpatialTreeInterface queries ~1.7x faster (point-in-polygon over an indexed ring: 300 ns -> 178 ns per query on a 65k-vertex polygon) with no interface or layout change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
asinghvi17
commented
Jul 6, 2026
Split the module body into one file per concern, following the SpatialTreeInterface convention: `types.jl` (the `BulkLoadAlgorithm`s and `RTree`), `bulk_loading.jl` (`loadorder` methods and packing), `interface.jl` (SpatialTreeInterface implementation and `query`), with `hilbert.jl` unchanged. Pure code motion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
They sit with the file that extends them; drops the `node_extent` import, which nothing extended or called. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Split out of #428 so the spatial-tree improvements can land independently of prepared geometry.
FlexibleRTrees(new)A packed , static R-tree over
Extents of any dimensionality, vendored and restructured from SortTileRecursiveTree.jl. Storage is a flat vector of per-level extent vectors plus a leaf permutation (likeNaturalIndexand JTSHPRtree), soRTree{A, E}is concrete regardless of depth and fully inferrable.Benchmarks: on spatially random collections, HPR beats STR by ~20% and unsorted packing by ~1000×; on ring edges natural order remains fastest, confirming
NaturalIndexas the default there. The other advantage here is type stability, so you can do things like nearest neighbour queries and distance queries on it.NaturalIndextraversal speed-upEach per-child operation (
nchild,getchild,child_indices_extents) re-chasedparent_index → levels → level → extentsfor every child, and profiles showed that pointer chase dominating tree-query time. Hoisting the child-extent vector once per node makes generic SpatialTreeInterface queries ~1.7× faster (point-in-polygon over an indexed ring: 300 ns → 178 ns per query on a 65k-vertex polygon) with no interface or layout change.Relation to #428
The prepared-geometry integration stays there: the
build_edge_treehook that lets a bulk-load algorithm selectRTreeas an edge-tree backend, and the corresponding integration testset.🤖 Generated with Claude Code