pysimplicial 0.2.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.
Files changed (35) hide show
  1. pysimplicial-0.2.0/PKG-INFO +297 -0
  2. pysimplicial-0.2.0/README.md +271 -0
  3. pysimplicial-0.2.0/pyproject.toml +35 -0
  4. pysimplicial-0.2.0/setup.cfg +4 -0
  5. pysimplicial-0.2.0/src/pysimplicial/__init__.py +27 -0
  6. pysimplicial-0.2.0/src/pysimplicial/_errors.py +13 -0
  7. pysimplicial-0.2.0/src/pysimplicial/_solvers/__init__.py +0 -0
  8. pysimplicial-0.2.0/src/pysimplicial/_solvers/cuda_restarts.py +507 -0
  9. pysimplicial-0.2.0/src/pysimplicial/_solvers/exact.py +1375 -0
  10. pysimplicial-0.2.0/src/pysimplicial/_solvers/set_cover.py +136 -0
  11. pysimplicial-0.2.0/src/pysimplicial/category.py +290 -0
  12. pysimplicial-0.2.0/src/pysimplicial/collapse.py +52 -0
  13. pysimplicial-0.2.0/src/pysimplicial/complex.py +80 -0
  14. pysimplicial-0.2.0/src/pysimplicial/contiguity.py +97 -0
  15. pysimplicial-0.2.0/src/pysimplicial/datasets/__init__.py +19 -0
  16. pysimplicial-0.2.0/src/pysimplicial/datasets/graphs.py +48 -0
  17. pysimplicial-0.2.0/src/pysimplicial/datasets/random_complexes.py +29 -0
  18. pysimplicial-0.2.0/src/pysimplicial/datasets/rips.py +185 -0
  19. pysimplicial-0.2.0/src/pysimplicial/datasets/triangulations.json +1 -0
  20. pysimplicial-0.2.0/src/pysimplicial/datasets/triangulations.py +44 -0
  21. pysimplicial-0.2.0/src/pysimplicial/maps.py +81 -0
  22. pysimplicial-0.2.0/src/pysimplicial/operations.py +105 -0
  23. pysimplicial-0.2.0/src/pysimplicial/visualization/__init__.py +36 -0
  24. pysimplicial-0.2.0/src/pysimplicial/visualization/_layout.py +824 -0
  25. pysimplicial-0.2.0/src/pysimplicial/visualization/_points.py +46 -0
  26. pysimplicial-0.2.0/src/pysimplicial/visualization/_surface.py +1459 -0
  27. pysimplicial-0.2.0/src/pysimplicial/visualization/_two_d.py +603 -0
  28. pysimplicial-0.2.0/src/pysimplicial.egg-info/PKG-INFO +297 -0
  29. pysimplicial-0.2.0/src/pysimplicial.egg-info/SOURCES.txt +33 -0
  30. pysimplicial-0.2.0/src/pysimplicial.egg-info/dependency_links.txt +1 -0
  31. pysimplicial-0.2.0/src/pysimplicial.egg-info/requires.txt +17 -0
  32. pysimplicial-0.2.0/src/pysimplicial.egg-info/top_level.txt +1 -0
  33. pysimplicial-0.2.0/tests/test_datasets_and_visualization.py +56 -0
  34. pysimplicial-0.2.0/tests/test_gscat.py +119 -0
  35. pysimplicial-0.2.0/tests/test_topology.py +120 -0
