Skip to content

Commit 7c7a8b7

Browse files
committed
perf: lazy proxy classes for O(1) property access (SimplicesProxy, VertexToSimplicesProxy, VerticesProxy)
1 parent fc3eb74 commit 7c7a8b7

9 files changed

Lines changed: 479 additions & 83 deletions

File tree

‎.pre-commit-config.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ repos:
2020
- id: mypy
2121
additional_dependencies: [numpy]
2222
args: [--strict]
23+
exclude: '(\.pyi$|tests/)'
2324
- repo: local
2425
hooks:
2526
- id: cargo-fmt

‎IMPLEMENTATION.md‎

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -177,59 +177,59 @@ Wraps `Triangulation`. All methods exposed to Python.
177177
```python
178178
class Triangulation:
179179
def __init__(self, coords: np.ndarray) -> None: ...
180-
180+
181181
def add_point(
182182
self,
183183
point: tuple[float, ...] | np.ndarray,
184184
simplex: tuple[int, ...] | None = None,
185185
transform: np.ndarray | None = None,
186186
) -> tuple[set[tuple[int, ...]], set[tuple[int, ...]]]: ...
187-
187+
188188
@property
189189
def vertices(self) -> list[tuple[float, ...]]: ...
190-
190+
191191
@property
192192
def simplices(self) -> set[tuple[int, ...]]: ...
193-
193+
194194
@property
195195
def vertex_to_simplices(self) -> list[set[tuple[int, ...]]]: ...
196-
196+
197197
@property
198198
def hull(self) -> set[int]: ...
199-
199+
200200
@property
201201
def dim(self) -> int: ...
202-
202+
203203
def get_vertices(self, indices: tuple[int, ...]) -> list[tuple[float, ...]]: ...
204-
204+
205205
def locate_point(self, point: tuple[float, ...] | np.ndarray) -> tuple[int, ...] | None: ...
206-
206+
207207
def get_reduced_simplex(
208208
self, point: tuple[float, ...], simplex: tuple[int, ...], eps: float = 1e-8
209209
) -> tuple[int, ...]: ...
210-
210+
211211
def circumscribed_circle(
212212
self, simplex: tuple[int, ...], transform: np.ndarray | None = None
213213
) -> tuple[tuple[float, ...], float]: ...
214-
214+
215215
def point_in_circumcircle(
216216
self, pt_index: int, simplex: tuple[int, ...], transform: np.ndarray | None = None
217217
) -> bool: ...
218-
218+
219219
def volume(self, simplex: tuple[int, ...]) -> float: ...
220-
220+
221221
def faces(
222222
self, dim: int | None = None, vertices: bool = False,
223223
simplices: set[tuple[int, ...]] | None = None,
224224
) -> Iterator: ...
225-
225+
226226
def containing(self, face: tuple[int, ...]) -> set[tuple[int, ...]]: ...
227-
227+
228228
def reference_invariant(self) -> bool: ...
229-
229+
230230
@property
231231
def default_transform(self) -> np.ndarray: ...
232-
232+
233233
def point_in_simplex(self, point: tuple[float, ...], simplex: tuple[int, ...], eps: float = 1e-8) -> bool: ...
234234
```
235235

@@ -294,4 +294,4 @@ pip install maturin
294294
5. Working `maturin develop --release` build
295295
6. All tests passing
296296

297-
When complete, write results to `.claude/REPORT.md`.
297+
When complete, write results to `.claude/REPORT.md`.

‎python/adaptive_triangulation/__init__.py‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
from __future__ import annotations
2424

2525
from ._rust import (
26+
SimplicesProxy,
2627
Triangulation,
28+
VertexToSimplicesProxy,
29+
VerticesProxy,
30+
__version__,
2731
circumsphere,
2832
fast_2d_circumcircle,
2933
fast_2d_point_in_simplex,
@@ -35,12 +39,12 @@
3539
simplex_volume_in_embedding,
3640
volume,
3741
)
38-
from ._rust import (
39-
__version__ as __version__,
40-
)
4142

