Skip to main content

fastintervaltree

PyPI ci License: Apache-2.0

A drop-in subclass of intervaltree's IntervalTree whose range queries walk the tree once. It returns the same sets as intervaltree 3.2.1, and is pure Python.

# before
from intervaltree import Interval, IntervalTree
# after: nothing else changes
from fastintervaltree import Interval, IntervalTree

Status: version 0.1.0, working and tested. The overlap and envelop change has also been offered to intervaltree itself as pull request #166; if that is merged and released, most of the reason for this package goes away.

Why

intervaltree answers overlap(begin, end) with one point search for begin and then one more for every interval boundary inside the range. On a tree of 12,000 intervals a query that returns 71 of them takes about 1.4 ms. Users have reported this on intervaltree's tracker (#120, #127). envelop works the same way, and overlaps with a range scans the whole table of boundaries when the answer is not found at once.

Here each of these is a single descent that skips a subtree the range cannot reach. The tree, its nodes and every operation that changes the tree are intervaltree's own code, inherited unchanged.

Numbers

Microseconds per query, intervaltree 3.2.1 against this package on identical trees, random integer intervals. Python 3.13.5, Windows, one laptop; process pinned, 5 rounds with the two variants alternating, best round of each. Full output: results/bench_queries.txt.

Tree Query width Hits per query overlap envelop overlaps (yes/no)
12,000 intervals, length up to 2,000 5,000 71 1,383 → 12.5 (111x) 1,390 → 14.0 (99x) 10.5 → 3.3 (3.2x)
100,000 intervals, length up to 2,000 5,000 59 1,540 → 19.1 (81x) 1,572 → 18.9 (83x) 14.3 → 5.8 (2.5x)
same tree 100,000 1,013 30,640 → 119 (257x) 31,879 → 378 (84x) 14.1 → 2.7 (5.2x)
100,000 intervals, length up to 200,000 5,000 1,027 69,981 → 654 (107x) 61,706 → 1.3 277 → 134 (2.1x)
450,000 intervals, length up to 400 5,000 52 896 → 17.4 (51x) 939 → 22.7 (42x) 2,973 → 4.1 (723x)
450,000 short intervals with gaps 200 0.2 12.5 → 4.2 (3.0x) 11.6 → 1.6 (7.1x) 57,613 → 2.2
12,000 intervals with endpoints in 0..63 8 4,686 33,516 → 5,074 (6.6x) 32,832 → 1,839 (18x) 13.9 → 5.3 (2.6x)

How to read it:

  • The gain grows with the number of boundaries inside the query range. Narrow queries on sparse trees gain about 3x; wide ones gain 50x to 250x.
  • Rows where the original took tens of milliseconds were timed on few queries (5 to 20 per round), so those ratios are rough. Two cells have no ratio because it would mislead: the envelop that drops from 62 ms to 1.3 us returns 0.6 intervals per query, and the overlaps that drops from 58 ms to 2.2 us is the case where the original scans all of the roughly 900,000 boundaries.
  • The last row is the shape reported in issue #120, and it gains least. See "What is not faster".
  • Point queries (at, tree[p]) are 1.0x to 1.5x. Building a tree and add cost 0% to 5% more than the original in two runs, which is within this machine's noise.

remove_overlap, remove_envelop, chop and tree[a:b] call these queries and get faster with them. They were not timed separately.