@@ -0,0 +1,297 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysimplicial
3
+ Version: 0.2.0
4
+ Summary: Finite simplicial complexes, contiguity and simplicial LS category
5
+ Project-URL: Homepage, https://github.com/zgenng/PySimplicial
6
+ Project-URL: Repository, https://github.com/zgenng/PySimplicial
7
+ Project-URL: Issues, https://github.com/zgenng/PySimplicial/issues
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: numpy>=1.24
15
+ Provides-Extra: plot
16
+ Requires-Dist: matplotlib>=3.6; extra == "plot"
17
+ Provides-Extra: plot3d
18
+ Requires-Dist: plotly>=5; extra == "plot3d"
19
+ Provides-Extra: viz
20
+ Requires-Dist: matplotlib>=3.6; extra == "viz"
21
+ Requires-Dist: plotly>=5; extra == "viz"
22
+ Provides-Extra: cuda12
23
+ Requires-Dist: numba-cuda[cu12]; extra == "cuda12"
24
+ Provides-Extra: cuda13
25
+ Requires-Dist: numba-cuda[cu13]; extra == "cuda13"
26
+
27
+ # PySimplicial
28
+
29
+ **A Python library for computational simplicial topology, simplicial maps, contiguity, and simplicial Lusternik–Schnirelmann category.**
30
+
31
+ PySimplicial provides tools for constructing and analyzing finite abstract simplicial complexes, studying strong homotopy properties, and computing simplicial topological invariants. It includes exact algorithms for simplicial category and contiguity distance, along with CPU and optional CUDA-assisted methods for the simplicial geometric category.
32
+
33
+ ## Features
34
+
35
+ - **Simplicial complexes:** Immutable finite simplicial complexes, faces, facets, dimensions, and skeletons.
36
+ - **Operations:** Joins, wedges, disjoint unions, links, categorical products, and connected components.
37
+ - **Strong homotopy:** Dominated vertices, strong collapsibility, and strong cores.
38
+ - **Simplicial maps:** Construction, restriction, composition, and validation.
39
+ - **Contiguity:** Direct contiguity, contiguity classes, chains, and distance.
40
+ - **Simplicial LS category:** Computation of `scat` and `gscat`.
41
+ - **Exact computation:** Categorical covers, certificates, and rigorous bounds.
42
+ - **Optional CUDA acceleration:** GPU-assisted geometric category computations.
43
+ - **Datasets and visualization:** Graph families, triangulated manifolds, random and Vietoris–Rips complexes, 2D and interactive 3D plots.
44
+
45
+ ## Installation
46
+
47
+ Requires **Python 3.10+** and **NumPy 1.24+**.
48
+
49
+ Install directly from GitHub:
50
+
51
+ ```bash
52
+ python -m pip install git+https://github.com/zgenng/PySimplicial.git
53
+ ```
54
+
55
+ Or clone the repository and install in editable mode:
56
+
57
+ ```bash
58
+ git clone https://github.com/zgenng/PySimplicial.git
59
+ cd PySimplicial
60
+ python -m pip install -e .
61
+ ```
62
+
63
+ Optional visualization and CUDA dependencies (run from the project root):
64
+
65
+ ```bash
66
+ python -m pip install -e ".[viz]" # Matplotlib + Plotly
67
+ python -m pip install -e ".[plot]" # Matplotlib only
68
+ python -m pip install -e ".[plot3d]" # Plotly only
69
+ python -m pip install -e ".[cuda12]" # CUDA 12
70
+ python -m pip install -e ".[cuda13]" # CUDA 13
71
+ ```
72
+
73
+ CUDA requires a compatible NVIDIA GPU and driver. Once the package is published to PyPI, the intended command is:
74
+
75
+ ```bash
76
+ pip install pysimplicial
77
+ ```
78
+
79
+ ## Quick start
80
+
81
+ ### Finite simplicial complexes
82
+
83
+ ```python
84
+ from pysimplicial import SimplicialComplex
85
+
86
+ # Boundary of a triangle, a simplicial model of S¹
87
+ K = SimplicialComplex([(0, 1), (1, 2), (2, 0)])
88
+
89
+ print(K.dimension()) # 1
90
+ print(K.vertices)
91
+ print(K.facets)
92
+ print(K.faces())
93
+ ```
94
+
95
+ `SimplicialComplex` is immutable. Its facets are the inclusion-maximal simplices; nonempty faces are generated on demand. Use `K.faces(d)`, `K.skeleton(d)`, or `K.induced_subcomplex(vertices)` for common operations.
96
+
97
+ ### Strong collapsibility
98
+
99
+ ```python
100
+ from pysimplicial import is_strongly_collapsible, strong_core
101
+ from pysimplicial.datasets import path_graph
102
+
103
+ K = path_graph(5)
104
+ print(is_strongly_collapsible(K)) # True
105
+ result = strong_core(K)
106
+ print(result.core)
107
+ print(result.steps)
108
+ ```
109
+
110
+ A finite complex is *strongly collapsible* when dominated vertices can be removed iteratively until one vertex remains.
111
+
112
+ ### Simplicial maps and contiguity
113
+
114
+ Two simplicial maps `f, g: K → L` are contiguous if `f(σ) ∪ g(σ)` is a simplex of `L` for every simplex `σ` of `K`.
115
+
116
+ ```python
117
+ from pysimplicial import (
118
+ SimplicialComplex, SimplicialMap,
119
+ is_contiguous, same_contiguity_class, contiguity_chain,
120
+ )
121
+
122
+ K = SimplicialComplex([(0, 1)])
123
+ f = SimplicialMap.identity(K)
124
+ g = SimplicialMap.constant(K, K, vertex=0)
125
+
126
+ print(is_contiguous(f, g))
127
+ print(same_contiguity_class(f, g))
128
+ print(contiguity_chain(f, g))
129
+ ```
130
+
131
+ ## Simplicial Lusternik–Schnirelmann category
132
+
133
+ PySimplicial computes two related invariants:
134
+
135
+ - `scat(K)`: reduced simplicial LS category, using covers by categorical subcomplexes.
136
+ - `gscat(K)`: reduced simplicial geometric category, using covers by strongly collapsible subcomplexes.
137
+
138
+ A cover by `r` subcomplexes yields the **reduced value `r - 1`**.
139
+
140
+ ### Simplicial category
141
+
142
+ ```python
143
+ from pysimplicial import scat
144
+ from pysimplicial.datasets import cycle_graph
145
+
146
+ K = cycle_graph(3)
147
+ result = scat(K)
148
+ print(result.value) # 1
149
+ print(result.cover)
150
+ print(result.chains)
151
+ ```
152
+
153
+ ### Geometric category
154
+
155
+ ```python
156
+ from pysimplicial import gscat, verify_gscat_cover
157
+ from pysimplicial.datasets import projective_plane
158
+
159
+ K = projective_plane()
160
+ result = gscat(K)
161
+
162
+ print(result.value) # 2
163
+ print(result.exact)
164
+ print(result.lower_bound, result.upper_bound)
165
+ assert verify_gscat_cover(K, result.cover)
166
+ ```
167
+
168
+ Mathematically, in the reduced convention,
169
+
170
+ \[
171
+ \operatorname{gscat}(K) = \min\{r \geq 0 : K = K_0 \cup \cdots \cup K_r,\; K_i \text{ strongly collapsible}\}.
172
+ \]
173
+
174
+ When the result's lower and upper bounds agree, the answer is exact. Otherwise, `value` is `None` and the verified cover supplies an upper bound. Search limits can be configured with `max_candidate_states` and `max_search_states`.
175
+
176
+ ## Optional CUDA acceleration
177
+
178
+ ```python
179
+ from pysimplicial import cuda_status, gscat
180
+ from pysimplicial.datasets import projective_plane
181
+
182
+ print(cuda_status())
183
+ K = projective_plane()
184
+ result = gscat(K, backend="cuda", restarts=1000, seed=42)
185
+ print(result.value, result.gpu_used, result.exact)
186
+ ```
187
+
188
+ Set `backend="auto"` to use CUDA when available, or `backend="cpu"` for CPU-only computation. Set `restarts=0` to skip randomized restarts and proceed to the exact search. CPU verification is used to check returned covers. The randomized CUDA restart kernel supports up to 64 vertices and 512 facets; larger inputs use the exact-search path.
189
+
190
+ ## Datasets
191
+
192
+ ### Standard graph families
193
+
194
+ ```python
195
+ from pysimplicial.datasets import (
196
+ complete_graph, complete_bipartite_graph, cycle_graph, path_graph,
197
+ )
198
+
199
+ K1 = complete_graph(5)
200
+ K2 = complete_bipartite_graph(3, 4)
201
+ K3 = cycle_graph(6)
202
+ K4 = path_graph(5)
203
+ ```
204
+
205
+ ### Named triangulations
206
+
207
+ ```python
208
+ from pysimplicial.datasets import (
209
+ torus, projective_plane, tetrahedron_boundary,
210
+ triangulation, triangulation_names,
211
+ )
212
+
213
+ T = torus()
214
+ RP2 = projective_plane()
215
+ S2 = tetrahedron_boundary()
216
+ CP2 = triangulation("CP2")
217
+ print(CP2.dimension()) # 4
218
+ print(triangulation_names())
219
+ ```
220
+
221
+ ### Random and Vietoris–Rips complexes
222
+
223
+ ```python
224
+ from pysimplicial.datasets import random_d_complex, generate_rips_data
225
+
226
+ K = random_d_complex(n=10, dim=2, seed=42)
227
+ points, R, epsilon = generate_rips_data(n_points=20, shape="circle", seed=42)
228
+ print(R.dimension(), epsilon)
229
+ ```
230
+
231
+ ## Visualization
232
+
233
+ Install `.[viz]` first.
234
+
235
+ ### 2D
236
+
237
+ ```python
238
+ from pysimplicial import gscat
239
+ from pysimplicial.datasets import complete_graph
240
+ from pysimplicial.visualization import draw_complex_and_cover
241
+
242
+ K = complete_graph(5)
243
+ result = gscat(K)
244
+ draw_complex_and_cover(K, result, legend=True)
245
+ ```
246
+
247
+ ### Interactive 3D
248
+
249
+ ```python
250
+ from pysimplicial import gscat
251
+ from pysimplicial.datasets import projective_plane
252
+ from pysimplicial.visualization import draw_surface_3d
253
+
254
+ K = projective_plane()
255
+ result = gscat(K)
256
+ draw_surface_3d(K, cover=result.cover, show=False, save_html="rp2-cover.html")
257
+ ```
258
+
259
+ ## Tests and development
260
+
261
+ After installing the package:
262
+
263
+ ```bash
264
+ python -m unittest discover -s tests -v
265
+ ```
266
+
267
+ Build and validate distributions:
268
+
269
+ ```bash
270
+ python -m pip install build twine
271
+ python -m build
272
+ python -m twine check dist/*
273
+ ```
274
+
275
+ The test suite covers topological operations, contiguity, geometric category, datasets, and visualization. CUDA-specific tests require compatible hardware.
276
+
277
+ ## Mathematical background and references
278
+
279
+ This project is motivated by computational problems in finite simplicial complexes, strong homotopy theory, contiguity, and simplicial Lusternik–Schnirelmann category.
280
+
281
+ - J. A. Barmak and E. G. Minian, *Strong homotopy types, nerves and collapses*, Discrete & Computational Geometry (2012).
282
+ - D. Fernández-Ternero, E. Macías-Virgós, E. Minuz, and J. A. Vilches, *Simplicial Lusternik–Schnirelmann category*, Publicacions Matemàtiques (2019).
283
+ - [Frank Lutz's triangulated surface catalog](https://www3.math.tu-berlin.de/IfM/Nachrufe/Frank_Lutz/stellar/surfaces.html).
284
+
285
+ ## Contributing
286
+
287
+ Bug reports, suggestions, and contributions are welcome. Please open an [issue](https://github.com/zgenng/PySimplicial/issues) to discuss problems or improvements.
288
+
289
+ ## Project status
290
+
291
+ PySimplicial is an evolving research-oriented project. Public APIs and algorithms may change as development continues.
292
+
293
+ **Current source version:** `0.2.0`
294
+
295
+ ## Author
296
+
297
+ **Islam Yeginbay** — [@zgenng](https://github.com/zgenng/PySimplicial)
@@ -0,0 +1,271 @@
1
+ # PySimplicial
2
+
3
+ **A Python library for computational simplicial topology, simplicial maps, contiguity, and simplicial Lusternik–Schnirelmann category.**
4
+
5
+ PySimplicial provides tools for constructing and analyzing finite abstract simplicial complexes, studying strong homotopy properties, and computing simplicial topological invariants. It includes exact algorithms for simplicial category and contiguity distance, along with CPU and optional CUDA-assisted methods for the simplicial geometric category.
6
+
7
+ ## Features
8
+
9
+ - **Simplicial complexes:** Immutable finite simplicial complexes, faces, facets, dimensions, and skeletons.
10
+ - **Operations:** Joins, wedges, disjoint unions, links, categorical products, and connected components.
11
+ - **Strong homotopy:** Dominated vertices, strong collapsibility, and strong cores.
12
+ - **Simplicial maps:** Construction, restriction, composition, and validation.
13
+ - **Contiguity:** Direct contiguity, contiguity classes, chains, and distance.
14
+ - **Simplicial LS category:** Computation of `scat` and `gscat`.
15
+ - **Exact computation:** Categorical covers, certificates, and rigorous bounds.
16
+ - **Optional CUDA acceleration:** GPU-assisted geometric category computations.
17
+ - **Datasets and visualization:** Graph families, triangulated manifolds, random and Vietoris–Rips complexes, 2D and interactive 3D plots.
18
+
19
+ ## Installation
20
+
21
+ Requires **Python 3.10+** and **NumPy 1.24+**.
22
+
23
+ Install directly from GitHub:
24
+
25
+ ```bash
26
+ python -m pip install git+https://github.com/zgenng/PySimplicial.git
27
+ ```
28
+
29
+ Or clone the repository and install in editable mode:
30
+
31
+ ```bash
32
+ git clone https://github.com/zgenng/PySimplicial.git
33
+ cd PySimplicial
34
+ python -m pip install -e .
35
+ ```
36
+
37
+ Optional visualization and CUDA dependencies (run from the project root):
38
+
39
+ ```bash
40
+ python -m pip install -e ".[viz]" # Matplotlib + Plotly
41
+ python -m pip install -e ".[plot]" # Matplotlib only
42
+ python -m pip install -e ".[plot3d]" # Plotly only
43
+ python -m pip install -e ".[cuda12]" # CUDA 12
44
+ python -m pip install -e ".[cuda13]" # CUDA 13
45
+ ```
46
+
47
+ CUDA requires a compatible NVIDIA GPU and driver. Once the package is published to PyPI, the intended command is:
48
+
49
+ ```bash
50
+ pip install pysimplicial
51
+ ```
52
+
53
+ ## Quick start
54
+
55
+ ### Finite simplicial complexes
56
+
57
+ ```python
58
+ from pysimplicial import SimplicialComplex
59
+
60
+ # Boundary of a triangle, a simplicial model of S¹
61
+ K = SimplicialComplex([(0, 1), (1, 2), (2, 0)])
62
+
63
+ print(K.dimension()) # 1
64
+ print(K.vertices)
65
+ print(K.facets)
66
+ print(K.faces())
67
+ ```
68
+
69
+ `SimplicialComplex` is immutable. Its facets are the inclusion-maximal simplices; nonempty faces are generated on demand. Use `K.faces(d)`, `K.skeleton(d)`, or `K.induced_subcomplex(vertices)` for common operations.
70
+
71
+ ### Strong collapsibility
72
+
73
+ ```python
74
+ from pysimplicial import is_strongly_collapsible, strong_core
75
+ from pysimplicial.datasets import path_graph
76
+
77
+ K = path_graph(5)
78
+ print(is_strongly_collapsible(K)) # True
79
+ result = strong_core(K)
80
+ print(result.core)
81
+ print(result.steps)
82
+ ```
83
+
84
+ A finite complex is *strongly collapsible* when dominated vertices can be removed iteratively until one vertex remains.
85
+
86
+ ### Simplicial maps and contiguity
87
+
88
+ Two simplicial maps `f, g: K → L` are contiguous if `f(σ) ∪ g(σ)` is a simplex of `L` for every simplex `σ` of `K`.
89
+
90
+ ```python
91
+ from pysimplicial import (
92
+ SimplicialComplex, SimplicialMap,
93
+ is_contiguous, same_contiguity_class, contiguity_chain,
94
+ )
95
+
96
+ K = SimplicialComplex([(0, 1)])
97
+ f = SimplicialMap.identity(K)
98
+ g = SimplicialMap.constant(K, K, vertex=0)
99
+
100
+ print(is_contiguous(f, g))
101
+ print(same_contiguity_class(f, g))
102
+ print(contiguity_chain(f, g))
103
+ ```
104
+
105
+ ## Simplicial Lusternik–Schnirelmann category
106
+
107
+ PySimplicial computes two related invariants:
108
+
109
+ - `scat(K)`: reduced simplicial LS category, using covers by categorical subcomplexes.
110
+ - `gscat(K)`: reduced simplicial geometric category, using covers by strongly collapsible subcomplexes.
111
+
112
+ A cover by `r` subcomplexes yields the **reduced value `r - 1`**.
113
+
114
+ ### Simplicial category
115
+
116
+ ```python
117
+ from pysimplicial import scat
118
+ from pysimplicial.datasets import cycle_graph
119
+
120
+ K = cycle_graph(3)
121
+ result = scat(K)
122
+ print(result.value) # 1
123
+ print(result.cover)
124
+ print(result.chains)
125
+ ```
126
+
127
+ ### Geometric category
128
+
129
+ ```python
130
+ from pysimplicial import gscat, verify_gscat_cover
131
+ from pysimplicial.datasets import projective_plane
132
+
133
+ K = projective_plane()
134
+ result = gscat(K)
135
+
136
+ print(result.value) # 2
137
+ print(result.exact)
138
+ print(result.lower_bound, result.upper_bound)
139
+ assert verify_gscat_cover(K, result.cover)
140
+ ```
141
+
142
+ Mathematically, in the reduced convention,
143
+
144
+ \[
145
+ \operatorname{gscat}(K) = \min\{r \geq 0 : K = K_0 \cup \cdots \cup K_r,\; K_i \text{ strongly collapsible}\}.
146
+ \]
147
+
148
+ When the result's lower and upper bounds agree, the answer is exact. Otherwise, `value` is `None` and the verified cover supplies an upper bound. Search limits can be configured with `max_candidate_states` and `max_search_states`.
149
+
150
+ ## Optional CUDA acceleration
151
+
152
+ ```python
153
+ from pysimplicial import cuda_status, gscat
154
+ from pysimplicial.datasets import projective_plane
155
+
156
+ print(cuda_status())
157
+ K = projective_plane()
158
+ result = gscat(K, backend="cuda", restarts=1000, seed=42)
159
+ print(result.value, result.gpu_used, result.exact)
160
+ ```
161
+
162
+ Set `backend="auto"` to use CUDA when available, or `backend="cpu"` for CPU-only computation. Set `restarts=0` to skip randomized restarts and proceed to the exact search. CPU verification is used to check returned covers. The randomized CUDA restart kernel supports up to 64 vertices and 512 facets; larger inputs use the exact-search path.
163
+
164
+ ## Datasets
165
+
166
+ ### Standard graph families
167
+
168
+ ```python
169
+ from pysimplicial.datasets import (
170
+ complete_graph, complete_bipartite_graph, cycle_graph, path_graph,
171
+ )
172
+
173
+ K1 = complete_graph(5)
174
+ K2 = complete_bipartite_graph(3, 4)
175
+ K3 = cycle_graph(6)
176
+ K4 = path_graph(5)
177
+ ```
178
+
179
+ ### Named triangulations
180
+
181
+ ```python
182
+ from pysimplicial.datasets import (
183
+ torus, projective_plane, tetrahedron_boundary,
184
+ triangulation, triangulation_names,
185
+ )
186
+
187
+ T = torus()
188
+ RP2 = projective_plane()
189
+ S2 = tetrahedron_boundary()
190
+ CP2 = triangulation("CP2")
191
+ print(CP2.dimension()) # 4
192
+ print(triangulation_names())
193
+ ```
194
+
195
+ ### Random and Vietoris–Rips complexes
196
+
197
+ ```python
198
+ from pysimplicial.datasets import random_d_complex, generate_rips_data
199
+
200
+ K = random_d_complex(n=10, dim=2, seed=42)
201
+ points, R, epsilon = generate_rips_data(n_points=20, shape="circle", seed=42)
202
+ print(R.dimension(), epsilon)
203
+ ```
204
+
205
+ ## Visualization
206
+
207
+ Install `.[viz]` first.
208
+
209
+ ### 2D
210
+
211
+ ```python
212
+ from pysimplicial import gscat
213
+ from pysimplicial.datasets import complete_graph
214
+ from pysimplicial.visualization import draw_complex_and_cover
215
+
216
+ K = complete_graph(5)
217
+ result = gscat(K)
218
+ draw_complex_and_cover(K, result, legend=True)
219
+ ```
220
+
221
+ ### Interactive 3D
222
+
223
+ ```python
224
+ from pysimplicial import gscat
225
+ from pysimplicial.datasets import projective_plane
226
+ from pysimplicial.visualization import draw_surface_3d
227
+
228
+ K = projective_plane()
229
+ result = gscat(K)
230
+ draw_surface_3d(K, cover=result.cover, show=False, save_html="rp2-cover.html")
231
+ ```
232
+
233
+ ## Tests and development
234
+
235
+ After installing the package:
236
+
237
+ ```bash
238
+ python -m unittest discover -s tests -v
239
+ ```
240
+
241
+ Build and validate distributions:
242
+
243
+ ```bash
244
+ python -m pip install build twine
245
+ python -m build
246
+ python -m twine check dist/*
247
+ ```
248
+
249
+ The test suite covers topological operations, contiguity, geometric category, datasets, and visualization. CUDA-specific tests require compatible hardware.
250
+
251
+ ## Mathematical background and references
252
+
253
+ This project is motivated by computational problems in finite simplicial complexes, strong homotopy theory, contiguity, and simplicial Lusternik–Schnirelmann category.
254
+
255
+ - J. A. Barmak and E. G. Minian, *Strong homotopy types, nerves and collapses*, Discrete & Computational Geometry (2012).
256
+ - D. Fernández-Ternero, E. Macías-Virgós, E. Minuz, and J. A. Vilches, *Simplicial Lusternik–Schnirelmann category*, Publicacions Matemàtiques (2019).
257
+ - [Frank Lutz's triangulated surface catalog](https://www3.math.tu-berlin.de/IfM/Nachrufe/Frank_Lutz/stellar/surfaces.html).
258
+
259
+ ## Contributing
260
+
261
+ Bug reports, suggestions, and contributions are welcome. Please open an [issue](https://github.com/zgenng/PySimplicial/issues) to discuss problems or improvements.
262
+
263
+ ## Project status
264
+
265
+ PySimplicial is an evolving research-oriented project. Public APIs and algorithms may change as development continues.
266
+
267
+ **Current source version:** `0.2.0`
268
+
269
+ ## Author
270
+
271
+ **Islam Yeginbay** — [@zgenng](https://github.com/zgenng/PySimplicial)
@@ -0,0 +1,35 @@
1
+ [project.urls]
2
+ Homepage = "https://github.com/zgenng/PySimplicial"
3
+ Repository = "https://github.com/zgenng/PySimplicial"
4
+ Issues = "https://github.com/zgenng/PySimplicial/issues"
5
+
6
+ [build-system]
7
+ requires = ["setuptools>=61", "wheel"]
8
+ build-backend = "setuptools.build_meta"
9
+
10
+ [project]
11
+ name = "pysimplicial"
12
+ version = "0.2.0"
13
+ description = "Finite simplicial complexes, contiguity and simplicial LS category"
14
+ readme = "README.md"
15
+ requires-python = ">=3.10"
16
+ dependencies = ["numpy>=1.24"]
17
+ classifiers = [
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Topic :: Scientific/Engineering :: Mathematics",
21
+ "Operating System :: OS Independent",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ plot = ["matplotlib>=3.6"]
26
+ plot3d = ["plotly>=5"]
27
+ viz = ["matplotlib>=3.6", "plotly>=5"]
28
+ cuda12 = ["numba-cuda[cu12]"]
29
+ cuda13 = ["numba-cuda[cu13]"]
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"]
33
+
34
+ [tool.setuptools.package-data]
35
+ "pysimplicial.datasets" = ["*.json"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ """Finite simplicial complexes, contiguity and simplicial category."""
2
+
3
+ from ._errors import CudaUnavailableError, SearchLimitExceeded
4
+ from .category import (
5
+ CategoryResult,
6
+ GSCatResult,
7
+ contiguity_distance,
8
+ cuda_status,
9
+ gscat,
10
+ is_categorical,
11
+ scat,
12
+ verify_gscat_cover,
13
+ )
14
+ from .collapse import core, dominators, is_strongly_collapsible, strong_core
15
+ from .complex import SimplicialComplex
16
+ from .contiguity import contiguity_chain, contiguity_class, is_contiguous, same_contiguity_class
17
+ from .maps import SimplicialMap
18
+ from .operations import categorical_product, connected_components, disjoint_union, graph_join, join, link, relabel, wedge
19
+
20
+ __all__ = [
21
+ "CategoryResult", "CudaUnavailableError", "GSCatResult", "SearchLimitExceeded",
22
+ "SimplicialComplex", "SimplicialMap", "categorical_product", "connected_components",
23
+ "contiguity_chain", "contiguity_class", "contiguity_distance", "core", "cuda_status",
24
+ "disjoint_union", "dominators", "graph_join", "gscat", "is_categorical",
25
+ "is_contiguous", "is_strongly_collapsible", "join", "link", "relabel",
26
+ "same_contiguity_class", "scat", "strong_core", "verify_gscat_cover", "wedge",
27
+ ]
@@ -0,0 +1,13 @@
1
+ class SearchLimitExceeded(RuntimeError):
2
+ """A search budget expired before minimality or reachability was decided."""
3
+
4
+ def __init__(self, message, *, gpu_used=False, cover_lower_bound=None, cover_masks=()):
5
+ super().__init__(message)
6
+ self.gpu_used = gpu_used
7
+ self.cover_lower_bound = cover_lower_bound
8
+ self.cover_masks = cover_masks
9
+ self.cover_witnesses = ()
10
+
11
+
12
+ class CudaUnavailableError(RuntimeError):
13
+ """The explicitly requested CUDA backend is unavailable."""