4243
__all__: list[str] = [
44+
"SimplicesProxy",
4345
"Triangulation",
46+
"VertexToSimplicesProxy",
47+
"VerticesProxy",
4448
"__version__",
4549
"circumsphere",
4650
"fast_2d_circumcircle",

‎python/adaptive_triangulation/__init__.pyi‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
from ._rust import (
2+
SimplicesProxy as SimplicesProxy,
3+
)
14
from ._rust import (
25
Triangulation as Triangulation,
36
)
7+
from ._rust import (
8+
VertexToSimplicesProxy as VertexToSimplicesProxy,
9+
)
10+
from ._rust import (
11+
VerticesProxy as VerticesProxy,
12+
)
413
from ._rust import (
514
__version__ as __version__,
615
)
@@ -36,7 +45,10 @@ from ._rust import (
3645
)
3746

3847
__all__: list[str] = [
48+
"SimplicesProxy",
3949
"Triangulation",
50+
"VertexToSimplicesProxy",
51+
"VerticesProxy",
4052
"__version__",
4153
"circumsphere",
4254
"fast_2d_circumcircle",

‎python/adaptive_triangulation/_rust.pyi‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,43 @@ PointsLike: TypeAlias = Sequence[Sequence[float]] | npt.ArrayLike
99
SimplexLike: TypeAlias = Sequence[int]
1010
Simplex: TypeAlias = tuple[int, ...]
1111
SimplexSet: TypeAlias = set[Simplex]
12+
CircumscribedCircle: TypeAlias = tuple[tuple[float, ...], float]
1213
TransformLike: TypeAlias = Sequence[Sequence[float]] | npt.ArrayLike
1314

1415
__version__: str
1516

17+
class SimplicesProxy:
18+
def __contains__(self, simplex: Simplex) -> bool: ...
19+
def __iter__(self) -> Iterator[Simplex]: ...
20+
def __len__(self) -> int: ...
21+
22+
class VerticesProxy:
23+
def __getitem__(self, index: int) -> tuple[float, ...]: ...
24+
def __iter__(self) -> Iterator[tuple[float, ...]]: ...
25+
def __len__(self) -> int: ...
26+
27+
class VertexToSimplicesProxy:
28+
def __getitem__(self, index: int) -> SimplexSet: ...
29+
def __iter__(self) -> Iterator[SimplexSet]: ...
30+
def __len__(self) -> int: ...
1631

1732
class Triangulation:
1833
def __init__(self, coords: PointsLike) -> None: ...
19-
2034
@property
21-
def vertices(self) -> list[tuple[float, ...]]: ...
22-
35+
def vertices(self) -> VerticesProxy: ...
2336
@property
24-
def simplices(self) -> SimplexSet: ...
25-
37+
def simplices(self) -> SimplicesProxy: ...
2638
@property
27-
def vertex_to_simplices(self) -> list[SimplexSet]: ...
28-
39+
def vertex_to_simplices(self) -> VertexToSimplicesProxy: ...
2940
@property
3041
def hull(self) -> set[int]: ...
31-
3242
@property
3343
def dim(self) -> int: ...
34-
3544
@property
3645
def default_transform(self) -> npt.NDArray[np.float64]: ...
37-
3846
def add_simplex(self, simplex: SimplexLike) -> None: ...
3947
def delete_simplex(self, simplex: SimplexLike) -> None: ...
48+
def has_simplex(self, simplex: Simplex) -> bool: ...
4049
def add_point(
4150
self,
4251
point: PointLike,
@@ -55,7 +64,7 @@ class Triangulation:
5564
self,
5665
simplex: SimplexLike,
5766
transform: TransformLike | None = None,
58-
) -> tuple[tuple[float, ...], float]: ...
67+
) -> CircumscribedCircle: ...
5968
def point_in_circumcircle(
6069
self,
6170
pt_index: int,
@@ -78,6 +87,7 @@ class Triangulation:
7887
) -> Iterator[Simplex]: ...
7988
def containing(self, face: Sequence[int]) -> SimplexSet: ...
8089
def reference_invariant(self) -> bool: ...
90+
def vertex_to_simplices_for(self, vertex: int) -> SimplicesProxy: ...
8191
def point_in_simplex(
8292
self,
8393
point: PointLike,
@@ -93,7 +103,6 @@ class Triangulation:
93103
def vertex_invariant(self, vertex: int) -> bool: ...
94104
def convex_invariant(self, vertex: int) -> bool: ...
95105

96-
97106
def circumsphere(points: PointsLike) -> tuple[tuple[float, ...], float]: ...
98107
def fast_2d_circumcircle(points: PointsLike) -> tuple[tuple[float, ...], float]: ...
99108
def fast_2d_point_in_simplex(point: PointLike, simplex: PointsLike, eps: float = 1e-8) -> bool: ...
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-

‎src/lib.rs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use pyo3::types::{PyAny, PyModule, PyTuple};
77

88
use crate::geometry as geom;
99
use crate::triangulation::{
10-
parse_point, parse_points_sized, point_tuple, PyFacesIter, PyTriangulation,
10+
parse_point, parse_points_sized, point_tuple, PyFacesIter, PySimplicesProxy, PyTriangulation,
11+
PyVertexToSimplicesIter, PyVertexToSimplicesProxy, PyVerticesIter, PyVerticesProxy,
1112
};
1213

1314
fn numpy_linalg_error(py: Python<'_>, message: &str) -> PyErr {
@@ -33,6 +34,11 @@ fn point_in_simplex_error(py: Python<'_>, err: geom::GeometryError) -> PyErr {
3334
fn _rust(m: &Bound<'_, PyModule>) -> PyResult<()> {
3435
m.add_class::<PyTriangulation>()?;
3536
m.add_class::<PyFacesIter>()?;
37+
m.add_class::<PySimplicesProxy>()?;
38+
m.add_class::<PyVerticesProxy>()?;
39+
m.add_class::<PyVertexToSimplicesProxy>()?;
40+
m.add_class::<PyVerticesIter>()?;
41+
m.add_class::<PyVertexToSimplicesIter>()?;
3642
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
3743

3844
m.add_function(wrap_pyfunction!(py_circumsphere, m)?)?;

0 commit comments

Comments
 (0)