What is not faster

  • Many intervals with the same range. Interval.__hash__ uses only begin and end, so intervals that share a range and differ in data all land in one hash bucket, and every set that holds k of them costs on the order of k squared comparisons. With 1,000 such intervals one at took 129 ms in the original; with 5,000 it took 3.0 s. This package does not change that (#126), and it is why the 0..63 row above gains only 6.6x. Interval is intervaltree's own class here, so its hash cannot be changed without breaking equality with intervals made elsewhere.
  • Building, add, remove, merge_*, split_overlaps and the set operations are intervaltree's code. split_overlaps on 100,000 sparse intervals took 29.7 s in one profiling run (results/profile_ops.txt).

Differences from intervaltree

Results are equal sets of the same Interval objects. Three things differ:

  1. Iteration order of a result set from overlap and envelop can differ, because hits are found in a different order. at keeps the original's order. Since remove_overlap(begin, end), remove_envelop and chop remove hits in iteration order, the internal layout of the tree afterwards can differ from what intervaltree would have built. Its contents, and the answers to every query, do not.
  2. copy, union, difference, intersection, symmetric_difference, from_tuples and unpickling return this package's IntervalTree. In intervaltree 3.2.1 a subclass gets plain IntervalTrees back from these; its development branch has already changed that.
  3. NaN. If a query endpoint or any endpoint in the tree is NaN, the call is passed to intervaltree's own code, so the answer is whatever intervaltree gives.

Endpoints are assumed to be totally ordered apart from NaN. Types with a partial order (sets, for example) are not supported and not tested.

Evidence

  • Parity tests (tests/test_parity.py): every query at every pair of points against intervaltree, with int, float (including infinities and -0.0), Fraction, str and datetime endpoints; trees built at once and one interval at a time; and again after every step of random sequences drawn from 28 operations. Exception types are compared as well as results. Hypothesis generates the cases.
  • The fast path is the code under test (tests/test_fast_path.py): a counter on intervaltree's two search routines reads zero for ordinary trees, and non-zero when NaN forces the fallback.
  • Mutation check (tools/mutation_check.py): 37 deliberate one-line breakages; the tests catch 33. The other 4 cannot change any answer, and the reasons are printed in results/mutation_check.txt.
  • intervaltree's own test suite at tag 3.2.1 passes with this class swapped in (tools/swap_in_fast.py): 99 tests, the same count as without the swap.

CI runs the tests on Linux, Windows and macOS with Python 3.10, 3.13 and 3.15, and on Linux with Python 3.9, always against intervaltree 3.2.1. Python 3.11 was run once by hand.

Install

pip install fastintervaltree

It needs Python 3.9 or newer and installs intervaltree 3.2.x as a dependency.

To run the checks, from a clone:

pip install -e ".[test]"
python -m pytest                      # about 2 minutes
python tools/mutation_check.py        # several minutes, 6 processes
python research/bench_queries.py      # a few minutes; needs a quiet machine

Licence

Apache-2.0, the same as intervaltree, from which this is derived. See NOTICE. Written with the help of an AI coding assistant (Claude Code).

Metadata

Release files for fastintervaltree 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastintervaltree 0.1.0
File Size Uploaded Provenance Actions
fastintervaltree-0.1.0.tar.gz 20.6 kB With provenance Details for fastintervaltree-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fastintervaltree 0.1.0
File Interpreter ABI Platform Actions
fastintervaltree-0.1.0-py3-none-any.whl Python 3 none any Details for fastintervaltree-0.1.0-py3-none-any.whl

Total release size: 33.1 kB

Release files / fastintervaltree-0.1.0.tar.gz

Download URL fastintervaltree-0.1.0.tar.gz
Size 20.6 kB
Tags Source
SHA-256 checksum
How to use checksums
14cf960dc17599d24710ebdf14eab59cd1904147b1ef3118869dfcb908b85d51
BLAKE2b-256 checksum
How to use checksums
63c5e9ffee9dfb162fe8efaf07c3dda2db9d69050b9a6ffdf7b723d2bf878e9e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Release files / fastintervaltree-0.1.0-py3-none-any.whl

Download URL fastintervaltree-0.1.0-py3-none-any.whl
Size 12.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b64a76a741c8d5176edde6f6e20db83ff8372f743f17a328c340323d914e8700
BLAKE2b-256 checksum
How to use checksums
203ecb18ef223bfcc3d2f03128f70756c0b62bbc55b8ba0a96597e3207c697b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Security for fastintervaltree 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fastintervaltree-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page