vineyards 1.0.0__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.
- vineyards-1.0.0/CHANGELOG.md +42 -0
- vineyards-1.0.0/CITATION.cff +22 -0
- vineyards-1.0.0/LICENSE +21 -0
- vineyards-1.0.0/MANIFEST.in +16 -0
- vineyards-1.0.0/PKG-INFO +293 -0
- vineyards-1.0.0/README.md +243 -0
- vineyards-1.0.0/cpp/exact_poly.cpp +425 -0
- vineyards-1.0.0/cpp/kinetic_arith.hpp +300 -0
- vineyards-1.0.0/cpp/kinetic_delaunay_2d.cpp +478 -0
- vineyards-1.0.0/cpp/kinetic_delaunay_3d.cpp +618 -0
- vineyards-1.0.0/cpp/sparse_ru.cpp +552 -0
- vineyards-1.0.0/docs/Makefile +12 -0
- vineyards-1.0.0/docs/api.rst +89 -0
- vineyards-1.0.0/docs/conf.py +48 -0
- vineyards-1.0.0/docs/cpp_kernels.rst +30 -0
- vineyards-1.0.0/docs/engines.rst +48 -0
- vineyards-1.0.0/docs/index.rst +44 -0
- vineyards-1.0.0/docs/install.rst +38 -0
- vineyards-1.0.0/pyproject.toml +110 -0
- vineyards-1.0.0/scripts/smoke_readme.py +106 -0
- vineyards-1.0.0/scripts/wheel_smoke.py +52 -0
- vineyards-1.0.0/setup.cfg +4 -0
- vineyards-1.0.0/setup.py +102 -0
- vineyards-1.0.0/tests/test_3d.py +600 -0
- vineyards-1.0.0/tests/test_backend_equiv.py +292 -0
- vineyards-1.0.0/tests/test_comparison.py +104 -0
- vineyards-1.0.0/tests/test_counters.py +82 -0
- vineyards-1.0.0/tests/test_cpp_exact_poly.py +129 -0
- vineyards-1.0.0/tests/test_d1_validation.py +690 -0
- vineyards-1.0.0/tests/test_dionysus_comparison.py +334 -0
- vineyards-1.0.0/tests/test_feature_tracking.py +115 -0
- vineyards-1.0.0/tests/test_frame_vs_kinetic.py +79 -0
- vineyards-1.0.0/tests/test_hollow_triangle.py +150 -0
- vineyards-1.0.0/tests/test_kinetic_cpp_2d.py +106 -0
- vineyards-1.0.0/tests/test_kinetic_cpp_3d.py +127 -0
- vineyards-1.0.0/tests/test_kinetic_delaunay.py +285 -0
- vineyards-1.0.0/tests/test_kinetic_delaunay_3d.py +202 -0
- vineyards-1.0.0/tests/test_kinetic_exact.py +140 -0
- vineyards-1.0.0/tests/test_kinetic_exact_degeneracies.py +105 -0
- vineyards-1.0.0/tests/test_kinetic_filtration.py +62 -0
- vineyards-1.0.0/tests/test_kinetic_filtration_3d.py +64 -0
- vineyards-1.0.0/tests/test_kinetic_filtration_dynamic.py +60 -0
- vineyards-1.0.0/tests/test_kinetic_predicates.py +151 -0
- vineyards-1.0.0/tests/test_kinetic_vineyard.py +262 -0
- vineyards-1.0.0/tests/test_kinetic_vineyard_3d.py +131 -0
- vineyards-1.0.0/tests/test_knee_times.py +94 -0
- vineyards-1.0.0/tests/test_local_ops.py +237 -0
- vineyards-1.0.0/tests/test_moving_vineyard.py +778 -0
- vineyards-1.0.0/tests/test_oracle.py +157 -0
- vineyards-1.0.0/tests/test_persistence.py +203 -0
- vineyards-1.0.0/tests/test_polar_plotting.py +288 -0
- vineyards-1.0.0/tests/test_retriangulation.py +418 -0
- vineyards-1.0.0/tests/test_sos.py +325 -0
- vineyards-1.0.0/tests/test_transposition.py +374 -0
- vineyards-1.0.0/tests/test_vineyard.py +904 -0
- vineyards-1.0.0/vineyards/__init__.py +149 -0
- vineyards-1.0.0/vineyards/_exact_poly.pyi +31 -0
- vineyards-1.0.0/vineyards/_kinetic_2d.pyi +23 -0
- vineyards-1.0.0/vineyards/_kinetic_3d.pyi +23 -0
- vineyards-1.0.0/vineyards/_sparse.pyi +26 -0
- vineyards-1.0.0/vineyards/alpha_values.py +154 -0
- vineyards-1.0.0/vineyards/backend.py +223 -0
- vineyards-1.0.0/vineyards/comparison.py +194 -0
- vineyards-1.0.0/vineyards/counters.py +379 -0
- vineyards-1.0.0/vineyards/cpp_backend.py +272 -0
- vineyards-1.0.0/vineyards/dionysus_bridge.py +306 -0
- vineyards-1.0.0/vineyards/feature_tracking.py +248 -0
- vineyards-1.0.0/vineyards/kinetic_delaunay.py +632 -0
- vineyards-1.0.0/vineyards/kinetic_delaunay_3d.py +620 -0
- vineyards-1.0.0/vineyards/kinetic_exact.py +708 -0
- vineyards-1.0.0/vineyards/kinetic_filtration.py +466 -0
- vineyards-1.0.0/vineyards/kinetic_vineyard.py +343 -0
- vineyards-1.0.0/vineyards/kinetic_vineyard_3d.py +136 -0
- vineyards-1.0.0/vineyards/oracle.py +153 -0
- vineyards-1.0.0/vineyards/persistence.py +972 -0
- vineyards-1.0.0/vineyards/plotting.py +257 -0
- vineyards-1.0.0/vineyards/polar_plotting.py +562 -0
- vineyards-1.0.0/vineyards/predicates.py +188 -0
- vineyards-1.0.0/vineyards/py.typed +0 -0
- vineyards-1.0.0/vineyards/regular.py +80 -0
- vineyards-1.0.0/vineyards/retriangulation.py +525 -0
- vineyards-1.0.0/vineyards/sos.py +197 -0
- vineyards-1.0.0/vineyards/transposition.py +362 -0
- vineyards-1.0.0/vineyards/vineyard.py +812 -0
- vineyards-1.0.0/vineyards.egg-info/PKG-INFO +293 -0
- vineyards-1.0.0/vineyards.egg-info/SOURCES.txt +87 -0
- vineyards-1.0.0/vineyards.egg-info/dependency_links.txt +1 -0
- vineyards-1.0.0/vineyards.egg-info/requires.txt +25 -0
- vineyards-1.0.0/vineyards.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the installable ``vineyards`` package are recorded here.
|
|
4
|
+
The GitHub Releases page mirrors tagged versions.
|
|
5
|
+
|
|
6
|
+
## [1.0.0] - 2026-07-17
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- Event-driven kinetic Delaunay / vineyard engines in 2D and 3D (exact algebraic
|
|
10
|
+
flip and transposition times; INF hull; SoS on space and on time).
|
|
11
|
+
- Optional GMP C++ kernels: ``_exact_poly``, ``_kinetic_2d``, ``_kinetic_3d``
|
|
12
|
+
(bit-exact flip sequences vs pure Python when built).
|
|
13
|
+
- Sparse GF(2) R=DU C++ kernel ``_sparse`` with local insert/delete and
|
|
14
|
+
bubble paths, differential-tested against dense numpy.
|
|
15
|
+
- Certificate poly caches and binary float-key event heaps in kinetic C++.
|
|
16
|
+
- Shared arithmetic header ``cpp/kinetic_arith.hpp``.
|
|
17
|
+
- Oracle snap (``recover`` flip) for residual multi-cospheric 3D instants that
|
|
18
|
+
local bistellar flips cannot order; vineyard construction fails only if the
|
|
19
|
+
snap itself fails.
|
|
20
|
+
- Type stubs (``.pyi``), ``py.typed``, Sphinx docs, Read the Docs and GitHub
|
|
21
|
+
Pages configs, cibuildwheel publish workflow.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Production default R=DU backend is sparse C++ when built
|
|
25
|
+
(``default_backend_cls()``). Dense remains the bit-exact algebra oracle.
|
|
26
|
+
Override with ``VINEYARDS_BACKEND=dense|sparse``.
|
|
27
|
+
- Kinetic ``run()`` prefers C++ when built; override with
|
|
28
|
+
``VINEYARDS_KINETIC_CPP=0``.
|
|
29
|
+
|
|
30
|
+
### Notes
|
|
31
|
+
- Exact kinetic arithmetic favors tens to low hundreds of points; use
|
|
32
|
+
``track_features`` or frame-bound ``moving_vineyard`` at larger scale.
|
|
33
|
+
- Binary wheels bundle GMP where present (LGPL for that component); MIT for
|
|
34
|
+
this project's own code.
|
|
35
|
+
- cibuildwheel smoke (``scripts/wheel_smoke.py``) imports all four C++ kernels
|
|
36
|
+
on Linux/macOS so GMP bundling failures cannot ship silently; Windows
|
|
37
|
+
requires sparse only.
|
|
38
|
+
- GMP kernels link ``libgmpxx.a`` / ``libgmp.a`` when present (static) so
|
|
39
|
+
delocate/auditwheel do not need to vendor Homebrew or manylinux libgmp
|
|
40
|
+
dylibs (fixes first-release wheel matrix failures).
|
|
41
|
+
- Linux wheels build on **manylinux_2_28** so runtime dependency ``gudhi``
|
|
42
|
+
(manylinux_2_28 wheels only) can install during cibuildwheel's test step.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
title: "Vineyards over changing triangulations"
|
|
3
|
+
message: "If you use this software, please cite it using these metadata."
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- given-names: Shawn
|
|
7
|
+
family-names: Ray
|
|
8
|
+
repository-code: "https://github.com/codingwithshawnyt/vineyards"
|
|
9
|
+
abstract: >-
|
|
10
|
+
Exact persistent-homology vineyards for moving 2D and 3D point sets whose
|
|
11
|
+
Delaunay / alpha complex changes by flips: vine identity is carried through
|
|
12
|
+
the flips from the maintained persistence pairing, with no diagram-matching
|
|
13
|
+
heuristic. Includes frame-bound and event-driven (kinetic) engines, a weighted
|
|
14
|
+
(regular / Laguerre) alpha path for points carrying radii.
|
|
15
|
+
keywords:
|
|
16
|
+
- topological data analysis
|
|
17
|
+
- persistent homology
|
|
18
|
+
- vineyards
|
|
19
|
+
- Delaunay triangulation
|
|
20
|
+
- kinetic data structures
|
|
21
|
+
license: MIT
|
|
22
|
+
version: 1.0.0
|
vineyards-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shawn Ray
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include CITATION.cff
|
|
5
|
+
include pyproject.toml
|
|
6
|
+
include setup.py
|
|
7
|
+
recursive-include cpp *.cpp *.hpp *.h
|
|
8
|
+
recursive-include vineyards *.py *.pyi
|
|
9
|
+
recursive-include docs *.rst *.py Makefile
|
|
10
|
+
recursive-include scripts *.py
|
|
11
|
+
graft vineyards
|
|
12
|
+
global-exclude *.pyc
|
|
13
|
+
global-exclude __pycache__
|
|
14
|
+
global-exclude *.so
|
|
15
|
+
global-exclude *.dylib
|
|
16
|
+
prune docs/_build
|
vineyards-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vineyards
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Vineyards over changing triangulations: exact vine tracking for moving 2D and 3D point sets through Delaunay flips (frame-bound and event-driven).
|
|
5
|
+
Author-email: Shawn Ray <shawnray5699@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/codingwithshawnyt/vineyards
|
|
8
|
+
Project-URL: Repository, https://github.com/codingwithshawnyt/vineyards
|
|
9
|
+
Project-URL: Issues, https://github.com/codingwithshawnyt/vineyards/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/codingwithshawnyt/vineyards/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: topological-data-analysis,persistent-homology,vineyards,Delaunay,kinetic-data-structures,computational-topology
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Classifier: Programming Language :: C++
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: numpy>=1.24
|
|
30
|
+
Requires-Dist: gudhi>=3.6
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
33
|
+
Requires-Dist: matplotlib>=3.7; extra == "test"
|
|
34
|
+
Requires-Dist: pillow>=9.0; extra == "test"
|
|
35
|
+
Requires-Dist: pybind11>=2.10; extra == "test"
|
|
36
|
+
Requires-Dist: setuptools>=61.0; extra == "test"
|
|
37
|
+
Provides-Extra: dionysus
|
|
38
|
+
Requires-Dist: dionysus>=2.2; extra == "dionysus"
|
|
39
|
+
Provides-Extra: plot
|
|
40
|
+
Requires-Dist: matplotlib>=3.7; extra == "plot"
|
|
41
|
+
Requires-Dist: pillow>=9.0; extra == "plot"
|
|
42
|
+
Provides-Extra: viz
|
|
43
|
+
Requires-Dist: matplotlib>=3.7; extra == "viz"
|
|
44
|
+
Requires-Dist: pillow>=9.0; extra == "viz"
|
|
45
|
+
Requires-Dist: pyvista>=0.44; extra == "viz"
|
|
46
|
+
Provides-Extra: docs
|
|
47
|
+
Requires-Dist: sphinx>=7.0; extra == "docs"
|
|
48
|
+
Requires-Dist: sphinx-rtd-theme>=2.0; extra == "docs"
|
|
49
|
+
Dynamic: license-file
|
|
50
|
+
|
|
51
|
+
# Vineyards over changing triangulations
|
|
52
|
+
|
|
53
|
+
A vineyard (Cohen-Steiner, Edelsbrunner, Morozov, SoCG 2006) is the 1-parameter
|
|
54
|
+
family of persistence diagrams of a changing filtration: each diagram point
|
|
55
|
+
traces a vine through time. CEM06 updates the decomposition `D = R·U` in linear
|
|
56
|
+
time per transposition when the complex is fixed and only filtration values
|
|
57
|
+
move. This library closes the remaining case: moving 2D/3D point sets whose
|
|
58
|
+
Delaunay/alpha complex changes by flips. Flips are handled by simplex
|
|
59
|
+
delete/insert on the CEM06 transposition kernel, and vine identity is carried
|
|
60
|
+
through those updates from the maintained pairing (no diagram-point matching).
|
|
61
|
+
|
|
62
|
+
Two engines share that handoff. `moving_vineyard` is frame-bound (sample motion,
|
|
63
|
+
diff consecutive complexes). `KineticVineyard2D` / `KineticVineyard3D` are
|
|
64
|
+
event-driven: linear trajectories, flips and alpha-value crossings at exact
|
|
65
|
+
algebraic times. For hundreds to thousands of points, `track_features` matches
|
|
66
|
+
prominent GUDHI diagram points across frames. Weighted (regular/Laguerre) alpha
|
|
67
|
+
accepts `weights=` (squared radii); use `assert_no_hidden` when a point can drop
|
|
68
|
+
out of the regular triangulation.
|
|
69
|
+
|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
## Install
|
|
73
|
+
|
|
74
|
+
From PyPI (recommended):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install vineyards
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
That pulls `numpy` and `gudhi`. A C++17 compiler is required to build the sparse
|
|
81
|
+
GF(2) kernel at install time. For the optional GMP exact-arithmetic kernel:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Debian/Ubuntu
|
|
85
|
+
sudo apt install build-essential libgmp-dev python3-dev
|
|
86
|
+
|
|
87
|
+
# macOS (Homebrew)
|
|
88
|
+
brew install gmp
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
From a clone (development):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python3 -m venv .venv
|
|
95
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
96
|
+
pip install -U pip setuptools wheel pybind11
|
|
97
|
+
pip install -e '.[test]'
|
|
98
|
+
python setup.py build_ext --inplace # _sparse; with GMP also _exact_poly, _kinetic_2d, _kinetic_3d
|
|
99
|
+
pytest -q -m "not slow"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Extras: `pip install 'vineyards[plot]'` (matplotlib) or `'vineyards[viz]'`
|
|
103
|
+
(matplotlib + pyvista). Plotting imports those only when called. Dionysus
|
|
104
|
+
cross-checks: `pip install 'vineyards[dionysus]'`. Documentation:
|
|
105
|
+
`pip install 'vineyards[docs]'` then `cd docs && make html` (also built on
|
|
106
|
+
GitHub Pages / Read the Docs). Override the GMP prefix with `GMP_PREFIX` if
|
|
107
|
+
needed (Homebrew defaults to `/opt/homebrew` or `/usr/local`).
|
|
108
|
+
|
|
109
|
+
Environment toggles:
|
|
110
|
+
|
|
111
|
+
| Variable | Effect |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `VINEYARDS_BACKEND=dense` | Force dense numpy R=DU (default: sparse C++ when built) |
|
|
114
|
+
| `VINEYARDS_BACKEND=sparse` | Require sparse C++ (error if extension missing) |
|
|
115
|
+
| `VINEYARDS_KINETIC_CPP=0` | Force pure-Python kinetic Delaunay (default: C++ when built) |
|
|
116
|
+
|
|
117
|
+
## Quickstart
|
|
118
|
+
|
|
119
|
+
Frame-bound vineyard on a moving point set:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import numpy as np
|
|
123
|
+
from vineyards import (
|
|
124
|
+
PersistenceState, gudhi_alpha_filtration,
|
|
125
|
+
moving_vineyard, compute_vineyard, plot_vineyard,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
points = np.random.default_rng(0).random((20, 2))
|
|
129
|
+
state = PersistenceState.from_simplex_tree(gudhi_alpha_filtration(points))
|
|
130
|
+
diagram = state.diagram() # rows (dim, birth, death)
|
|
131
|
+
|
|
132
|
+
target = {sigma: 2.0 * v for sigma, v in state.filtration}
|
|
133
|
+
vineyard, events = compute_vineyard(state, target, num_samples=50)
|
|
134
|
+
|
|
135
|
+
frames = [points + 0.02 * k for k in range(10)]
|
|
136
|
+
vineyard, events = moving_vineyard(frames)
|
|
137
|
+
plot_vineyard(vineyard, filename="vineyard.png")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Event-driven (kinetic) vineyard:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from fractions import Fraction
|
|
144
|
+
import numpy as np
|
|
145
|
+
from vineyards import LinearTrajectory, KineticVineyard2D # or KineticVineyard3D
|
|
146
|
+
|
|
147
|
+
pts = np.random.default_rng(0).random((10, 2))
|
|
148
|
+
vel = 0.3 * np.random.default_rng(1).standard_normal((10, 2))
|
|
149
|
+
traj = LinearTrajectory(pos0=pts, vel=vel)
|
|
150
|
+
kv = KineticVineyard2D(traj, horizon=Fraction(1, 4))
|
|
151
|
+
dgm = kv.diagram_at(Fraction(1, 6))
|
|
152
|
+
kv.record(Fraction(1, 4))
|
|
153
|
+
assert kv.verify_identity()
|
|
154
|
+
vineyard = kv.vineyard()
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Lower-star filtrations on a fixed complex use
|
|
158
|
+
`lower_star_filtration(simplices, vertex_values)`. The default R=DU backend is
|
|
159
|
+
the sparse C++ kernel when built (`CppSparseBackend`); force dense with
|
|
160
|
+
`VINEYARDS_BACKEND=dense` or `backend_cls=DenseBackend`.
|
|
161
|
+
|
|
162
|
+
## Positioning
|
|
163
|
+
|
|
164
|
+
[Dionysus 2](https://www.mrzv.org/software/dionysus2/) (≥ 2.2) implements CEM06
|
|
165
|
+
vineyards on a fixed complex; Dionysus 1 is the earlier public vineyards code.
|
|
166
|
+
[GUDHI](https://gudhi.inria.fr/) supplies alpha/Delaunay geometry and the
|
|
167
|
+
independent diagram oracle used throughout this repository. Fixed-complex
|
|
168
|
+
homotopies are checked against Dionysus when installed
|
|
169
|
+
(`tests/test_dionysus_comparison.py`); changing triangulations are outside
|
|
170
|
+
Dionysus and are the scope of `moving_vineyard` and the kinetic engines.
|
|
171
|
+
|
|
172
|
+
## Validation
|
|
173
|
+
|
|
174
|
+
Claims below name the tests that assert them (run with `pytest`):
|
|
175
|
+
|
|
176
|
+
| Claim | Tests |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| Diagrams match GUDHI after retriangulation / moving frames | `tests/test_retriangulation.py`, `tests/test_moving_vineyard.py`, `tests/test_3d.py` |
|
|
179
|
+
| Algebraic invariants (`D = R·U`, reduced `R`, unitriangular `U`) | `PersistenceState.verify` exercised across the suite (e.g. `tests/test_persistence.py`, `tests/test_local_ops.py`) |
|
|
180
|
+
| Vine identity vs reduced pairing | `tests/test_vineyard.py`, `tests/test_moving_vineyard.py` (`test_vine_identity_through_switches`) |
|
|
181
|
+
| Kinetic Delaunay vs GUDHI (2D / 3D) | `tests/test_kinetic_delaunay.py`, `tests/test_kinetic_delaunay_3d.py` |
|
|
182
|
+
| Kinetic filtration order vs GUDHI | `tests/test_kinetic_filtration.py`, `tests/test_kinetic_filtration_3d.py`, `tests/test_kinetic_filtration_dynamic.py` |
|
|
183
|
+
| Kinetic vineyard diagrams + vine identity vs GUDHI | `tests/test_kinetic_vineyard.py`, `tests/test_kinetic_vineyard_3d.py` |
|
|
184
|
+
| Dense vs sparse backend (`R`/`U`/`low` and diagrams) | `tests/test_backend_equiv.py` |
|
|
185
|
+
| Python vs C++ exact poly / Sturm | `tests/test_cpp_exact_poly.py` |
|
|
186
|
+
| SoS signs vs shrinking-ε and raw determinants | `tests/test_sos.py` |
|
|
187
|
+
| Weighted alpha vs weighted GUDHI | `tests/test_3d.py` (weighted cases) |
|
|
188
|
+
| Weighted flip continuity (bracketing) | `tests/test_3d.py::test_weighted_flip_continuity_lemma` |
|
|
189
|
+
| Multi-flip-at-one-τ kinetic vineyard | `tests/test_kinetic_vineyard.py::test_kinetic_vineyard_through_coincident_flip_cluster` |
|
|
190
|
+
| Frame-bound vs kinetic cancellation | `tests/test_frame_vs_kinetic.py` |
|
|
191
|
+
| Sparse bubble insert/delete vs dense | `tests/test_backend_equiv.py::test_sparse_bubble_path_matches_dense` |
|
|
192
|
+
|
|
193
|
+
## Scope and limitations
|
|
194
|
+
|
|
195
|
+
- Frame-bound engine: exact on the piecewise-linear interpolation of the
|
|
196
|
+
samples; events that cancel inside one frame interval are invisible (the
|
|
197
|
+
kinetic engine is the remedy; see `tests/test_frame_vs_kinetic.py`).
|
|
198
|
+
- Kinetic engine: exact event times, 2D and 3D (interior flips and hull
|
|
199
|
+
changes via vertex-at-infinity). With GMP, `run()` uses the C++ kernels
|
|
200
|
+
(`vineyards._kinetic_2d` / `vineyards._kinetic_3d`) with integer-coefficient
|
|
201
|
+
certificates (scale-cleared trajectories), bit-exact on flip sequences
|
|
202
|
+
(`tests/test_kinetic_cpp_2d.py`, `tests/test_kinetic_cpp_3d.py`); set
|
|
203
|
+
`VINEYARDS_KINETIC_CPP=0` for pure Python. The C++ event queue uses tight
|
|
204
|
+
root isolation and float-first extract-min (exact AlgT only on near-ties).
|
|
205
|
+
Exact arithmetic still favors tens-low hundreds of points for long horizons;
|
|
206
|
+
use `track_features` or frame-bound at scale.
|
|
207
|
+
- Degeneracies: geometric predicates use Edelsbrunner-Mücke Simulation of
|
|
208
|
+
Simplicity; coincident flip certificates (interior InCircle/InSphere and
|
|
209
|
+
hull/spoke orientation vs infinity) are resolved by SoS on time. Hull
|
|
210
|
+
legality is the geometric supporting-line / extreme-vertex test (raw
|
|
211
|
+
orientation so collinear hull points stay on the line). Several flips at
|
|
212
|
+
one algebraic time are batched in the kinetic vineyard. A residual that
|
|
213
|
+
local flips cannot order is finished by an oracle snap of the Delaunay
|
|
214
|
+
complex (recorded as a ``recover`` flip); only an unsuccessful snap raises
|
|
215
|
+
at vineyard construction.
|
|
216
|
+
- Weighted alpha: non-hiding is required (`assert_no_hidden`); the weighted
|
|
217
|
+
flip-continuity handoff is confirmed numerically against weighted GUDHI
|
|
218
|
+
in `tests/test_3d.py`.
|
|
219
|
+
- Geometry for frame-bound alpha values is GUDHI's; the kinetic path has its
|
|
220
|
+
own exact predicates. **Default R=DU backend is sparse C++** when
|
|
221
|
+
`vineyards._sparse` is built (`default_backend_cls()` /
|
|
222
|
+
`CppSparseBackend`); dense numpy remains the bit-exact reference oracle
|
|
223
|
+
(`VINEYARDS_BACKEND=dense` or `backend_cls=DenseBackend`). Install builds
|
|
224
|
+
the sparse kernel when a C++17 toolchain is available. GMP enables the
|
|
225
|
+
exact-poly and kinetic-2D/3D kernels (shared arithmetic in
|
|
226
|
+
`cpp/kinetic_arith.hpp`; binary float-key event heaps; certificate poly
|
|
227
|
+
caches; optional if GMP headers are missing; CI on Linux asserts all four
|
|
228
|
+
modules import). Type stubs (`.pyi`) ship for the C extensions. Docs:
|
|
229
|
+
`docs/` (Sphinx; GitHub Pages + Read the Docs configs). Releases publish
|
|
230
|
+
**sdists and platform wheels** via cibuildwheel.
|
|
231
|
+
- CI: Linux (Ubuntu) is the primary surface. Windows builds the sparse kernel
|
|
232
|
+
and runs core tests (GMP exact-poly / kinetic-2D/3D are skipped when GMP is
|
|
233
|
+
absent).
|
|
234
|
+
|
|
235
|
+
## Measured sparse speedups
|
|
236
|
+
|
|
237
|
+
From `python examples/benchmark_sparse.py` on this machine after
|
|
238
|
+
`python setup.py build_ext --inplace` (Apple M4 Max, macOS 15, arm64, Python
|
|
239
|
+
3.13). Columns are dense vs C++ sparse wall time and the ratio dense/sparse;
|
|
240
|
+
`nnzR/m^2` and `nnzU/m^2` are filled fractions of the reduced matrices.
|
|
241
|
+
|
|
242
|
+
| n | m | nnzR/m^2 | nnzU/m^2 | reduce | update | local |
|
|
243
|
+
|----:|----:|---------:|---------:|-------:|-------:|------:|
|
|
244
|
+
| 40 | 217 | 0.006 | 0.012 | 7.1x | 123.1x | 16.4x |
|
|
245
|
+
| 70 | 393 | 0.004 | 0.007 | 8.0x | 200.6x | 15.6x |
|
|
246
|
+
| 100 | 575 | 0.003 | 0.005 | 10.3x | 211.9x | 19.0x |
|
|
247
|
+
|
|
248
|
+
Re-run the script on your hardware; numbers vary with CPU and size.
|
|
249
|
+
|
|
250
|
+
## Knee rates
|
|
251
|
+
|
|
252
|
+
Pairing-switch share of value-update transpositions under random-walk motion
|
|
253
|
+
(`update%` in the script). From `python examples/counter_report.py` on the same
|
|
254
|
+
machine (Apple M4 Max, macOS 15, arm64):
|
|
255
|
+
|
|
256
|
+
| n | m | knee/switch % | crossings/flip | changed/flip | flip frames |
|
|
257
|
+
|----:|-----:|------:|-------:|------:|----:|
|
|
258
|
+
| 8 | 33 | 9.42% | 19.8 | 9.6 | 82 |
|
|
259
|
+
| 30 | 159 | 3.16% | 549.4 | 91.0 | 45 |
|
|
260
|
+
| 100 | 572 | 1.21% | 5747.7 | 540.2 | 16 |
|
|
261
|
+
| 300 | 1767 | 0.52% | 27006.2 | 2181.6 | 5 |
|
|
262
|
+
|
|
263
|
+
## References
|
|
264
|
+
|
|
265
|
+
- D. Cohen-Steiner, H. Edelsbrunner, D. Morozov. Vines and Vineyards by
|
|
266
|
+
Updating Persistence in Linear Time. In Proc. 22nd Annu. Symp. Comput.
|
|
267
|
+
Geom. (SoCG), pp. 119-126, 2006.
|
|
268
|
+
- H. Edelsbrunner, D. Letscher, A. Zomorodian. Topological Persistence and
|
|
269
|
+
Simplification. Discrete Comput. Geom. 28:511-533, 2002.
|
|
270
|
+
- H. Edelsbrunner, J. Harer. Computational Topology: An Introduction. AMS,
|
|
271
|
+
2010.
|
|
272
|
+
- H. Edelsbrunner, E. P. Mücke. Simulation of Simplicity: A Technique to Cope
|
|
273
|
+
with Degenerate Cases in Geometric Algorithms. ACM Trans. Graph. 9(1):66-104,
|
|
274
|
+
1990.
|
|
275
|
+
- The GUDHI Project. GUDHI User and Reference Manual.
|
|
276
|
+
https://gudhi.inria.fr/doc/latest/
|
|
277
|
+
- D. Morozov. Dionysus 2. https://www.mrzv.org/software/dionysus2/
|
|
278
|
+
|
|
279
|
+
## Citation
|
|
280
|
+
|
|
281
|
+
```bibtex
|
|
282
|
+
@software{ray_vineyards,
|
|
283
|
+
author = {Ray, Shawn},
|
|
284
|
+
title = {Vineyards over changing triangulations},
|
|
285
|
+
url = {https://github.com/codingwithshawnyt/vineyards},
|
|
286
|
+
year = {2026}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
See also `CITATION.cff`.
|
|
291
|
+
|
|
292
|
+
Research code from a summer internship at ISTA (group of Herbert Edelsbrunner),
|
|
293
|
+
2026.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Vineyards over changing triangulations
|
|
2
|
+
|
|
3
|
+
A vineyard (Cohen-Steiner, Edelsbrunner, Morozov, SoCG 2006) is the 1-parameter
|
|
4
|
+
family of persistence diagrams of a changing filtration: each diagram point
|
|
5
|
+
traces a vine through time. CEM06 updates the decomposition `D = R·U` in linear
|
|
6
|
+
time per transposition when the complex is fixed and only filtration values
|
|
7
|
+
move. This library closes the remaining case: moving 2D/3D point sets whose
|
|
8
|
+
Delaunay/alpha complex changes by flips. Flips are handled by simplex
|
|
9
|
+
delete/insert on the CEM06 transposition kernel, and vine identity is carried
|
|
10
|
+
through those updates from the maintained pairing (no diagram-point matching).
|
|
11
|
+
|
|
12
|
+
Two engines share that handoff. `moving_vineyard` is frame-bound (sample motion,
|
|
13
|
+
diff consecutive complexes). `KineticVineyard2D` / `KineticVineyard3D` are
|
|
14
|
+
event-driven: linear trajectories, flips and alpha-value crossings at exact
|
|
15
|
+
algebraic times. For hundreds to thousands of points, `track_features` matches
|
|
16
|
+
prominent GUDHI diagram points across frames. Weighted (regular/Laguerre) alpha
|
|
17
|
+
accepts `weights=` (squared radii); use `assert_no_hidden` when a point can drop
|
|
18
|
+
out of the regular triangulation.
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
From PyPI (recommended):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install vineyards
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That pulls `numpy` and `gudhi`. A C++17 compiler is required to build the sparse
|
|
31
|
+
GF(2) kernel at install time. For the optional GMP exact-arithmetic kernel:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Debian/Ubuntu
|
|
35
|
+
sudo apt install build-essential libgmp-dev python3-dev
|
|
36
|
+
|
|
37
|
+
# macOS (Homebrew)
|
|
38
|
+
brew install gmp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
From a clone (development):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
python3 -m venv .venv
|
|
45
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
46
|
+
pip install -U pip setuptools wheel pybind11
|
|
47
|
+
pip install -e '.[test]'
|
|
48
|
+
python setup.py build_ext --inplace # _sparse; with GMP also _exact_poly, _kinetic_2d, _kinetic_3d
|
|
49
|
+
pytest -q -m "not slow"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Extras: `pip install 'vineyards[plot]'` (matplotlib) or `'vineyards[viz]'`
|
|
53
|
+
(matplotlib + pyvista). Plotting imports those only when called. Dionysus
|
|
54
|
+
cross-checks: `pip install 'vineyards[dionysus]'`. Documentation:
|
|
55
|
+
`pip install 'vineyards[docs]'` then `cd docs && make html` (also built on
|
|
56
|
+
GitHub Pages / Read the Docs). Override the GMP prefix with `GMP_PREFIX` if
|
|
57
|
+
needed (Homebrew defaults to `/opt/homebrew` or `/usr/local`).
|
|
58
|
+
|
|
59
|
+
Environment toggles:
|
|
60
|
+
|
|
61
|
+
| Variable | Effect |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `VINEYARDS_BACKEND=dense` | Force dense numpy R=DU (default: sparse C++ when built) |
|
|
64
|
+
| `VINEYARDS_BACKEND=sparse` | Require sparse C++ (error if extension missing) |
|
|
65
|
+
| `VINEYARDS_KINETIC_CPP=0` | Force pure-Python kinetic Delaunay (default: C++ when built) |
|
|
66
|
+
|
|
67
|
+
## Quickstart
|
|
68
|
+
|
|
69
|
+
Frame-bound vineyard on a moving point set:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import numpy as np
|
|
73
|
+
from vineyards import (
|
|
74
|
+
PersistenceState, gudhi_alpha_filtration,
|
|
75
|
+
moving_vineyard, compute_vineyard, plot_vineyard,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
points = np.random.default_rng(0).random((20, 2))
|
|
79
|
+
state = PersistenceState.from_simplex_tree(gudhi_alpha_filtration(points))
|
|
80
|
+
diagram = state.diagram() # rows (dim, birth, death)
|
|
81
|
+
|
|
82
|
+
target = {sigma: 2.0 * v for sigma, v in state.filtration}
|
|
83
|
+
vineyard, events = compute_vineyard(state, target, num_samples=50)
|
|
84
|
+
|
|
85
|
+
frames = [points + 0.02 * k for k in range(10)]
|
|
86
|
+
vineyard, events = moving_vineyard(frames)
|
|
87
|
+
plot_vineyard(vineyard, filename="vineyard.png")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Event-driven (kinetic) vineyard:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from fractions import Fraction
|
|
94
|
+
import numpy as np
|
|
95
|
+
from vineyards import LinearTrajectory, KineticVineyard2D # or KineticVineyard3D
|
|
96
|
+
|
|
97
|
+
pts = np.random.default_rng(0).random((10, 2))
|
|
98
|
+
vel = 0.3 * np.random.default_rng(1).standard_normal((10, 2))
|
|
99
|
+
traj = LinearTrajectory(pos0=pts, vel=vel)
|
|
100
|
+
kv = KineticVineyard2D(traj, horizon=Fraction(1, 4))
|
|
101
|
+
dgm = kv.diagram_at(Fraction(1, 6))
|
|
102
|
+
kv.record(Fraction(1, 4))
|
|
103
|
+
assert kv.verify_identity()
|
|
104
|
+
vineyard = kv.vineyard()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Lower-star filtrations on a fixed complex use
|
|
108
|
+
`lower_star_filtration(simplices, vertex_values)`. The default R=DU backend is
|
|
109
|
+
the sparse C++ kernel when built (`CppSparseBackend`); force dense with
|
|
110
|
+
`VINEYARDS_BACKEND=dense` or `backend_cls=DenseBackend`.
|
|
111
|
+
|
|
112
|
+
## Positioning
|
|
113
|
+
|
|
114
|
+
[Dionysus 2](https://www.mrzv.org/software/dionysus2/) (≥ 2.2) implements CEM06
|
|
115
|
+
vineyards on a fixed complex; Dionysus 1 is the earlier public vineyards code.
|
|
116
|
+
[GUDHI](https://gudhi.inria.fr/) supplies alpha/Delaunay geometry and the
|
|
117
|
+
independent diagram oracle used throughout this repository. Fixed-complex
|
|
118
|
+
homotopies are checked against Dionysus when installed
|
|
119
|
+
(`tests/test_dionysus_comparison.py`); changing triangulations are outside
|
|
120
|
+
Dionysus and are the scope of `moving_vineyard` and the kinetic engines.
|
|
121
|
+
|
|
122
|
+
## Validation
|
|
123
|
+
|
|
124
|
+
Claims below name the tests that assert them (run with `pytest`):
|
|
125
|
+
|
|
126
|
+
| Claim | Tests |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| Diagrams match GUDHI after retriangulation / moving frames | `tests/test_retriangulation.py`, `tests/test_moving_vineyard.py`, `tests/test_3d.py` |
|
|
129
|
+
| Algebraic invariants (`D = R·U`, reduced `R`, unitriangular `U`) | `PersistenceState.verify` exercised across the suite (e.g. `tests/test_persistence.py`, `tests/test_local_ops.py`) |
|
|
130
|
+
| Vine identity vs reduced pairing | `tests/test_vineyard.py`, `tests/test_moving_vineyard.py` (`test_vine_identity_through_switches`) |
|
|
131
|
+
| Kinetic Delaunay vs GUDHI (2D / 3D) | `tests/test_kinetic_delaunay.py`, `tests/test_kinetic_delaunay_3d.py` |
|
|
132
|
+
| Kinetic filtration order vs GUDHI | `tests/test_kinetic_filtration.py`, `tests/test_kinetic_filtration_3d.py`, `tests/test_kinetic_filtration_dynamic.py` |
|
|
133
|
+
| Kinetic vineyard diagrams + vine identity vs GUDHI | `tests/test_kinetic_vineyard.py`, `tests/test_kinetic_vineyard_3d.py` |
|
|
134
|
+
| Dense vs sparse backend (`R`/`U`/`low` and diagrams) | `tests/test_backend_equiv.py` |
|
|
135
|
+
| Python vs C++ exact poly / Sturm | `tests/test_cpp_exact_poly.py` |
|
|
136
|
+
| SoS signs vs shrinking-ε and raw determinants | `tests/test_sos.py` |
|
|
137
|
+
| Weighted alpha vs weighted GUDHI | `tests/test_3d.py` (weighted cases) |
|
|
138
|
+
| Weighted flip continuity (bracketing) | `tests/test_3d.py::test_weighted_flip_continuity_lemma` |
|
|
139
|
+
| Multi-flip-at-one-τ kinetic vineyard | `tests/test_kinetic_vineyard.py::test_kinetic_vineyard_through_coincident_flip_cluster` |
|
|
140
|
+
| Frame-bound vs kinetic cancellation | `tests/test_frame_vs_kinetic.py` |
|
|
141
|
+
| Sparse bubble insert/delete vs dense | `tests/test_backend_equiv.py::test_sparse_bubble_path_matches_dense` |
|
|
142
|
+
|
|
143
|
+
## Scope and limitations
|
|
144
|
+
|
|
145
|
+
- Frame-bound engine: exact on the piecewise-linear interpolation of the
|
|
146
|
+
samples; events that cancel inside one frame interval are invisible (the
|
|
147
|
+
kinetic engine is the remedy; see `tests/test_frame_vs_kinetic.py`).
|
|
148
|
+
- Kinetic engine: exact event times, 2D and 3D (interior flips and hull
|
|
149
|
+
changes via vertex-at-infinity). With GMP, `run()` uses the C++ kernels
|
|
150
|
+
(`vineyards._kinetic_2d` / `vineyards._kinetic_3d`) with integer-coefficient
|
|
151
|
+
certificates (scale-cleared trajectories), bit-exact on flip sequences
|
|
152
|
+
(`tests/test_kinetic_cpp_2d.py`, `tests/test_kinetic_cpp_3d.py`); set
|
|
153
|
+
`VINEYARDS_KINETIC_CPP=0` for pure Python. The C++ event queue uses tight
|
|
154
|
+
root isolation and float-first extract-min (exact AlgT only on near-ties).
|
|
155
|
+
Exact arithmetic still favors tens-low hundreds of points for long horizons;
|
|
156
|
+
use `track_features` or frame-bound at scale.
|
|
157
|
+
- Degeneracies: geometric predicates use Edelsbrunner-Mücke Simulation of
|
|
158
|
+
Simplicity; coincident flip certificates (interior InCircle/InSphere and
|
|
159
|
+
hull/spoke orientation vs infinity) are resolved by SoS on time. Hull
|
|
160
|
+
legality is the geometric supporting-line / extreme-vertex test (raw
|
|
161
|
+
orientation so collinear hull points stay on the line). Several flips at
|
|
162
|
+
one algebraic time are batched in the kinetic vineyard. A residual that
|
|
163
|
+
local flips cannot order is finished by an oracle snap of the Delaunay
|
|
164
|
+
complex (recorded as a ``recover`` flip); only an unsuccessful snap raises
|
|
165
|
+
at vineyard construction.
|
|
166
|
+
- Weighted alpha: non-hiding is required (`assert_no_hidden`); the weighted
|
|
167
|
+
flip-continuity handoff is confirmed numerically against weighted GUDHI
|
|
168
|
+
in `tests/test_3d.py`.
|
|
169
|
+
- Geometry for frame-bound alpha values is GUDHI's; the kinetic path has its
|
|
170
|
+
own exact predicates. **Default R=DU backend is sparse C++** when
|
|
171
|
+
`vineyards._sparse` is built (`default_backend_cls()` /
|
|
172
|
+
`CppSparseBackend`); dense numpy remains the bit-exact reference oracle
|
|
173
|
+
(`VINEYARDS_BACKEND=dense` or `backend_cls=DenseBackend`). Install builds
|
|
174
|
+
the sparse kernel when a C++17 toolchain is available. GMP enables the
|
|
175
|
+
exact-poly and kinetic-2D/3D kernels (shared arithmetic in
|
|
176
|
+
`cpp/kinetic_arith.hpp`; binary float-key event heaps; certificate poly
|
|
177
|
+
caches; optional if GMP headers are missing; CI on Linux asserts all four
|
|
178
|
+
modules import). Type stubs (`.pyi`) ship for the C extensions. Docs:
|
|
179
|
+
`docs/` (Sphinx; GitHub Pages + Read the Docs configs). Releases publish
|
|
180
|
+
**sdists and platform wheels** via cibuildwheel.
|
|
181
|
+
- CI: Linux (Ubuntu) is the primary surface. Windows builds the sparse kernel
|
|
182
|
+
and runs core tests (GMP exact-poly / kinetic-2D/3D are skipped when GMP is
|
|
183
|
+
absent).
|
|
184
|
+
|
|
185
|
+
## Measured sparse speedups
|
|
186
|
+
|
|
187
|
+
From `python examples/benchmark_sparse.py` on this machine after
|
|
188
|
+
`python setup.py build_ext --inplace` (Apple M4 Max, macOS 15, arm64, Python
|
|
189
|
+
3.13). Columns are dense vs C++ sparse wall time and the ratio dense/sparse;
|
|
190
|
+
`nnzR/m^2` and `nnzU/m^2` are filled fractions of the reduced matrices.
|
|
191
|
+
|
|
192
|
+
| n | m | nnzR/m^2 | nnzU/m^2 | reduce | update | local |
|
|
193
|
+
|----:|----:|---------:|---------:|-------:|-------:|------:|
|
|
194
|
+
| 40 | 217 | 0.006 | 0.012 | 7.1x | 123.1x | 16.4x |
|
|
195
|
+
| 70 | 393 | 0.004 | 0.007 | 8.0x | 200.6x | 15.6x |
|
|
196
|
+
| 100 | 575 | 0.003 | 0.005 | 10.3x | 211.9x | 19.0x |
|
|
197
|
+
|
|
198
|
+
Re-run the script on your hardware; numbers vary with CPU and size.
|
|
199
|
+
|
|
200
|
+
## Knee rates
|
|
201
|
+
|
|
202
|
+
Pairing-switch share of value-update transpositions under random-walk motion
|
|
203
|
+
(`update%` in the script). From `python examples/counter_report.py` on the same
|
|
204
|
+
machine (Apple M4 Max, macOS 15, arm64):
|
|
205
|
+
|
|
206
|
+
| n | m | knee/switch % | crossings/flip | changed/flip | flip frames |
|
|
207
|
+
|----:|-----:|------:|-------:|------:|----:|
|
|
208
|
+
| 8 | 33 | 9.42% | 19.8 | 9.6 | 82 |
|
|
209
|
+
| 30 | 159 | 3.16% | 549.4 | 91.0 | 45 |
|
|
210
|
+
| 100 | 572 | 1.21% | 5747.7 | 540.2 | 16 |
|
|
211
|
+
| 300 | 1767 | 0.52% | 27006.2 | 2181.6 | 5 |
|
|
212
|
+
|
|
213
|
+
## References
|
|
214
|
+
|
|
215
|
+
- D. Cohen-Steiner, H. Edelsbrunner, D. Morozov. Vines and Vineyards by
|
|
216
|
+
Updating Persistence in Linear Time. In Proc. 22nd Annu. Symp. Comput.
|
|
217
|
+
Geom. (SoCG), pp. 119-126, 2006.
|
|
218
|
+
- H. Edelsbrunner, D. Letscher, A. Zomorodian. Topological Persistence and
|
|
219
|
+
Simplification. Discrete Comput. Geom. 28:511-533, 2002.
|
|
220
|
+
- H. Edelsbrunner, J. Harer. Computational Topology: An Introduction. AMS,
|
|
221
|
+
2010.
|
|
222
|
+
- H. Edelsbrunner, E. P. Mücke. Simulation of Simplicity: A Technique to Cope
|
|
223
|
+
with Degenerate Cases in Geometric Algorithms. ACM Trans. Graph. 9(1):66-104,
|
|
224
|
+
1990.
|
|
225
|
+
- The GUDHI Project. GUDHI User and Reference Manual.
|
|
226
|
+
https://gudhi.inria.fr/doc/latest/
|
|
227
|
+
- D. Morozov. Dionysus 2. https://www.mrzv.org/software/dionysus2/
|
|
228
|
+
|
|
229
|
+
## Citation
|
|
230
|
+
|
|
231
|
+
```bibtex
|
|
232
|
+
@software{ray_vineyards,
|
|
233
|
+
author = {Ray, Shawn},
|
|
234
|
+
title = {Vineyards over changing triangulations},
|
|
235
|
+
url = {https://github.com/codingwithshawnyt/vineyards},
|
|
236
|
+
year = {2026}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
See also `CITATION.cff`.
|
|
241
|
+
|
|
242
|
+
Research code from a summer internship at ISTA (group of Herbert Edelsbrunner),
|
|
243
|
+
2026.
|