holonomy-lib 0.8.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.
- holonomy_lib-0.8.0/LICENSE.md +105 -0
- holonomy_lib-0.8.0/PKG-INFO +161 -0
- holonomy_lib-0.8.0/README.md +119 -0
- holonomy_lib-0.8.0/pyproject.toml +107 -0
- holonomy_lib-0.8.0/setup.cfg +4 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/__init__.py +1 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/__main__.py +79 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/batching.py +182 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/common.py +187 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/curvature.py +154 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/datasets.py +346 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/graphs.py +286 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/server.py +172 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/static/app.js +435 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/static/charts.js +114 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/static/index.html +45 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/static/layout.js +85 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/static/style.css +121 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/static/view.js +195 -0
- holonomy_lib-0.8.0/src/holonomy_explorer/topology.py +118 -0
- holonomy_lib-0.8.0/src/holonomy_lib/__init__.py +9 -0
- holonomy_lib-0.8.0/src/holonomy_lib/_graph_utils.py +52 -0
- holonomy_lib-0.8.0/src/holonomy_lib/_quadrature.py +74 -0
- holonomy_lib-0.8.0/src/holonomy_lib/algebra/__init__.py +32 -0
- holonomy_lib-0.8.0/src/holonomy_lib/algebra/eigsh_sparse.py +251 -0
- holonomy_lib-0.8.0/src/holonomy_lib/algebra/lanczos.py +361 -0
- holonomy_lib-0.8.0/src/holonomy_lib/algebra/linear.py +180 -0
- holonomy_lib-0.8.0/src/holonomy_lib/algebra/solvers.py +547 -0
- holonomy_lib-0.8.0/src/holonomy_lib/convex/__init__.py +27 -0
- holonomy_lib-0.8.0/src/holonomy_lib/convex/least_squares.py +184 -0
- holonomy_lib-0.8.0/src/holonomy_lib/discrete_geometry/__init__.py +38 -0
- holonomy_lib-0.8.0/src/holonomy_lib/discrete_geometry/forman.py +242 -0
- holonomy_lib-0.8.0/src/holonomy_lib/discrete_geometry/ricci.py +855 -0
- holonomy_lib-0.8.0/src/holonomy_lib/experimental/__init__.py +13 -0
- holonomy_lib-0.8.0/src/holonomy_lib/experimental/heterogeneous_kappa.py +361 -0
- holonomy_lib-0.8.0/src/holonomy_lib/experimental/laplacian_eigenmaps.py +200 -0
- holonomy_lib-0.8.0/src/holonomy_lib/hyperbolic/__init__.py +27 -0
- holonomy_lib-0.8.0/src/holonomy_lib/hyperbolic/frechet_mean.py +381 -0
- holonomy_lib-0.8.0/src/holonomy_lib/hyperbolic/heat_kernel.py +608 -0
- holonomy_lib-0.8.0/src/holonomy_lib/hyperbolic/manifold_inner.py +81 -0
- holonomy_lib-0.8.0/src/holonomy_lib/info_geometry/__init__.py +64 -0
- holonomy_lib-0.8.0/src/holonomy_lib/info_geometry/divergences.py +224 -0
- holonomy_lib-0.8.0/src/holonomy_lib/info_geometry/fisher.py +179 -0
- holonomy_lib-0.8.0/src/holonomy_lib/lie/__init__.py +54 -0
- holonomy_lib-0.8.0/src/holonomy_lib/lie/so3.py +385 -0
- holonomy_lib-0.8.0/src/holonomy_lib/lie/spherical_harmonics.py +189 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/__init__.py +53 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/comparison.py +343 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/fixed_rank.py +453 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/lorentz.py +699 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/lorentzian.py +567 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/product.py +425 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/spd.py +504 -0
- holonomy_lib-0.8.0/src/holonomy_lib/manifolds/stereographic.py +680 -0
- holonomy_lib-0.8.0/src/holonomy_lib/optimization/__init__.py +42 -0
- holonomy_lib-0.8.0/src/holonomy_lib/optimization/base.py +65 -0
- holonomy_lib-0.8.0/src/holonomy_lib/optimization/sgd.py +112 -0
- holonomy_lib-0.8.0/src/holonomy_lib/py.typed +0 -0
- holonomy_lib-0.8.0/src/holonomy_lib/sheaf/__init__.py +74 -0
- holonomy_lib-0.8.0/src/holonomy_lib/sheaf/graph_sheaf.py +352 -0
- holonomy_lib-0.8.0/src/holonomy_lib/sheaf/laplacian.py +529 -0
- holonomy_lib-0.8.0/src/holonomy_lib/simplicial/__init__.py +55 -0
- holonomy_lib-0.8.0/src/holonomy_lib/simplicial/_face_lookup.py +99 -0
- holonomy_lib-0.8.0/src/holonomy_lib/simplicial/complex.py +168 -0
- holonomy_lib-0.8.0/src/holonomy_lib/simplicial/sparse_complex.py +145 -0
- holonomy_lib-0.8.0/src/holonomy_lib/simplicial/vietoris_rips.py +277 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/__init__.py +55 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/diffusion_map.py +169 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/effective_resistance.py +199 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/embedding.py +131 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/heat_kernel.py +236 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/laplacian.py +441 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/magnetic.py +351 -0
- holonomy_lib-0.8.0/src/holonomy_lib/spectral/spectral_dimension.py +104 -0
- holonomy_lib-0.8.0/src/holonomy_lib/tensor_calculus/__init__.py +23 -0
- holonomy_lib-0.8.0/src/holonomy_lib/tensor_calculus/decomposition.py +208 -0
- holonomy_lib-0.8.0/src/holonomy_lib/topology/__init__.py +28 -0
- holonomy_lib-0.8.0/src/holonomy_lib/topology/_filtration.py +147 -0
- holonomy_lib-0.8.0/src/holonomy_lib/topology/_reduction.py +227 -0
- holonomy_lib-0.8.0/src/holonomy_lib/topology/hodge.py +250 -0
- holonomy_lib-0.8.0/src/holonomy_lib/topology/persistent_homology.py +301 -0
- holonomy_lib-0.8.0/src/holonomy_lib.egg-info/PKG-INFO +161 -0
- holonomy_lib-0.8.0/src/holonomy_lib.egg-info/SOURCES.txt +89 -0
- holonomy_lib-0.8.0/src/holonomy_lib.egg-info/dependency_links.txt +1 -0
- holonomy_lib-0.8.0/src/holonomy_lib.egg-info/entry_points.txt +2 -0
- holonomy_lib-0.8.0/src/holonomy_lib.egg-info/requires.txt +20 -0
- holonomy_lib-0.8.0/src/holonomy_lib.egg-info/top_level.txt +2 -0
- holonomy_lib-0.8.0/tests/test_audit.py +268 -0
- holonomy_lib-0.8.0/tests/test_conventions.py +103 -0
- holonomy_lib-0.8.0/tests/test_device_parity.py +194 -0
- holonomy_lib-0.8.0/tests/test_quadrature.py +47 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-ALv2
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Synoros
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: holonomy-lib
|
|
3
|
+
Version: 0.8.0
|
|
4
|
+
Summary: Batched PyTorch primitives for Riemannian geometry, spectral graph theory, discrete curvature, topology, and tensor decompositions.
|
|
5
|
+
Author: Synoros
|
|
6
|
+
License-Expression: FSL-1.1-ALv2
|
|
7
|
+
Project-URL: Homepage, https://github.com/Synoros-io/holonomy_lib
|
|
8
|
+
Project-URL: Repository, https://github.com/Synoros-io/holonomy_lib
|
|
9
|
+
Project-URL: Issues, https://github.com/Synoros-io/holonomy_lib/issues
|
|
10
|
+
Keywords: pytorch,differential-geometry,riemannian-manifolds,hyperbolic-geometry,riemannian-optimization,spectral-graph-theory,graph-laplacian,magnetic-laplacian,heat-kernel,diffusion-maps,effective-resistance,ricci-curvature,ricci-flow,cellular-sheaves,simplicial-complex,hodge-laplacian,persistent-homology,topological-data-analysis,information-geometry,tensor-decomposition,numerical-linear-algebra
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE.md
|
|
23
|
+
Requires-Dist: torch>=2.2
|
|
24
|
+
Requires-Dist: numpy>=1.26
|
|
25
|
+
Requires-Dist: scipy>=1.11.2
|
|
26
|
+
Provides-Extra: comparison
|
|
27
|
+
Requires-Dist: pymanopt; extra == "comparison"
|
|
28
|
+
Requires-Dist: geoopt; extra == "comparison"
|
|
29
|
+
Requires-Dist: geomstats; extra == "comparison"
|
|
30
|
+
Requires-Dist: autograd; extra == "comparison"
|
|
31
|
+
Requires-Dist: tensorly; extra == "comparison"
|
|
32
|
+
Requires-Dist: networkx; extra == "comparison"
|
|
33
|
+
Requires-Dist: gudhi; extra == "comparison"
|
|
34
|
+
Requires-Dist: ripser; extra == "comparison"
|
|
35
|
+
Requires-Dist: GraphRicciCurvature; extra == "comparison"
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy; extra == "dev"
|
|
40
|
+
Requires-Dist: scipy-stubs; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# holonomy_lib
|
|
44
|
+
|
|
45
|
+
Geometry, graph and topology primitives for PyTorch. Most functions take a batch
|
|
46
|
+
of inputs (a leading batch dimension) and run on the device and dtype you pass in.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
Python 3.12 or later. Install PyTorch for your hardware first, using the
|
|
51
|
+
[PyTorch selector](https://pytorch.org/get-started/locally/), then:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install holonomy-lib
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Example
|
|
58
|
+
|
|
59
|
+
Effective resistance between the ends of a three-node path and of a triangle,
|
|
60
|
+
computed as one batch:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import torch
|
|
64
|
+
from holonomy_lib.spectral import effective_resistance
|
|
65
|
+
|
|
66
|
+
device = "cuda" if torch.cuda.is_available() else "cpu" # ROCm builds also use "cuda"
|
|
67
|
+
adjacency = torch.tensor([
|
|
68
|
+
[[0, 1, 0], [1, 0, 1], [0, 1, 0]], # path 0-1-2
|
|
69
|
+
[[0, 1, 1], [1, 0, 1], [1, 1, 0]], # triangle
|
|
70
|
+
], dtype=torch.float64, device=device)
|
|
71
|
+
|
|
72
|
+
R = effective_resistance(adjacency)
|
|
73
|
+
print(R.shape) # torch.Size([2, 3, 3])
|
|
74
|
+
print(R[:, 0, 2]) # tensor([2.0000, 0.6667], dtype=torch.float64)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## What's in it
|
|
78
|
+
|
|
79
|
+
[CONTENTS.md](https://github.com/Synoros-io/holonomy_lib/blob/master/CONTENTS.md) lists every function with its signature and the
|
|
80
|
+
paper it implements.
|
|
81
|
+
|
|
82
|
+
| Subpackage | Contents |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `manifolds` | Fixed-rank, SPD, Lorentz, Lorentzian, stereographic and product manifolds; model-space volumes. |
|
|
85
|
+
| `optimization` | Riemannian SGD. |
|
|
86
|
+
| `hyperbolic` | Fréchet means, manifold-aware inner products, hyperbolic heat kernels. |
|
|
87
|
+
| `lie` | SO(3) exponential and logarithm, rotations, real spherical harmonics. |
|
|
88
|
+
| `info_geometry` | Bregman and KL divergences, Fisher information, natural gradients. |
|
|
89
|
+
| `tensor_calculus` | Mode unfolding, mode products, HOSVD. |
|
|
90
|
+
| `algebra` | Truncated SVD, dense and sparse eigensolvers, conjugate gradient, LSQR. |
|
|
91
|
+
| `convex` | Regularized least squares. |
|
|
92
|
+
| `spectral` | Graph Laplacians, embeddings, heat diffusion, effective resistance, spectral dimension. |
|
|
93
|
+
| `discrete_geometry` | Ollivier and Forman curvature, Ricci flow with surgery. |
|
|
94
|
+
| `sheaf` | Graph sheaves, coboundaries, sheaf Laplacians and their spectra. |
|
|
95
|
+
| `simplicial` | Dense and sparse simplicial complexes, boundary operators, Vietoris-Rips. |
|
|
96
|
+
| `topology` | Hodge Laplacians, Betti numbers, persistent homology. |
|
|
97
|
+
|
|
98
|
+
## Explorer
|
|
99
|
+
|
|
100
|
+
`holonomy-explorer` opens a local page that runs the library live: curvature
|
|
101
|
+
and diffusion on graphs, geodesics as curvature passes through zero,
|
|
102
|
+
persistent homology of point clouds, and batch-size timings on your hardware.
|
|
103
|
+
Options: `--device`, `--dtype`, `--port`, `--no-browser`.
|
|
104
|
+
|
|
105
|
+

|
|
106
|
+
|
|
107
|
+
## Experimental
|
|
108
|
+
|
|
109
|
+
`holonomy_lib.experimental` holds two unfinished pieces that are not part of
|
|
110
|
+
the stable API:
|
|
111
|
+
|
|
112
|
+
- `hyperbolic_laplacian_eigenmaps`: nothing in its objective keeps nodes apart,
|
|
113
|
+
so an embedding can collapse to a point.
|
|
114
|
+
- `HeterogeneousKappaManifold`: a curvature per point. Its `dissimilarity` is
|
|
115
|
+
not a metric.
|
|
116
|
+
|
|
117
|
+
## Limits
|
|
118
|
+
|
|
119
|
+
- Use `float64` when accuracy matters.
|
|
120
|
+
- Sparse eigensolvers, sparse simplicial complexes and sheaves handle one
|
|
121
|
+
instance at a time. Sparse eigensolvers are not differentiable.
|
|
122
|
+
- Persistent homology runs its reduction one batch member at a time on the CPU.
|
|
123
|
+
- Ollivier curvature uses entropy-regularized transport, so it is close to the
|
|
124
|
+
exact value rather than equal to it, and it warns if the solver did not
|
|
125
|
+
converge. Edge weights act as both lengths and random-walk weights.
|
|
126
|
+
- Gradients through `cg` can be wrong when it converges in very few iterations.
|
|
127
|
+
- Effective resistance and commute time are `inf` between disconnected components.
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
uv sync --extra dev
|
|
133
|
+
python -m pytest -q
|
|
134
|
+
python -m ruff check src/ tests/
|
|
135
|
+
python -m mypy src/
|
|
136
|
+
python tools/audit.py src/holonomy_lib --strict
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
[CONVENTIONS.md](https://github.com/Synoros-io/holonomy_lib/blob/master/CONVENTIONS.md) has the coding and numerical rules;
|
|
140
|
+
[CHANGELOG.md](https://github.com/Synoros-io/holonomy_lib/blob/master/CHANGELOG.md) has the release history.
|
|
141
|
+
|
|
142
|
+
## Citation
|
|
143
|
+
|
|
144
|
+
```bibtex
|
|
145
|
+
@software{holonomy_lib,
|
|
146
|
+
author = {John Vaught},
|
|
147
|
+
title = {holonomy\_lib: Batched PyTorch primitives for geometry and topology},
|
|
148
|
+
version = {0.8.0},
|
|
149
|
+
year = {2026},
|
|
150
|
+
url = {https://github.com/Synoros-io/holonomy_lib},
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Please also cite the papers named in the docstrings of the functions you use.
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
[FSL-1.1-ALv2](https://github.com/Synoros-io/holonomy_lib/blob/master/LICENSE.md). You can use and modify it freely; competing
|
|
159
|
+
commercial use is reserved to Synoros. Each release becomes Apache-2.0 two
|
|
160
|
+
years after it ships. Releases up to 0.7.0 remain AGPL-3.0-or-later. For other
|
|
161
|
+
terms, contact [contact@synoros.io](mailto:contact@synoros.io).
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# holonomy_lib
|
|
2
|
+
|
|
3
|
+
Geometry, graph and topology primitives for PyTorch. Most functions take a batch
|
|
4
|
+
of inputs (a leading batch dimension) and run on the device and dtype you pass in.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
Python 3.12 or later. Install PyTorch for your hardware first, using the
|
|
9
|
+
[PyTorch selector](https://pytorch.org/get-started/locally/), then:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install holonomy-lib
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
Effective resistance between the ends of a three-node path and of a triangle,
|
|
18
|
+
computed as one batch:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import torch
|
|
22
|
+
from holonomy_lib.spectral import effective_resistance
|
|
23
|
+
|
|
24
|
+
device = "cuda" if torch.cuda.is_available() else "cpu" # ROCm builds also use "cuda"
|
|
25
|
+
adjacency = torch.tensor([
|
|
26
|
+
[[0, 1, 0], [1, 0, 1], [0, 1, 0]], # path 0-1-2
|
|
27
|
+
[[0, 1, 1], [1, 0, 1], [1, 1, 0]], # triangle
|
|
28
|
+
], dtype=torch.float64, device=device)
|
|
29
|
+
|
|
30
|
+
R = effective_resistance(adjacency)
|
|
31
|
+
print(R.shape) # torch.Size([2, 3, 3])
|
|
32
|
+
print(R[:, 0, 2]) # tensor([2.0000, 0.6667], dtype=torch.float64)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What's in it
|
|
36
|
+
|
|
37
|
+
[CONTENTS.md](https://github.com/Synoros-io/holonomy_lib/blob/master/CONTENTS.md) lists every function with its signature and the
|
|
38
|
+
paper it implements.
|
|
39
|
+
|
|
40
|
+
| Subpackage | Contents |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `manifolds` | Fixed-rank, SPD, Lorentz, Lorentzian, stereographic and product manifolds; model-space volumes. |
|
|
43
|
+
| `optimization` | Riemannian SGD. |
|
|
44
|
+
| `hyperbolic` | Fréchet means, manifold-aware inner products, hyperbolic heat kernels. |
|
|
45
|
+
| `lie` | SO(3) exponential and logarithm, rotations, real spherical harmonics. |
|
|
46
|
+
| `info_geometry` | Bregman and KL divergences, Fisher information, natural gradients. |
|
|
47
|
+
| `tensor_calculus` | Mode unfolding, mode products, HOSVD. |
|
|
48
|
+
| `algebra` | Truncated SVD, dense and sparse eigensolvers, conjugate gradient, LSQR. |
|
|
49
|
+
| `convex` | Regularized least squares. |
|
|
50
|
+
| `spectral` | Graph Laplacians, embeddings, heat diffusion, effective resistance, spectral dimension. |
|
|
51
|
+
| `discrete_geometry` | Ollivier and Forman curvature, Ricci flow with surgery. |
|
|
52
|
+
| `sheaf` | Graph sheaves, coboundaries, sheaf Laplacians and their spectra. |
|
|
53
|
+
| `simplicial` | Dense and sparse simplicial complexes, boundary operators, Vietoris-Rips. |
|
|
54
|
+
| `topology` | Hodge Laplacians, Betti numbers, persistent homology. |
|
|
55
|
+
|
|
56
|
+
## Explorer
|
|
57
|
+
|
|
58
|
+
`holonomy-explorer` opens a local page that runs the library live: curvature
|
|
59
|
+
and diffusion on graphs, geodesics as curvature passes through zero,
|
|
60
|
+
persistent homology of point clouds, and batch-size timings on your hardware.
|
|
61
|
+
Options: `--device`, `--dtype`, `--port`, `--no-browser`.
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
## Experimental
|
|
66
|
+
|
|
67
|
+
`holonomy_lib.experimental` holds two unfinished pieces that are not part of
|
|
68
|
+
the stable API:
|
|
69
|
+
|
|
70
|
+
- `hyperbolic_laplacian_eigenmaps`: nothing in its objective keeps nodes apart,
|
|
71
|
+
so an embedding can collapse to a point.
|
|
72
|
+
- `HeterogeneousKappaManifold`: a curvature per point. Its `dissimilarity` is
|
|
73
|
+
not a metric.
|
|
74
|
+
|
|
75
|
+
## Limits
|
|
76
|
+
|
|
77
|
+
- Use `float64` when accuracy matters.
|
|
78
|
+
- Sparse eigensolvers, sparse simplicial complexes and sheaves handle one
|
|
79
|
+
instance at a time. Sparse eigensolvers are not differentiable.
|
|
80
|
+
- Persistent homology runs its reduction one batch member at a time on the CPU.
|
|
81
|
+
- Ollivier curvature uses entropy-regularized transport, so it is close to the
|
|
82
|
+
exact value rather than equal to it, and it warns if the solver did not
|
|
83
|
+
converge. Edge weights act as both lengths and random-walk weights.
|
|
84
|
+
- Gradients through `cg` can be wrong when it converges in very few iterations.
|
|
85
|
+
- Effective resistance and commute time are `inf` between disconnected components.
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv sync --extra dev
|
|
91
|
+
python -m pytest -q
|
|
92
|
+
python -m ruff check src/ tests/
|
|
93
|
+
python -m mypy src/
|
|
94
|
+
python tools/audit.py src/holonomy_lib --strict
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
[CONVENTIONS.md](https://github.com/Synoros-io/holonomy_lib/blob/master/CONVENTIONS.md) has the coding and numerical rules;
|
|
98
|
+
[CHANGELOG.md](https://github.com/Synoros-io/holonomy_lib/blob/master/CHANGELOG.md) has the release history.
|
|
99
|
+
|
|
100
|
+
## Citation
|
|
101
|
+
|
|
102
|
+
```bibtex
|
|
103
|
+
@software{holonomy_lib,
|
|
104
|
+
author = {John Vaught},
|
|
105
|
+
title = {holonomy\_lib: Batched PyTorch primitives for geometry and topology},
|
|
106
|
+
version = {0.8.0},
|
|
107
|
+
year = {2026},
|
|
108
|
+
url = {https://github.com/Synoros-io/holonomy_lib},
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Please also cite the papers named in the docstrings of the functions you use.
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
[FSL-1.1-ALv2](https://github.com/Synoros-io/holonomy_lib/blob/master/LICENSE.md). You can use and modify it freely; competing
|
|
117
|
+
commercial use is reserved to Synoros. Each release becomes Apache-2.0 two
|
|
118
|
+
years after it ships. Releases up to 0.7.0 remain AGPL-3.0-or-later. For other
|
|
119
|
+
terms, contact [contact@synoros.io](mailto:contact@synoros.io).
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "holonomy-lib"
|
|
3
|
+
version = "0.8.0"
|
|
4
|
+
description = "Batched PyTorch primitives for Riemannian geometry, spectral graph theory, discrete curvature, topology, and tensor decompositions."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "FSL-1.1-ALv2"
|
|
7
|
+
license-files = ["LICENSE.md"]
|
|
8
|
+
authors = [{ name = "Synoros" }]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
keywords = [
|
|
11
|
+
"pytorch",
|
|
12
|
+
"differential-geometry",
|
|
13
|
+
"riemannian-manifolds",
|
|
14
|
+
"hyperbolic-geometry",
|
|
15
|
+
"riemannian-optimization",
|
|
16
|
+
"spectral-graph-theory",
|
|
17
|
+
"graph-laplacian",
|
|
18
|
+
"magnetic-laplacian",
|
|
19
|
+
"heat-kernel",
|
|
20
|
+
"diffusion-maps",
|
|
21
|
+
"effective-resistance",
|
|
22
|
+
"ricci-curvature",
|
|
23
|
+
"ricci-flow",
|
|
24
|
+
"cellular-sheaves",
|
|
25
|
+
"simplicial-complex",
|
|
26
|
+
"hodge-laplacian",
|
|
27
|
+
"persistent-homology",
|
|
28
|
+
"topological-data-analysis",
|
|
29
|
+
"information-geometry",
|
|
30
|
+
"tensor-decomposition",
|
|
31
|
+
"numerical-linear-algebra",
|
|
32
|
+
]
|
|
33
|
+
classifiers = [
|
|
34
|
+
"Development Status :: 4 - Beta",
|
|
35
|
+
"Intended Audience :: Science/Research",
|
|
36
|
+
"Operating System :: OS Independent",
|
|
37
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
38
|
+
"Programming Language :: Python :: 3.12",
|
|
39
|
+
"Programming Language :: Python :: 3.13",
|
|
40
|
+
"Programming Language :: Python :: 3.14",
|
|
41
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
42
|
+
"Typing :: Typed",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
# The floors are the first releases that ship Python 3.12 wheels; nothing in
|
|
46
|
+
# the source needs anything newer. torch decides the hardware: pip picks the
|
|
47
|
+
# default CUDA wheel, so for ROCm, a specific CUDA version or CPU-only, install
|
|
48
|
+
# torch first from https://pytorch.org/get-started/locally/ and pip will keep it.
|
|
49
|
+
dependencies = [
|
|
50
|
+
"torch>=2.2",
|
|
51
|
+
"numpy>=1.26",
|
|
52
|
+
"scipy>=1.11.2",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[project.urls]
|
|
56
|
+
Homepage = "https://github.com/Synoros-io/holonomy_lib"
|
|
57
|
+
Repository = "https://github.com/Synoros-io/holonomy_lib"
|
|
58
|
+
Issues = "https://github.com/Synoros-io/holonomy_lib/issues"
|
|
59
|
+
|
|
60
|
+
[project.scripts]
|
|
61
|
+
holonomy-explorer = "holonomy_explorer.__main__:main"
|
|
62
|
+
|
|
63
|
+
[tool.setuptools.package-data]
|
|
64
|
+
holonomy_explorer = ["static/*"]
|
|
65
|
+
|
|
66
|
+
[project.optional-dependencies]
|
|
67
|
+
# Libraries the cross-check tests compare against. None of them are needed at
|
|
68
|
+
# runtime; each comparison test skips itself when its library is missing.
|
|
69
|
+
comparison = [
|
|
70
|
+
"pymanopt",
|
|
71
|
+
"geoopt",
|
|
72
|
+
"geomstats",
|
|
73
|
+
"autograd",
|
|
74
|
+
"tensorly",
|
|
75
|
+
"networkx",
|
|
76
|
+
"gudhi",
|
|
77
|
+
"ripser",
|
|
78
|
+
"GraphRicciCurvature",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
# Development toolchain: tests, lint, type checks (with SciPy's stubs so mypy
|
|
82
|
+
# can see through the sparse and quadrature fallbacks).
|
|
83
|
+
dev = ["pytest", "ruff", "mypy", "scipy-stubs"]
|
|
84
|
+
|
|
85
|
+
[build-system]
|
|
86
|
+
requires = ["setuptools>=77"]
|
|
87
|
+
build-backend = "setuptools.build_meta"
|
|
88
|
+
|
|
89
|
+
[tool.setuptools.packages.find]
|
|
90
|
+
where = ["src"]
|
|
91
|
+
|
|
92
|
+
[tool.pytest.ini_options]
|
|
93
|
+
testpaths = ["tests"]
|
|
94
|
+
|
|
95
|
+
[tool.ruff]
|
|
96
|
+
target-version = "py312"
|
|
97
|
+
extend-exclude = [".scratch", "archive", "notes"]
|
|
98
|
+
|
|
99
|
+
[tool.ruff.lint]
|
|
100
|
+
select = ["E", "F", "W", "I", "UP", "B"]
|
|
101
|
+
|
|
102
|
+
[tool.mypy]
|
|
103
|
+
python_version = "3.12"
|
|
104
|
+
files = ["src"]
|
|
105
|
+
check_untyped_defs = true
|
|
106
|
+
warn_unused_ignores = true
|
|
107
|
+
warn_redundant_casts = true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Local, offline views of computations performed by holonomy_lib."""
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Launch with holonomy-explorer or python -m holonomy_explorer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
import webbrowser
|
|
8
|
+
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
from .common import Context
|
|
12
|
+
from .server import create_server
|
|
13
|
+
|
|
14
|
+
# Local-only defaults requested by the explorer brief; every deployment can override.
|
|
15
|
+
DEFAULT_HOST = "127.0.0.1"
|
|
16
|
+
WILDCARD_HOST = "0.0.0.0" # IPv4 bind-all address; browse via loopback instead.
|
|
17
|
+
DEFAULT_PORT = 8765
|
|
18
|
+
DEFAULT_DTYPE = "float64"
|
|
19
|
+
MAX_PORT = 65535 # TCP port field is an unsigned 16-bit integer.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main() -> None:
|
|
23
|
+
"""Parse deployment settings, print the bound URL, and serve until Ctrl-C."""
|
|
24
|
+
parser = argparse.ArgumentParser(
|
|
25
|
+
description="Local holonomy_lib explorer. Offline UI; CPU/CUDA tensors.",
|
|
26
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--host",
|
|
30
|
+
default=os.getenv("HOLONOMY_EXPLORER_HOST", DEFAULT_HOST),
|
|
31
|
+
help="bind address; env HOLONOMY_EXPLORER_HOST",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--port",
|
|
35
|
+
type=int,
|
|
36
|
+
default=os.getenv("HOLONOMY_EXPLORER_PORT", str(DEFAULT_PORT)),
|
|
37
|
+
help="TCP port, 0 chooses a free port; env HOLONOMY_EXPLORER_PORT",
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--device",
|
|
41
|
+
default=os.getenv(
|
|
42
|
+
"HOLONOMY_EXPLORER_DEVICE",
|
|
43
|
+
"cuda" if torch.cuda.is_available() else "cpu",
|
|
44
|
+
),
|
|
45
|
+
help="torch device; env HOLONOMY_EXPLORER_DEVICE; ROCm also uses cuda",
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--dtype",
|
|
49
|
+
choices=("float32", "float64"),
|
|
50
|
+
default=os.getenv("HOLONOMY_EXPLORER_DTYPE", DEFAULT_DTYPE),
|
|
51
|
+
help="tensor precision; env HOLONOMY_EXPLORER_DTYPE",
|
|
52
|
+
)
|
|
53
|
+
parser.add_argument(
|
|
54
|
+
"--no-browser", action="store_true", help="print URL without opening a browser"
|
|
55
|
+
)
|
|
56
|
+
args = parser.parse_args()
|
|
57
|
+
if not 0 <= args.port <= MAX_PORT:
|
|
58
|
+
parser.error(f"port must be between 0 and {MAX_PORT}")
|
|
59
|
+
try:
|
|
60
|
+
context = Context.from_request({"device": args.device, "dtype": args.dtype})
|
|
61
|
+
server = create_server(args.host, args.port, str(context.device), args.dtype)
|
|
62
|
+
except (OSError, ValueError, RuntimeError) as error:
|
|
63
|
+
parser.error(str(error))
|
|
64
|
+
# Wildcard bindings are not navigable destinations; loopback reaches this server.
|
|
65
|
+
browser_host = DEFAULT_HOST if args.host == WILDCARD_HOST else args.host
|
|
66
|
+
url = f"http://{browser_host}:{server.server_address[1]}"
|
|
67
|
+
print(f"Holonomy explorer: {url} ({context.device}, {args.dtype})", flush=True)
|
|
68
|
+
if not args.no_browser:
|
|
69
|
+
webbrowser.open(url)
|
|
70
|
+
try:
|
|
71
|
+
server.serve_forever()
|
|
72
|
+
except KeyboardInterrupt:
|
|
73
|
+
pass
|
|
74
|
+
finally:
|
|
75
|
+
server.server_close()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
main()
|