fastquadtree 2.0.2__tar.gz → 2.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.github/workflows/docs.yml +10 -2
- fastquadtree-2.0.4/.github/workflows/release.yml +130 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.github/workflows/test.yml +15 -26
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/Cargo.lock +1 -1
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/Cargo.toml +1 -1
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/PKG-INFO +4 -22
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/README.md +1 -2
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/engines.py +19 -19
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/plotting.py +4 -4
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/system_info_collector.py +2 -2
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/benchmark.md +1 -1
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/ballpit.py +11 -11
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pyproject.toml +59 -63
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_base_quadtree.py +19 -3
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_base_quadtree_objects.py +6 -3
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_obj_store.py +2 -1
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/pyqtree.py +2 -2
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_internal_edges.py +2 -1
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/conftest.py +3 -2
- fastquadtree-2.0.4/tests/test_python/points/test_point_quadtree_precision.py +47 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_core.py +1 -3
- fastquadtree-2.0.4/uv.lock +1940 -0
- fastquadtree-2.0.2/.github/workflows/release.yml +0 -85
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.gitignore +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.pre-commit-config.yaml +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/LICENSE +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/ballpit.png +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/interactive_v2_rect_screenshot.png +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/interactive_v2_screenshot.png +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/quadtree_bench_throughput.png +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/quadtree_bench_time.png +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/benchmark_native_vs_shim.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/benchmark_np_vs_list.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/benchmark_serialization_vs_rebuild.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/cross_library_bench.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/__init__.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/main.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/optimizer.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/runner.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/requirements.txt +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/runner.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/2.0_migration_guide.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/2.0_proposal.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/insert_result.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/item.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/point_item.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/pyqtree.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/quadtree.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/quadtree_objects.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/rect_item.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/rect_quadtree.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/rect_quadtree_objects.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/future_features.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/index.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/quickstart.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/runnables.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/rust_usage.md +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/styles/overrides.css +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/examples/custom_id_example.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/examples/object_tracking_example.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/interactive.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/interactive_v2.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/interactive_v2_rect.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/requirements.txt +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/mkdocs.yml +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pyrightconfig.json +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/__init__.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_common.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_insert_result.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_item.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/point_quadtree.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/point_quadtree_objects.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/py.typed +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/rect_quadtree.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/rect_quadtree_objects.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/geom.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/lib.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/quadtree.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/rect_quadtree.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/__init__.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/insertions.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/nearest_neighbor.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/query.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/rect_quadtree.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/rectangle_traversal.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/serialization.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_delete.rs +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/__init__.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_common_validation.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_insert_result_and_items.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_obj_store.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_serialization_container.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/integration/test_migration_breaks_and_safety.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/integration/test_public_api_contracts.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_core.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_mutation.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_numpy.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_serialization.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_deletion_update.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_numpy.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_serialization.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_core.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_mutation.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_numpy.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_serialization.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_core.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_deletion_update.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_numpy.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_serialization.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/test_pyqtree_shim_compat.py +0 -0
- {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/unconventional_bounds.rs +0 -0
|
@@ -14,7 +14,15 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
16
|
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
fetch-tags: true
|
|
17
20
|
- uses: actions/setup-python@v5
|
|
18
21
|
with: { python-version: '3.11' }
|
|
19
|
-
-
|
|
20
|
-
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v7
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
- run: uv venv .venv
|
|
27
|
+
- run: uv sync --python .venv/bin/python --group dev
|
|
28
|
+
- run: uv run mkdocs gh-deploy --force
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
release:
|
|
7
|
+
types: [published]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
name: Test build
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.10"
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v7
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Create venv
|
|
28
|
+
run: uv venv .venv
|
|
29
|
+
|
|
30
|
+
# Installs your project editable + dev group deps (from [dependency-groups].dev)
|
|
31
|
+
- name: Install dev deps
|
|
32
|
+
run: uv sync --python .venv/bin/python --group dev
|
|
33
|
+
|
|
34
|
+
# Build extension into the venv so tests import the native module
|
|
35
|
+
- name: Build with maturin (develop)
|
|
36
|
+
run: uv run --python .venv/bin/python maturin develop --release
|
|
37
|
+
|
|
38
|
+
- name: Run Python tests
|
|
39
|
+
run: uv run --python .venv/bin/python pytest
|
|
40
|
+
|
|
41
|
+
- name: Install Rust toolchain
|
|
42
|
+
uses: dtolnay/rust-toolchain@stable
|
|
43
|
+
|
|
44
|
+
- name: Run Rust tests
|
|
45
|
+
run: cargo test
|
|
46
|
+
|
|
47
|
+
- name: Upload coverage to Codecov
|
|
48
|
+
uses: codecov/codecov-action@v5
|
|
49
|
+
with:
|
|
50
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
51
|
+
|
|
52
|
+
build:
|
|
53
|
+
name: Build wheels
|
|
54
|
+
needs: test
|
|
55
|
+
runs-on: ${{ matrix.os }}
|
|
56
|
+
strategy:
|
|
57
|
+
fail-fast: false
|
|
58
|
+
matrix:
|
|
59
|
+
include:
|
|
60
|
+
# Native wheels
|
|
61
|
+
- os: ubuntu-latest
|
|
62
|
+
maturin_args: "--release --sdist --out dist"
|
|
63
|
+
manylinux: "2_28"
|
|
64
|
+
|
|
65
|
+
- os: macos-latest
|
|
66
|
+
maturin_args: "--release --out dist --target universal2-apple-darwin"
|
|
67
|
+
|
|
68
|
+
- os: windows-latest
|
|
69
|
+
maturin_args: "--release --out dist"
|
|
70
|
+
|
|
71
|
+
# Linux cross-arch wheels
|
|
72
|
+
- os: ubuntu-latest
|
|
73
|
+
maturin_args: "--release --out dist --target aarch64-unknown-linux-gnu"
|
|
74
|
+
manylinux: "2_28"
|
|
75
|
+
|
|
76
|
+
- os: ubuntu-latest
|
|
77
|
+
maturin_args: "--release --out dist --target armv7-unknown-linux-gnueabihf"
|
|
78
|
+
manylinux: "2_28"
|
|
79
|
+
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
|
|
83
|
+
# Keep Python simple here; maturin-action brings its own Python(s) for builds.
|
|
84
|
+
- name: Set up Python
|
|
85
|
+
uses: actions/setup-python@v5
|
|
86
|
+
with:
|
|
87
|
+
python-version: "3.10"
|
|
88
|
+
|
|
89
|
+
- name: Build wheels with maturin
|
|
90
|
+
uses: PyO3/maturin-action@v1
|
|
91
|
+
with:
|
|
92
|
+
command: build
|
|
93
|
+
args: ${{ matrix.maturin_args }}
|
|
94
|
+
manylinux: ${{ matrix.manylinux }}
|
|
95
|
+
|
|
96
|
+
- name: Upload dist artifacts
|
|
97
|
+
uses: actions/upload-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
name: dist-${{ runner.os }}-${{ matrix.maturin_args }}
|
|
100
|
+
path: dist/*
|
|
101
|
+
|
|
102
|
+
publish:
|
|
103
|
+
name: Publish distributions to PyPI
|
|
104
|
+
needs: build
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
permissions:
|
|
107
|
+
contents: read
|
|
108
|
+
id-token: write # for Trusted Publisher (recommended)
|
|
109
|
+
steps:
|
|
110
|
+
- uses: actions/checkout@v4
|
|
111
|
+
|
|
112
|
+
- name: Install uv
|
|
113
|
+
uses: astral-sh/setup-uv@v7
|
|
114
|
+
|
|
115
|
+
- name: Download all dist artifacts
|
|
116
|
+
uses: actions/download-artifact@v4
|
|
117
|
+
with:
|
|
118
|
+
pattern: dist-*
|
|
119
|
+
path: dist
|
|
120
|
+
merge-multiple: true
|
|
121
|
+
|
|
122
|
+
# Option A (recommended): PyPI Trusted Publisher (OIDC), no token needed.
|
|
123
|
+
# - name: Publish (Trusted Publisher)
|
|
124
|
+
# run: uv publish dist/*
|
|
125
|
+
|
|
126
|
+
# Option B: Token-based publish.
|
|
127
|
+
- name: Publish (Token)
|
|
128
|
+
env:
|
|
129
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
130
|
+
run: uv publish dist/*
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
# .github/workflows/test.yml
|
|
2
1
|
name: Test
|
|
3
2
|
on:
|
|
4
3
|
push:
|
|
5
4
|
branches: [ main ]
|
|
6
5
|
|
|
7
|
-
permissions:
|
|
8
|
-
contents: write
|
|
9
|
-
pages: write
|
|
10
|
-
id-token: write
|
|
11
|
-
|
|
12
6
|
jobs:
|
|
13
7
|
test:
|
|
14
8
|
name: Test build (Python ${{ matrix.python-version }})
|
|
@@ -26,32 +20,27 @@ jobs:
|
|
|
26
20
|
with:
|
|
27
21
|
python-version: ${{ matrix.python-version }}
|
|
28
22
|
allow-prereleases: true
|
|
29
|
-
cache: "pip"
|
|
30
|
-
|
|
31
|
-
- name: Create venv for maturin develop
|
|
32
|
-
run: python -m venv .venv
|
|
33
23
|
|
|
34
|
-
- name:
|
|
35
|
-
uses:
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
36
26
|
with:
|
|
37
|
-
|
|
38
|
-
args: --release
|
|
39
|
-
manylinux: manylinux2014
|
|
27
|
+
enable-cache: true
|
|
40
28
|
|
|
41
|
-
- name:
|
|
42
|
-
run:
|
|
43
|
-
. .venv/bin/activate
|
|
44
|
-
pip install -e '.[dev]'
|
|
29
|
+
- name: Create venv (uv)
|
|
30
|
+
run: uv venv .venv
|
|
45
31
|
|
|
46
|
-
- name:
|
|
47
|
-
run:
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
- name: Build with maturin into this Python
|
|
33
|
+
run: uv run --python .venv/bin/python maturin develop --release
|
|
34
|
+
env:
|
|
35
|
+
# keeps your manylinux intent for Linux builds in other workflows;
|
|
36
|
+
# for develop on ubuntu-latest this is mostly irrelevant
|
|
37
|
+
MATURIN_MANYLINUX: "2_28"
|
|
38
|
+
|
|
39
|
+
- name: Install dev deps (uv)
|
|
40
|
+
run: uv sync --python .venv/bin/python --group dev
|
|
50
41
|
|
|
51
42
|
- name: Run Python tests
|
|
52
|
-
run:
|
|
53
|
-
. .venv/bin/activate
|
|
54
|
-
pytest
|
|
43
|
+
run: uv run --python .venv/bin/python pytest
|
|
55
44
|
|
|
56
45
|
- name: Install Rust toolchain
|
|
57
46
|
uses: dtolnay/rust-toolchain@stable
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastquadtree
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -11,33 +11,16 @@ Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
|
11
11
|
Classifier: Topic :: Software Development :: Libraries
|
|
12
12
|
Classifier: Typing :: Typed
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Requires-Dist: ruff>=0.6.0 ; extra == 'dev'
|
|
15
|
-
Requires-Dist: pytest>=8.4.2 ; extra == 'dev'
|
|
16
|
-
Requires-Dist: pytest-cov>=7.0.0 ; extra == 'dev'
|
|
17
|
-
Requires-Dist: coverage>=7.5 ; extra == 'dev'
|
|
18
|
-
Requires-Dist: mypy>=1.10 ; extra == 'dev'
|
|
19
|
-
Requires-Dist: build>=1.2.1 ; extra == 'dev'
|
|
20
|
-
Requires-Dist: mkdocs>=1.6 ; extra == 'dev'
|
|
21
|
-
Requires-Dist: mkdocs-material ; extra == 'dev'
|
|
22
|
-
Requires-Dist: mkdocstrings[python] ; extra == 'dev'
|
|
23
|
-
Requires-Dist: mkdocs-autorefs ; extra == 'dev'
|
|
24
|
-
Requires-Dist: mkdocs-git-revision-date-localized-plugin ; extra == 'dev'
|
|
25
|
-
Requires-Dist: mkdocs-minify-plugin ; extra == 'dev'
|
|
26
|
-
Requires-Dist: maturin>=1.5 ; extra == 'dev'
|
|
27
|
-
Requires-Dist: pyqtree==1.0.0 ; extra == 'dev'
|
|
28
|
-
Requires-Dist: numpy ; extra == 'dev'
|
|
29
|
-
Requires-Dist: pre-commit ; extra == 'dev'
|
|
30
|
-
Provides-Extra: dev
|
|
31
14
|
License-File: LICENSE
|
|
32
15
|
Summary: Rust-accelerated quadtree for Python with fast inserts, range queries, and k-NN search.
|
|
33
16
|
Keywords: quadtree,spatial-index,geometry,rust,pyo3,nearest-neighbor,k-nn
|
|
34
17
|
Author: Ethan Anderson
|
|
35
18
|
Requires-Python: >=3.9
|
|
36
19
|
Description-Content-Type: text/markdown
|
|
37
|
-
Project-URL: Homepage, https://github.com/Elan456/fastquadtree
|
|
38
|
-
Project-URL: Repository, https://github.com/Elan456/fastquadtree
|
|
39
20
|
Project-URL: Documentation, https://elan456.github.io/fastquadtree/
|
|
21
|
+
Project-URL: Homepage, https://github.com/Elan456/fastquadtree
|
|
40
22
|
Project-URL: Issues, https://github.com/Elan456/fastquadtree/issues
|
|
23
|
+
Project-URL: Repository, https://github.com/Elan456/fastquadtree
|
|
41
24
|
|
|
42
25
|
# fastquadtree
|
|
43
26
|
|
|
@@ -113,9 +96,8 @@ fastquadtree **outperforms** all other quadtree Python packages, including the R
|
|
|
113
96
|

|
|
114
97
|

|
|
115
98
|
|
|
116
|
-
### Summary (
|
|
99
|
+
### Summary (PyQtree baseline, sorted by total time)
|
|
117
100
|
- Points: **500,000**, Queries: **500**
|
|
118
|
-
- Fastest total: **fastquadtree** at **0.067 s**
|
|
119
101
|
|
|
120
102
|
| Library | Build (s) | Query (s) | Total (s) | Speed vs PyQtree |
|
|
121
103
|
|---|---:|---:|---:|---:|
|
|
@@ -72,9 +72,8 @@ fastquadtree **outperforms** all other quadtree Python packages, including the R
|
|
|
72
72
|

|
|
73
73
|

|
|
74
74
|
|
|
75
|
-
### Summary (
|
|
75
|
+
### Summary (PyQtree baseline, sorted by total time)
|
|
76
76
|
- Points: **500,000**, Queries: **500**
|
|
77
|
-
- Fastest total: **fastquadtree** at **0.067 s**
|
|
78
77
|
|
|
79
78
|
| Library | Build (s) | Query (s) | Total (s) | Speed vs PyQtree |
|
|
80
79
|
|---|---:|---:|---:|---:|
|
|
@@ -5,7 +5,7 @@ This module provides a unified interface for different quadtree libraries,
|
|
|
5
5
|
allowing fair comparison of their performance characteristics.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import Any, Callable,
|
|
8
|
+
from typing import Any, Callable, Optional
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
from pyqtree import Index as PyQTree # Pyqtree
|
|
@@ -30,8 +30,8 @@ class Engine:
|
|
|
30
30
|
self,
|
|
31
31
|
name: str,
|
|
32
32
|
color: str,
|
|
33
|
-
build_fn: Callable[[
|
|
34
|
-
query_fn: Callable[[Any,
|
|
33
|
+
build_fn: Callable[[list[tuple[int, int]]], Any],
|
|
34
|
+
query_fn: Callable[[Any, list[tuple[int, int, int, int]]], None],
|
|
35
35
|
):
|
|
36
36
|
"""
|
|
37
37
|
Initialize an engine adapter.
|
|
@@ -47,17 +47,17 @@ class Engine:
|
|
|
47
47
|
self._build = build_fn
|
|
48
48
|
self._query = query_fn
|
|
49
49
|
|
|
50
|
-
def build(self, points:
|
|
50
|
+
def build(self, points: list[tuple[int, int]]) -> Any:
|
|
51
51
|
"""Build a tree from the given points."""
|
|
52
52
|
return self._build(points)
|
|
53
53
|
|
|
54
|
-
def query(self, tree: Any, queries:
|
|
54
|
+
def query(self, tree: Any, queries: list[tuple[int, int, int, int]]) -> None:
|
|
55
55
|
"""Execute queries on the tree."""
|
|
56
56
|
return self._query(tree, queries)
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
def _create_e_pyquadtree_engine(
|
|
60
|
-
bounds:
|
|
60
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
61
61
|
) -> Engine:
|
|
62
62
|
"""Create engine adapter for e-pyquadtree."""
|
|
63
63
|
|
|
@@ -80,7 +80,7 @@ def _create_e_pyquadtree_engine(
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def _create_pyqtree_engine(
|
|
83
|
-
bounds:
|
|
83
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
84
84
|
) -> Engine:
|
|
85
85
|
"""Create engine adapter for PyQtree."""
|
|
86
86
|
|
|
@@ -98,7 +98,7 @@ def _create_pyqtree_engine(
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
def _create_fastquadtree_np_engine(
|
|
101
|
-
bounds:
|
|
101
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
102
102
|
) -> Engine:
|
|
103
103
|
"""Create engine adapter for fastquadtree but queries are returned as numpy arrays instead of Python lists."""
|
|
104
104
|
|
|
@@ -120,7 +120,7 @@ def _create_fastquadtree_np_engine(
|
|
|
120
120
|
|
|
121
121
|
|
|
122
122
|
def _create_fastquadtree_engine(
|
|
123
|
-
bounds:
|
|
123
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
124
124
|
) -> Engine:
|
|
125
125
|
"""Create engine adapter for fastquadtree."""
|
|
126
126
|
|
|
@@ -142,7 +142,7 @@ def _create_fastquadtree_engine(
|
|
|
142
142
|
|
|
143
143
|
|
|
144
144
|
def _create_fastquadtree_items_engine(
|
|
145
|
-
bounds:
|
|
145
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
146
146
|
) -> Engine:
|
|
147
147
|
"""Create engine adapter for fastquadtree."""
|
|
148
148
|
|
|
@@ -164,7 +164,7 @@ def _create_fastquadtree_items_engine(
|
|
|
164
164
|
|
|
165
165
|
|
|
166
166
|
def _create_quads_engine(
|
|
167
|
-
bounds:
|
|
167
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
168
168
|
) -> Optional[Engine]:
|
|
169
169
|
"""Create engine adapter for quads library (optional)."""
|
|
170
170
|
try:
|
|
@@ -194,7 +194,7 @@ def _create_quads_engine(
|
|
|
194
194
|
|
|
195
195
|
|
|
196
196
|
def _create_nontree_engine(
|
|
197
|
-
bounds:
|
|
197
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
198
198
|
) -> Optional[Engine]:
|
|
199
199
|
"""Create engine adapter for nontree library (optional)."""
|
|
200
200
|
try:
|
|
@@ -227,7 +227,7 @@ def _create_nontree_engine(
|
|
|
227
227
|
|
|
228
228
|
|
|
229
229
|
def _create_brute_force_engine(
|
|
230
|
-
bounds:
|
|
230
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
231
231
|
) -> Engine:
|
|
232
232
|
"""Create engine adapter for brute force search (always available)."""
|
|
233
233
|
|
|
@@ -252,7 +252,7 @@ def _create_brute_force_engine(
|
|
|
252
252
|
|
|
253
253
|
|
|
254
254
|
def _create_rtree_engine(
|
|
255
|
-
bounds:
|
|
255
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
256
256
|
) -> Optional[Engine]:
|
|
257
257
|
"""Create engine adapter for rtree library (optional)."""
|
|
258
258
|
try:
|
|
@@ -286,11 +286,11 @@ def _create_rtree_engine(
|
|
|
286
286
|
|
|
287
287
|
|
|
288
288
|
def _create_strtree_engine(
|
|
289
|
-
bounds:
|
|
289
|
+
bounds: tuple[int, int, int, int], max_points: int, max_depth: int
|
|
290
290
|
) -> Optional[Engine]:
|
|
291
291
|
"""Create engine adapter for Shapely STRtree (optional)."""
|
|
292
292
|
|
|
293
|
-
def build(points_list:
|
|
293
|
+
def build(points_list: list[tuple[int, int]]):
|
|
294
294
|
# Build geometries efficiently
|
|
295
295
|
|
|
296
296
|
xs = np.fromiter(
|
|
@@ -305,7 +305,7 @@ def _create_strtree_engine(
|
|
|
305
305
|
# Keep geoms alive next to the tree
|
|
306
306
|
return (tree, geoms)
|
|
307
307
|
|
|
308
|
-
def query(built, queries:
|
|
308
|
+
def query(built, queries: list[tuple[int, int, int, int]]):
|
|
309
309
|
tree, _geoms = built
|
|
310
310
|
for xmin, ymin, xmax, ymax in queries:
|
|
311
311
|
window = shp_box(xmin, ymin, xmax, ymax)
|
|
@@ -319,10 +319,10 @@ def _create_strtree_engine(
|
|
|
319
319
|
|
|
320
320
|
|
|
321
321
|
def get_engines(
|
|
322
|
-
bounds:
|
|
322
|
+
bounds: tuple[int, int, int, int] = (0, 0, 1000, 1000),
|
|
323
323
|
max_points: int = 20,
|
|
324
324
|
max_depth: int = 10,
|
|
325
|
-
) ->
|
|
325
|
+
) -> dict[str, Engine]:
|
|
326
326
|
"""
|
|
327
327
|
Get all available engine adapters.
|
|
328
328
|
|
|
@@ -5,7 +5,7 @@ This module handles creation of performance charts, graphs, and visualizations
|
|
|
5
5
|
for benchmark results analysis.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import Any
|
|
8
|
+
from typing import Any
|
|
9
9
|
|
|
10
10
|
import plotly.graph_objects as go
|
|
11
11
|
from plotly.subplots import make_subplots
|
|
@@ -14,7 +14,7 @@ from plotly.subplots import make_subplots
|
|
|
14
14
|
class PlotManager:
|
|
15
15
|
"""Manages creation and export of benchmark visualization plots."""
|
|
16
16
|
|
|
17
|
-
def __init__(self, results:
|
|
17
|
+
def __init__(self, results: dict[str, Any]):
|
|
18
18
|
"""Initialize with benchmark results."""
|
|
19
19
|
self.results = results
|
|
20
20
|
self.config = results["config"]
|
|
@@ -29,7 +29,7 @@ class PlotManager:
|
|
|
29
29
|
horizontal_spacing=0.08,
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
def add_time_traces(y_data:
|
|
32
|
+
def add_time_traces(y_data: dict[str, list], col: int):
|
|
33
33
|
"""Add traces for a specific time metric."""
|
|
34
34
|
show_legend = col == 1 # Only show legend for first column
|
|
35
35
|
for name in list(y_data.keys()):
|
|
@@ -160,7 +160,7 @@ class PlotManager:
|
|
|
160
160
|
|
|
161
161
|
return fig
|
|
162
162
|
|
|
163
|
-
def create_all_plots(self) ->
|
|
163
|
+
def create_all_plots(self) -> tuple[go.Figure, go.Figure]:
|
|
164
164
|
"""Create all benchmark plots."""
|
|
165
165
|
time_fig = self.create_time_plots()
|
|
166
166
|
throughput_fig = self.create_throughput_plots()
|
|
@@ -3,7 +3,7 @@ import json
|
|
|
3
3
|
import platform
|
|
4
4
|
import shutil
|
|
5
5
|
import subprocess
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
import cpuinfo
|
|
9
9
|
import distro
|
|
@@ -67,7 +67,7 @@ def _collect_gpus() -> list[dict]:
|
|
|
67
67
|
return gpus
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def collect_system_info() ->
|
|
70
|
+
def collect_system_info() -> dict[str, Any]:
|
|
71
71
|
info = {
|
|
72
72
|
"os": {
|
|
73
73
|
"system": platform.system(),
|
|
@@ -12,7 +12,7 @@ Quadtrees are the focus of the benchmark, but Rtrees are included for reference.
|
|
|
12
12
|
|
|
13
13
|
### Summary (largest dataset, PyQtree baseline)
|
|
14
14
|
- Points: **500,000**, Queries: **500**
|
|
15
|
-
- Fastest total: **fastquadtree** at **0.
|
|
15
|
+
- Fastest total: **fastquadtree** at **0.078 s**
|
|
16
16
|
|
|
17
17
|
| Library | Build (s) | Query (s) | Total (s) | Speed vs PyQtree |
|
|
18
18
|
|---|---:|---:|---:|---:|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import math
|
|
2
2
|
import random
|
|
3
3
|
import time
|
|
4
|
-
from
|
|
4
|
+
from collections.abc import Iterable
|
|
5
5
|
|
|
6
6
|
import pygame
|
|
7
7
|
from pyqtree import Index as PyQIndex
|
|
@@ -20,7 +20,7 @@ class Ball:
|
|
|
20
20
|
x: float,
|
|
21
21
|
y: float,
|
|
22
22
|
r: int = 10,
|
|
23
|
-
color:
|
|
23
|
+
color: tuple[int, int, int] = (255, 0, 0),
|
|
24
24
|
vx: float = 0.0,
|
|
25
25
|
vy: float = 0.0,
|
|
26
26
|
mass: float = 1.0,
|
|
@@ -35,7 +35,7 @@ class Ball:
|
|
|
35
35
|
self.mass = float(mass)
|
|
36
36
|
self.restitution = float(restitution)
|
|
37
37
|
|
|
38
|
-
def aabb(self) ->
|
|
38
|
+
def aabb(self) -> tuple[float, float, float, float]:
|
|
39
39
|
return (self.x - self.r, self.y - self.r, self.x + self.r, self.y + self.r)
|
|
40
40
|
|
|
41
41
|
def integrate(self, ax: float, ay: float, dt: float):
|
|
@@ -117,7 +117,7 @@ def resolve_ball_ball(a: Ball, b: Ball):
|
|
|
117
117
|
class SpatialBase:
|
|
118
118
|
name = "base"
|
|
119
119
|
|
|
120
|
-
def rebuild(self, balls:
|
|
120
|
+
def rebuild(self, balls: list[Ball], width: int, height: int) -> None:
|
|
121
121
|
raise NotImplementedError
|
|
122
122
|
|
|
123
123
|
def neighbors(self, b: Ball) -> Iterable[Ball]:
|
|
@@ -133,7 +133,7 @@ class FastQTIndex(SpatialBase):
|
|
|
133
133
|
self.capacity = capacity
|
|
134
134
|
self.qt = Quadtree((0, 0, width, height), capacity)
|
|
135
135
|
|
|
136
|
-
def rebuild(self, balls:
|
|
136
|
+
def rebuild(self, balls: list[Ball], width: int, height: int) -> None:
|
|
137
137
|
if width != self.width or height != self.height:
|
|
138
138
|
self.width, self.height = width, height
|
|
139
139
|
self.qt.clear()
|
|
@@ -142,7 +142,7 @@ class FastQTIndex(SpatialBase):
|
|
|
142
142
|
|
|
143
143
|
self.qt.insert_many([(b.x, b.y) for b in balls])
|
|
144
144
|
|
|
145
|
-
def neighbors(self, b: Ball, balls:
|
|
145
|
+
def neighbors(self, b: Ball, balls: list[Ball]) -> Iterable[Ball]:
|
|
146
146
|
r2 = 2 * b.r
|
|
147
147
|
min_x, min_y, max_x, max_y = b.x - r2, b.y - r2, b.x + r2, b.y + r2
|
|
148
148
|
neighbors = self.qt.query((min_x, min_y, max_x, max_y))
|
|
@@ -166,7 +166,7 @@ class PyQTreeIndex(SpatialBase):
|
|
|
166
166
|
bbox=(0, 0, width, height), max_items=max_items, max_depth=max_depth
|
|
167
167
|
)
|
|
168
168
|
|
|
169
|
-
def rebuild(self, balls:
|
|
169
|
+
def rebuild(self, balls: list[Ball], width: int, height: int) -> None:
|
|
170
170
|
if width != self.width or height != self.height:
|
|
171
171
|
self.width, self.height = width, height
|
|
172
172
|
self.idx = PyQIndex(
|
|
@@ -196,10 +196,10 @@ class PyQTreeIndex(SpatialBase):
|
|
|
196
196
|
class BruteIndex(SpatialBase):
|
|
197
197
|
name = "bruteforce"
|
|
198
198
|
|
|
199
|
-
def __init__(self, balls_ref:
|
|
199
|
+
def __init__(self, balls_ref: list[Ball]):
|
|
200
200
|
self._balls = balls_ref
|
|
201
201
|
|
|
202
|
-
def rebuild(self, balls:
|
|
202
|
+
def rebuild(self, balls: list[Ball], width: int, height: int) -> None:
|
|
203
203
|
# Nothing to build
|
|
204
204
|
pass
|
|
205
205
|
|
|
@@ -218,7 +218,7 @@ class BallPit:
|
|
|
218
218
|
self.width = width
|
|
219
219
|
self.height = height
|
|
220
220
|
|
|
221
|
-
self.balls:
|
|
221
|
+
self.balls: list[Ball] = []
|
|
222
222
|
self.pair_checks = 0 # updated each frame
|
|
223
223
|
|
|
224
224
|
# Spatial backends
|
|
@@ -279,7 +279,7 @@ class BallPit:
|
|
|
279
279
|
|
|
280
280
|
# 3) Neighborhood checks with dedup on object id pairs
|
|
281
281
|
self.pair_checks = 0
|
|
282
|
-
processed:
|
|
282
|
+
processed: set[tuple[int, int]] = set()
|
|
283
283
|
for a in self.balls:
|
|
284
284
|
start = time.perf_counter()
|
|
285
285
|
if self.mode == "fastquadtree":
|