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.
Files changed (111) hide show
  1. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.github/workflows/docs.yml +10 -2
  2. fastquadtree-2.0.4/.github/workflows/release.yml +130 -0
  3. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.github/workflows/test.yml +15 -26
  4. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/Cargo.lock +1 -1
  5. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/Cargo.toml +1 -1
  6. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/PKG-INFO +4 -22
  7. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/README.md +1 -2
  8. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/engines.py +19 -19
  9. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/plotting.py +4 -4
  10. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/system_info_collector.py +2 -2
  11. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/benchmark.md +1 -1
  12. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/ballpit.py +11 -11
  13. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pyproject.toml +59 -63
  14. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_base_quadtree.py +19 -3
  15. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_base_quadtree_objects.py +6 -3
  16. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_obj_store.py +2 -1
  17. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/pyqtree.py +2 -2
  18. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_internal_edges.py +2 -1
  19. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/conftest.py +3 -2
  20. fastquadtree-2.0.4/tests/test_python/points/test_point_quadtree_precision.py +47 -0
  21. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_core.py +1 -3
  22. fastquadtree-2.0.4/uv.lock +1940 -0
  23. fastquadtree-2.0.2/.github/workflows/release.yml +0 -85
  24. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.gitignore +0 -0
  25. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/.pre-commit-config.yaml +0 -0
  26. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/LICENSE +0 -0
  27. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/ballpit.png +0 -0
  28. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/interactive_v2_rect_screenshot.png +0 -0
  29. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/interactive_v2_screenshot.png +0 -0
  30. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/quadtree_bench_throughput.png +0 -0
  31. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/assets/quadtree_bench_time.png +0 -0
  32. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/benchmark_native_vs_shim.py +0 -0
  33. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/benchmark_np_vs_list.py +0 -0
  34. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/benchmark_serialization_vs_rebuild.py +0 -0
  35. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/cross_library_bench.py +0 -0
  36. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/__init__.py +0 -0
  37. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/main.py +0 -0
  38. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/optimizer.py +0 -0
  39. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/quadtree_bench/runner.py +0 -0
  40. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/requirements.txt +0 -0
  41. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/benchmarks/runner.py +0 -0
  42. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/2.0_migration_guide.md +0 -0
  43. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/2.0_proposal.md +0 -0
  44. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/insert_result.md +0 -0
  45. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/item.md +0 -0
  46. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/point_item.md +0 -0
  47. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/pyqtree.md +0 -0
  48. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/quadtree.md +0 -0
  49. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/quadtree_objects.md +0 -0
  50. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/rect_item.md +0 -0
  51. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/rect_quadtree.md +0 -0
  52. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/api/rect_quadtree_objects.md +0 -0
  53. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/future_features.md +0 -0
  54. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/index.md +0 -0
  55. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/quickstart.md +0 -0
  56. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/runnables.md +0 -0
  57. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/rust_usage.md +0 -0
  58. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/docs/styles/overrides.css +0 -0
  59. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/examples/custom_id_example.py +0 -0
  60. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/examples/object_tracking_example.py +0 -0
  61. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/interactive.py +0 -0
  62. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/interactive_v2.py +0 -0
  63. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/interactive_v2_rect.py +0 -0
  64. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/interactive/requirements.txt +0 -0
  65. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/mkdocs.yml +0 -0
  66. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pyrightconfig.json +0 -0
  67. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/__init__.py +0 -0
  68. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_common.py +0 -0
  69. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_insert_result.py +0 -0
  70. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/_item.py +0 -0
  71. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/point_quadtree.py +0 -0
  72. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/point_quadtree_objects.py +0 -0
  73. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/py.typed +0 -0
  74. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/rect_quadtree.py +0 -0
  75. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/pysrc/fastquadtree/rect_quadtree_objects.py +0 -0
  76. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/geom.rs +0 -0
  77. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/lib.rs +0 -0
  78. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/quadtree.rs +0 -0
  79. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/src/rect_quadtree.rs +0 -0
  80. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/__init__.py +0 -0
  81. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/insertions.rs +0 -0
  82. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/nearest_neighbor.rs +0 -0
  83. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/query.rs +0 -0
  84. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/rect_quadtree.rs +0 -0
  85. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/rectangle_traversal.rs +0 -0
  86. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/serialization.rs +0 -0
  87. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_delete.rs +0 -0
  88. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/__init__.py +0 -0
  89. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_common_validation.py +0 -0
  90. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_insert_result_and_items.py +0 -0
  91. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_obj_store.py +0 -0
  92. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/common/test_serialization_container.py +0 -0
  93. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/integration/test_migration_breaks_and_safety.py +0 -0
  94. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/integration/test_public_api_contracts.py +0 -0
  95. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_core.py +0 -0
  96. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_mutation.py +0 -0
  97. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_numpy.py +0 -0
  98. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points/test_point_quadtree_serialization.py +0 -0
  99. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_deletion_update.py +0 -0
  100. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_numpy.py +0 -0
  101. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/points_objects/test_point_quadtree_objects_serialization.py +0 -0
  102. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_core.py +0 -0
  103. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_mutation.py +0 -0
  104. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_numpy.py +0 -0
  105. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects/test_rect_quadtree_serialization.py +0 -0
  106. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_core.py +0 -0
  107. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_deletion_update.py +0 -0
  108. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_numpy.py +0 -0
  109. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/rects_objects/test_rect_quadtree_objects_serialization.py +0 -0
  110. {fastquadtree-2.0.2 → fastquadtree-2.0.4}/tests/test_python/test_pyqtree_shim_compat.py +0 -0
  111. {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
- - run: pip install -e '.[dev]'
20
- - run: mkdocs gh-deploy --force
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: Build with maturin into this Python
35
- uses: PyO3/maturin-action@v1
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v7
36
26
  with:
37
- command: develop
38
- args: --release
39
- manylinux: manylinux2014
27
+ enable-cache: true
40
28
 
41
- - name: Install Python test deps into .venv
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: Run Python tests
47
- run: |
48
- . .venv/bin/activate
49
- pytest
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
@@ -30,7 +30,7 @@ dependencies = [
30
30
 
31
31
  [[package]]
32
32
  name = "fastquadtree"
33
- version = "2.0.2"
33
+ version = "2.0.4"
34
34
  dependencies = [
35
35
  "bincode",
36
36
  "num-traits",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fastquadtree"
3
- version = "2.0.2"
3
+ version = "2.0.4"
4
4
  edition = "2021"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastquadtree
3
- Version: 2.0.2
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
  ![Total time](https://raw.githubusercontent.com/Elan456/fastquadtree/main/assets/quadtree_bench_time.png)
114
97
  ![Throughput](https://raw.githubusercontent.com/Elan456/fastquadtree/main/assets/quadtree_bench_throughput.png)
115
98
 
116
- ### Summary (largest dataset, PyQtree baseline)
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
  ![Total time](https://raw.githubusercontent.com/Elan456/fastquadtree/main/assets/quadtree_bench_time.png)
73
73
  ![Throughput](https://raw.githubusercontent.com/Elan456/fastquadtree/main/assets/quadtree_bench_throughput.png)
74
74
 
75
- ### Summary (largest dataset, PyQtree baseline)
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, Dict, List, Optional, Tuple
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[[List[Tuple[int, int]]], Any],
34
- query_fn: Callable[[Any, List[Tuple[int, int, int, int]]], None],
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: List[Tuple[int, int]]) -> Any:
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: List[Tuple[int, int, int, int]]) -> None:
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: Tuple[int, int, int, int], max_points: int, max_depth: int
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: List[Tuple[int, int]]):
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: List[Tuple[int, int, int, int]]):
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: Tuple[int, int, int, int] = (0, 0, 1000, 1000),
322
+ bounds: tuple[int, int, int, int] = (0, 0, 1000, 1000),
323
323
  max_points: int = 20,
324
324
  max_depth: int = 10,
325
- ) -> Dict[str, Engine]:
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, Dict, Tuple
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: Dict[str, Any]):
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: Dict[str, list], col: int):
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) -> Tuple[go.Figure, go.Figure]:
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, Dict
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() -> Dict[str, Any]:
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.089 s**
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 typing import Iterable, List, Set, Tuple
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: Tuple[int, int, int] = (255, 0, 0),
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) -> Tuple[float, float, float, float]:
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: List[Ball], width: int, height: int) -> None:
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: List[Ball], width: int, height: int) -> None:
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: List[Ball]) -> Iterable[Ball]:
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: List[Ball], width: int, height: int) -> None:
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: List[Ball]):
199
+ def __init__(self, balls_ref: list[Ball]):
200
200
  self._balls = balls_ref
201
201
 
202
- def rebuild(self, balls: List[Ball], width: int, height: int) -> None:
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: List[Ball] = []
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: Set[Tuple[int, int]] = set()
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":