groupoid 0.1.0.dev6__tar.gz → 0.1.0.dev8__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.
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/dependabot.yml +0 -1
- groupoid-0.1.0.dev8/.github/workflows/artifact-transfer.yml +46 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/workflows/ci.yml +43 -38
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/workflows/docs-deploy.yml +1 -2
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/workflows/release.yml +18 -12
- groupoid-0.1.0.dev8/.zenodo.json +34 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/CHANGELOG.md +49 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/CITATION.cff +2 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/CONTRIBUTING.md +8 -6
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/LIMITATIONS.md +18 -7
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/PKG-INFO +12 -9
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/README.md +10 -5
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/REPRODUCE.md +2 -1
- groupoid-0.1.0.dev8/SECURITY.md +31 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/STATUS.md +7 -5
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/codemeta.json +1 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/docs/index.md +1 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/docs/quickstart.md +2 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/__init__.py +1 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/persistence.py +25 -12
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid.egg-info/PKG-INFO +12 -9
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid.egg-info/SOURCES.txt +1 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid.egg-info/requires.txt +0 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/pyproject.toml +7 -7
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/scripts/reproduce_sheaf_laplacian.py +1 -1
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_persistence.py +22 -10
- groupoid-0.1.0.dev6/.github/scripts/install_torch_cpu.sh +0 -25
- groupoid-0.1.0.dev6/.zenodo.json +0 -39
- groupoid-0.1.0.dev6/SECURITY.md +0 -43
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/ISSUE_TEMPLATE/mathematical_correction.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.github/workflows/auto-tag-release.yml +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.gitignore +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/.pre-commit-config.yaml +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/CORRECTION_NOTICE.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/LICENSE +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/PROBLEMS.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/benchmarks/__init__.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/benchmarks/conftest.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/benchmarks/test_karcher_benchmark.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/docs/api.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/docs/overrides/404.html +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/docs/theory.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/examples/README.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/examples/__init__.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/examples/synthetic_curve_demo.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/experiments/PREREGISTRATION.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/experiments/README.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/experiments/RESULTS.md +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/experiments/analyze.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/experiments/results.json +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/experiments/run_benchmark.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/aggregation.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/cohomology.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/groupoid.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/laplacian.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/manifold.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/optimizer.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/sheaf.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid/transport.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid.egg-info/dependency_links.txt +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/groupoid.egg-info/top_level.txt +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/mkdocs.yml +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/scripts/bind_release_sbom.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/setup.cfg +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/__init__.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_aggregation_disconnected.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_audit_regressions.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_cohomology_cocycle.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_coverage_gaps.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_defensive_paths.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_imports.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_integration.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_optimizer_validation.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_persistence_dimension_labels.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_pipeline_integration.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_release_sbom_binding.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_release_workflow_integrity.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_scientific_corrections.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_sheaf_laplacian.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_smoke.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/test_transport_validation.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/theory/__init__.py +0 -0
- {groupoid-0.1.0.dev6 → groupoid-0.1.0.dev8}/tests/theory/test_mathematical_invariants.py +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Artifact transfer integrity
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths: [".github/workflows/**"]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
paths: [".github/workflows/**"]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
round-trip:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
timeout-minutes: 5
|
|
18
|
+
steps:
|
|
19
|
+
- name: Create fixture and independent expected checksum
|
|
20
|
+
shell: bash
|
|
21
|
+
run: |
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
mkdir -p payload/nested
|
|
24
|
+
printf '%s\n' "$GITHUB_SHA" > payload/nested/fixture.txt
|
|
25
|
+
(cd payload && sha256sum nested/fixture.txt) > expected.sha256
|
|
26
|
+
- name: Upload fixture
|
|
27
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
28
|
+
with:
|
|
29
|
+
name: artifact-transfer-proof
|
|
30
|
+
path: payload/
|
|
31
|
+
if-no-files-found: error
|
|
32
|
+
retention-days: 1
|
|
33
|
+
- name: Remove original fixture before downloading
|
|
34
|
+
run: rm -r payload
|
|
35
|
+
- name: Download fixture
|
|
36
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
37
|
+
with:
|
|
38
|
+
name: artifact-transfer-proof
|
|
39
|
+
path: restored/
|
|
40
|
+
- name: Verify restored bytes and directory layout
|
|
41
|
+
shell: bash
|
|
42
|
+
run: |
|
|
43
|
+
set -euo pipefail
|
|
44
|
+
cd restored
|
|
45
|
+
test "$(find . -type f | wc -l)" -eq 1
|
|
46
|
+
sha256sum --check ../expected.sha256
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
16
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
17
|
-
- uses: actions/setup-python@
|
|
17
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
18
18
|
with:
|
|
19
19
|
python-version: "3.11"
|
|
20
20
|
- name: Install dependencies
|
|
@@ -24,8 +24,8 @@ jobs:
|
|
|
24
24
|
# numpy / pydantic stubs (NDArray dtype args, the BaseModel base class).
|
|
25
25
|
# Linting only against `ruff black mypy` left numpy/pydantic uninstalled,
|
|
26
26
|
# so --strict raised disallow_subclassing_any on the BaseModel subclass.
|
|
27
|
-
#
|
|
28
|
-
.
|
|
27
|
+
# All jobs now install the declared runtime dependencies, without
|
|
28
|
+
# the unused optional PyTorch backend.
|
|
29
29
|
pip install -e ".[dev]"
|
|
30
30
|
- name: Run ruff
|
|
31
31
|
run: ruff check .
|
|
@@ -34,20 +34,44 @@ jobs:
|
|
|
34
34
|
- name: Run mypy (strict)
|
|
35
35
|
run: mypy --strict groupoid/ --ignore-missing-imports
|
|
36
36
|
|
|
37
|
+
# Retain the protected-main historical check name while making its semantics
|
|
38
|
+
# a negative compatibility test. It proves that Python 3.10 is REJECTED;
|
|
39
|
+
# supported functional tests run only on Python 3.11 and 3.12 above.
|
|
40
|
+
unsupported-python310:
|
|
41
|
+
name: test (3.10)
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
45
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.10"
|
|
48
|
+
- name: Verify unsupported interpreter is rejected by package metadata
|
|
49
|
+
run: |
|
|
50
|
+
set -euo pipefail
|
|
51
|
+
if python -m pip install --no-deps . > /tmp/unsupported-python.log 2>&1; then
|
|
52
|
+
cat /tmp/unsupported-python.log
|
|
53
|
+
echo "::error::Python 3.10 installation unexpectedly succeeded"
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
if ! grep -Eqi "requires a different Python|requires-python|requires Python" /tmp/unsupported-python.log; then
|
|
57
|
+
cat /tmp/unsupported-python.log
|
|
58
|
+
echo "::error::Installation failed for an unexpected reason"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
37
62
|
test:
|
|
38
63
|
runs-on: ubuntu-latest
|
|
39
64
|
strategy:
|
|
40
65
|
matrix:
|
|
41
|
-
python-version: ["3.
|
|
66
|
+
python-version: ["3.11", "3.12"]
|
|
42
67
|
steps:
|
|
43
68
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
44
|
-
- uses: actions/setup-python@
|
|
69
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
45
70
|
with:
|
|
46
71
|
python-version: ${{ matrix.python-version }}
|
|
47
72
|
- name: Install dependencies
|
|
48
73
|
run: |
|
|
49
74
|
python -m pip install --upgrade pip
|
|
50
|
-
.github/scripts/install_torch_cpu.sh
|
|
51
75
|
pip install -e ".[dev]"
|
|
52
76
|
- name: Run tests with coverage gate
|
|
53
77
|
run: >-
|
|
@@ -59,7 +83,7 @@ jobs:
|
|
|
59
83
|
runs-on: ubuntu-latest
|
|
60
84
|
steps:
|
|
61
85
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
62
|
-
- uses: actions/setup-python@
|
|
86
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
63
87
|
with:
|
|
64
88
|
python-version: "3.11"
|
|
65
89
|
- name: Install dependencies
|
|
@@ -68,42 +92,25 @@ jobs:
|
|
|
68
92
|
# Install the project's real runtime closure so pip-audit scans the
|
|
69
93
|
# packages GROUPOID actually depends on. The previous `safety` step
|
|
70
94
|
# installed only the tools and never the project, so it audited the
|
|
71
|
-
# wrong environment.
|
|
72
|
-
.github/scripts/install_torch_cpu.sh
|
|
95
|
+
# wrong environment. No unused PyTorch install is injected.
|
|
73
96
|
pip install -e .
|
|
74
97
|
pip install bandit pip-audit
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# dependency-consistent with torch (verified: pip check clean).
|
|
80
|
-
python -m pip install --upgrade "setuptools>=78.1.1,<82"
|
|
98
|
+
# Setuptools is build tooling, but remains in the audited CI environment.
|
|
99
|
+
# No torch<82 constraint remains; require the patched release.
|
|
100
|
+
python -m pip install --upgrade "setuptools>=84.1.0"
|
|
101
|
+
python -m pip check
|
|
81
102
|
- name: Run bandit
|
|
82
103
|
run: bandit -r groupoid/ -c pyproject.toml
|
|
83
104
|
- name: Audit dependencies for known vulnerabilities (pip-audit)
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
|
|
87
|
-
# exceptions, both disclosed in SECURITY.md:
|
|
88
|
-
# - CVE-2025-3000 (torch): no fixed release exists upstream, and OSV
|
|
89
|
-
# expresses the affected range (listed versions up to v2.6.0) as a
|
|
90
|
-
# Git/commit boundary pip-audit cannot version-resolve, so it
|
|
91
|
-
# conservatively flags the installed torch. The torch.load / JIT
|
|
92
|
-
# deserialization path is not exercised by GROUPOID. Revisit the ignore
|
|
93
|
-
# once upstream publishes a fixed release.
|
|
94
|
-
# - PYSEC-2026-3447 (CVE-2026-59890, setuptools <83): the fix (83.0.0) is
|
|
95
|
-
# unreachable while torch requires setuptools<82 (see the install step
|
|
96
|
-
# above). The flaw is a macOS-only (APFS/HFS+) Unicode-normalization
|
|
97
|
-
# bypass of MANIFEST.in exclude rules when building sdists; all CI and
|
|
98
|
-
# release builds run on ubuntu-latest. Drop the ignore once torch
|
|
99
|
-
# permits setuptools>=83.
|
|
100
|
-
run: pip-audit --ignore-vuln CVE-2025-3000 --ignore-vuln PYSEC-2026-3447
|
|
105
|
+
# Hard gate on the installed runtime and audit-tool closure.
|
|
106
|
+
# No CVE/PYSEC ignore flags or waived vulnerable packages.
|
|
107
|
+
run: pip-audit
|
|
101
108
|
|
|
102
109
|
pre-commit:
|
|
103
110
|
runs-on: ubuntu-latest
|
|
104
111
|
steps:
|
|
105
112
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
106
|
-
- uses: actions/setup-python@
|
|
113
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
107
114
|
with:
|
|
108
115
|
python-version: "3.11"
|
|
109
116
|
- name: Install pre-commit
|
|
@@ -115,13 +122,12 @@ jobs:
|
|
|
115
122
|
runs-on: ubuntu-latest
|
|
116
123
|
steps:
|
|
117
124
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
118
|
-
- uses: actions/setup-python@
|
|
125
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
119
126
|
with:
|
|
120
127
|
python-version: "3.11"
|
|
121
128
|
- name: Install dependencies
|
|
122
129
|
run: |
|
|
123
130
|
python -m pip install --upgrade pip
|
|
124
|
-
.github/scripts/install_torch_cpu.sh
|
|
125
131
|
pip install -e ".[dev]"
|
|
126
132
|
# Benchmarks run for information only. There is no regression gate:
|
|
127
133
|
# timing baselines recorded on one machine are not comparable to a
|
|
@@ -135,7 +141,7 @@ jobs:
|
|
|
135
141
|
pytest benchmarks/ -v --benchmark-json=benchmark_results.json || true
|
|
136
142
|
- name: Upload benchmark results
|
|
137
143
|
if: always()
|
|
138
|
-
uses: actions/upload-artifact@
|
|
144
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
139
145
|
with:
|
|
140
146
|
name: benchmark-results
|
|
141
147
|
path: benchmark_results.json
|
|
@@ -145,13 +151,12 @@ jobs:
|
|
|
145
151
|
runs-on: ubuntu-latest
|
|
146
152
|
steps:
|
|
147
153
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
148
|
-
- uses: actions/setup-python@
|
|
154
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
149
155
|
with:
|
|
150
156
|
python-version: "3.11"
|
|
151
157
|
- name: Install dependencies
|
|
152
158
|
run: |
|
|
153
159
|
python -m pip install --upgrade pip
|
|
154
|
-
.github/scripts/install_torch_cpu.sh
|
|
155
160
|
pip install -e ".[docs]"
|
|
156
161
|
- name: Build docs
|
|
157
162
|
run: mkdocs build --strict
|
|
@@ -17,13 +17,12 @@ jobs:
|
|
|
17
17
|
runs-on: ubuntu-latest
|
|
18
18
|
steps:
|
|
19
19
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
|
-
- uses: actions/setup-python@
|
|
20
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
21
21
|
with:
|
|
22
22
|
python-version: "3.11"
|
|
23
23
|
- name: Install dependencies
|
|
24
24
|
run: |
|
|
25
25
|
python -m pip install --upgrade pip
|
|
26
|
-
.github/scripts/install_torch_cpu.sh
|
|
27
26
|
pip install -e ".[docs]"
|
|
28
27
|
- name: Build docs
|
|
29
28
|
run: mkdocs build --strict
|
|
@@ -145,7 +145,7 @@ jobs:
|
|
|
145
145
|
exit 1
|
|
146
146
|
fi
|
|
147
147
|
echo "release target ${RELEASE_TARGET} matches pyproject version ${version}"
|
|
148
|
-
- uses: actions/setup-python@
|
|
148
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
149
149
|
with:
|
|
150
150
|
python-version: "3.12"
|
|
151
151
|
cache: pip
|
|
@@ -283,7 +283,7 @@ jobs:
|
|
|
283
283
|
with:
|
|
284
284
|
subject-path: "dist/*"
|
|
285
285
|
- name: Upload dist artifacts
|
|
286
|
-
uses: actions/upload-artifact@
|
|
286
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
287
287
|
with:
|
|
288
288
|
name: release-dist
|
|
289
289
|
path: dist/
|
|
@@ -300,11 +300,11 @@ jobs:
|
|
|
300
300
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
301
301
|
with:
|
|
302
302
|
ref: ${{ github.event.inputs.ref || github.ref }}
|
|
303
|
-
- uses: actions/setup-python@
|
|
303
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
304
304
|
with:
|
|
305
305
|
python-version: "3.12"
|
|
306
306
|
cache: pip
|
|
307
|
-
- uses: actions/download-artifact@
|
|
307
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
308
308
|
with:
|
|
309
309
|
name: release-dist
|
|
310
310
|
path: dist
|
|
@@ -347,7 +347,7 @@ jobs:
|
|
|
347
347
|
fi
|
|
348
348
|
python scripts/bind_release_sbom.py --verify-only --sbom sbom.cdx.json --wheel "${wheels[0]}"
|
|
349
349
|
- name: Upload SBOM artifact
|
|
350
|
-
uses: actions/upload-artifact@
|
|
350
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
351
351
|
with:
|
|
352
352
|
name: release-sbom
|
|
353
353
|
path: sbom.cdx.json
|
|
@@ -365,11 +365,11 @@ jobs:
|
|
|
365
365
|
id-token: write # attestation OIDC
|
|
366
366
|
attestations: write # actions/attest
|
|
367
367
|
steps:
|
|
368
|
-
- uses: actions/download-artifact@
|
|
368
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
369
369
|
with:
|
|
370
370
|
name: release-dist
|
|
371
371
|
path: dist
|
|
372
|
-
- uses: actions/download-artifact@
|
|
372
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
373
373
|
with:
|
|
374
374
|
name: release-sbom
|
|
375
375
|
path: .
|
|
@@ -407,7 +407,7 @@ jobs:
|
|
|
407
407
|
name: pypi
|
|
408
408
|
url: https://pypi.org/project/groupoid/
|
|
409
409
|
steps:
|
|
410
|
-
- uses: actions/download-artifact@
|
|
410
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
411
411
|
with:
|
|
412
412
|
name: release-dist
|
|
413
413
|
path: dist
|
|
@@ -479,7 +479,7 @@ jobs:
|
|
|
479
479
|
# step below still runs, so COMPLETE still proves PyPI is correct.
|
|
480
480
|
- name: Publish to PyPI (Trusted Publishing, OIDC)
|
|
481
481
|
if: needs.build.outputs.adopted != 'true'
|
|
482
|
-
uses: pypa/gh-action-pypi-publish@
|
|
482
|
+
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
|
|
483
483
|
with:
|
|
484
484
|
packages-dir: dist
|
|
485
485
|
print-hash: true
|
|
@@ -501,8 +501,14 @@ jobs:
|
|
|
501
501
|
import hashlib, json, pathlib, sys, time, urllib.error, urllib.request
|
|
502
502
|
|
|
503
503
|
dist = pathlib.Path("dist")
|
|
504
|
+
# PEP 740 .publish.attestation sidecars may be written to dist/ by
|
|
505
|
+
# the PyPI publishing action. They are attestations attached to the
|
|
506
|
+
# distributions, not separate package files in PyPI JSON urls.
|
|
507
|
+
# Compare every actual wheel/sdist byte without treating sidecars
|
|
508
|
+
# as missing distributions.
|
|
504
509
|
local = {p.name: hashlib.sha256(p.read_bytes()).hexdigest()
|
|
505
|
-
for p in sorted(dist.iterdir())
|
|
510
|
+
for p in sorted(dist.iterdir())
|
|
511
|
+
if p.is_file() and p.name.endswith((".whl", ".tar.gz"))}
|
|
506
512
|
wheel = next(n for n in local if n.endswith(".whl"))
|
|
507
513
|
project, version = wheel.split("-")[0], wheel.split("-")[1]
|
|
508
514
|
url = f"https://pypi.org/pypi/{project}/{version}/json"
|
|
@@ -565,11 +571,11 @@ jobs:
|
|
|
565
571
|
id-token: write # Sigstore signing OIDC
|
|
566
572
|
steps:
|
|
567
573
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
568
|
-
- uses: actions/download-artifact@
|
|
574
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
569
575
|
with:
|
|
570
576
|
name: release-dist
|
|
571
577
|
path: dist
|
|
572
|
-
- uses: actions/download-artifact@
|
|
578
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
573
579
|
with:
|
|
574
580
|
name: release-sbom
|
|
575
581
|
path: .
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"upload_type": "software",
|
|
3
|
+
"title": "GROUPOID: Groupoid-based aggregation for federated learning on Riemannian manifolds",
|
|
4
|
+
"version": "0.1.0.dev8",
|
|
5
|
+
"description": "<p>Pre-alpha research prototype exploring groupoid-based aggregation for federated learning on Riemannian manifolds. The supported point-valued aggregation path uses explicit invertible point actions, a cycle-basis holonomy defect diagnostic, the cellular sheaf Laplacian, and Karcher mean aggregation via geomstats. Tangent-vector parallel transport is provided separately through Schild and pole ladder utilities.</p><p><strong>Compatibility release v0.1.0.dev8:</strong> Python 3.10 support retired following upstream EOL on 2026-10-01. The supported runtime is Python 3.11-3.12; installation on 3.10 now fails closed via Requires-Python. No scientific algorithm or historical benchmark changes.</p><p><strong>Corrective release v0.1.0.dev7:</strong> the finite H0 bottleneck distance to an empty diagram is now half the longest unmatched interval, rather than an incorrect zero (both comparison directions tested). The unused mandatory PyTorch dependency was removed, reducing installation and audit complexity, and CI dependency scanning now runs without vulnerability exceptions. Pre-alpha research maturity, known limits on the H0-only diagnostic, and historical experiment results are unchanged. Existing environments may retain PyTorch after an upgrade.</p><p><strong>Library correction in v0.1.0.dev6:</strong> in v0.1.0.dev5 and earlier, the pole ladder used a step schedule that did not reach the endpoint for more than one rung, and the function named schild_ladder was a pole-ladder variant rather than Schild's construction; tangent-vector transport results from those versions with n_rungs greater than 1, including the default two-rung tangent transport operator, are incorrect. v0.1.0.dev6 corrects both ladders and adds input validation for unknown transport methods, n_rungs below 1, negative, non-finite or zero-sum aggregation weights, and non-finite holonomy maps. The preregistered benchmark uses explicit transport maps, not the ladders; its stored results are unchanged and were reproduced bit-for-bit under the dev6 candidate. The project remains a pre-alpha research prototype.</p><p><strong>Scientific correction in v0.1.0.dev5:</strong> earlier releases described the cycle-basis holonomy statistic as a first-cohomology (H^1) norm. The implementation actually computes the maximum Frobenius deviation of holonomy from identity over the particular NetworkX cycle basis. Exact zero has a flatness interpretation under explicit connectedness, completeness, invertibility, reciprocal opposite-edge registration when both directions are supplied, and complete evaluation of every cycle emitted by the NetworkX cycle-basis routine (an argument specific to the NetworkX Paton implementation exercised here, not to arbitrary cycle bases), but the nonzero magnitude is basis-dependent and is not invariant under arbitrary invertible changes of frame. The stored preregistered benchmark values are unchanged; the historical H2 rho and permutation p-value are reinterpreted as statistics for this fixed cycle-basis defect, not for a canonical H^1 norm. This version also withdraws register_transport_from_points from the supported point-valued aggregation path: its ambient square operator is assembled from transported tangent vectors and does not generally define the invertible manifold point action that aggregation requires. Tangent-vector ladder validation remains supported. The ambient tangent-matrix helper is restricted to vector-shaped point representations. Direct registered matrices are supported only under the explicit point-action contract documented in the repository, including reciprocal opposite arrows when both orientations are stored. See CORRECTION_NOTICE.md for the full correction record.</p><p>The earlier v0.1.0.dev0 version DOI 10.5281/zenodo.20563975 remains superseded and must not be cited for results. Exact historical versions should be cited by their version-specific DOI; project-level DOI metadata is maintained through the Zenodo version family.</p>",
|
|
6
|
+
"creators": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Maniches, Santiago",
|
|
9
|
+
"affiliation": "TOPOLOGICA LLC",
|
|
10
|
+
"orcid": "0009-0005-6480-1987"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"federated learning",
|
|
16
|
+
"Riemannian geometry",
|
|
17
|
+
"groupoid",
|
|
18
|
+
"sheaf theory",
|
|
19
|
+
"holonomy",
|
|
20
|
+
"topological data analysis"
|
|
21
|
+
],
|
|
22
|
+
"related_identifiers": [
|
|
23
|
+
{
|
|
24
|
+
"identifier": "10.5281/zenodo.20563974",
|
|
25
|
+
"relation": "isVersionOf",
|
|
26
|
+
"scheme": "doi"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"identifier": "https://github.com/smaniches/GROUPOID",
|
|
30
|
+
"relation": "isSupplementTo",
|
|
31
|
+
"scheme": "url"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -8,6 +8,53 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.1.0.dev8] - 2026-10-30
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Retired end-of-life Python 3.10 support.** Python 3.11 and 3.12 are the
|
|
16
|
+
supported and tested interpreter versions; `Requires-Python`, package
|
|
17
|
+
classifiers, installation instructions, test matrix, and citation metadata
|
|
18
|
+
now agree. Python 3.10 reached upstream end of life on October 1, 2026.
|
|
19
|
+
Existing users of Python 3.10 should migrate to 3.11 or 3.12 before
|
|
20
|
+
upgrading this package. Python 3.13+ remains excluded for the separately
|
|
21
|
+
documented numerical dependency constraints.
|
|
22
|
+
- This release contains no algorithm or scientific-method changes; historical
|
|
23
|
+
experimental artifacts and scientific qualification statements are unchanged.
|
|
24
|
+
|
|
25
|
+
## [0.1.0.dev7] - 2026-10-29
|
|
26
|
+
|
|
27
|
+
Pre-alpha corrective release distributing the October 29 fixes already merged
|
|
28
|
+
on `main` (#77, #78 and #81). No new experiments, measured federated-learning
|
|
29
|
+
performance gains, or general convergence claims are introduced. Archived
|
|
30
|
+
preregistration and historical benchmark outputs remain unchanged.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Finite H0 bottleneck versus an empty diagram (#77).** The previous
|
|
35
|
+
`track_divergence` fallback returned `0.0` when either finite H0 diagram
|
|
36
|
+
was empty. The mathematically correct cost is half the largest unmatched
|
|
37
|
+
persistence interval. For a two-point cloud separated by 4 versus a
|
|
38
|
+
singleton, the result is now **2.0** in either direction, not zero;
|
|
39
|
+
empty-versus-empty remains zero. Regression tests cover both directions.
|
|
40
|
+
The metric remains an H0-only geometric diagnostic, **not** a certificate
|
|
41
|
+
of federated model convergence or predictive stability.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **Removed an unused mandatory dependency (#81).** `torch` was declared as
|
|
46
|
+
required but is not imported by the implemented library. New installations
|
|
47
|
+
no longer require PyTorch or its dependency graph. The security CI installs
|
|
48
|
+
the actual supported runtime closure, requires patched `setuptools`, checks
|
|
49
|
+
`pip check`, and runs `pip-audit` without advisory ignores. The full
|
|
50
|
+
Python 3.10–3.12 tests, docs, and code-quality checks passed on `main`.
|
|
51
|
+
**Compatibility note:** PyTorch is no longer installed automatically;
|
|
52
|
+
callers requiring it for their own workflows must install it separately.
|
|
53
|
+
Upgrading an existing environment does not uninstall previously installed
|
|
54
|
+
PyTorch or other packages; independently audit those environments.
|
|
55
|
+
- Updated SHA-pinned `actions/setup-python` and PyPI publishing action (#78).
|
|
56
|
+
No algorithmic behavior was changed by this CI maintenance.
|
|
57
|
+
|
|
11
58
|
## [0.1.0.dev6]
|
|
12
59
|
|
|
13
60
|
Pre-alpha development release distributing the transport and validation fixes
|
|
@@ -268,7 +315,8 @@ Date shown is the tag commit (`v0.1.0.dev0` -> 2a02954). `CITATION.cff` records
|
|
|
268
315
|
`date-released: 2026-05-25`, when the core implementation landed; the tag was
|
|
269
316
|
later placed on the metadata commit.
|
|
270
317
|
|
|
271
|
-
[Unreleased]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.
|
|
318
|
+
[Unreleased]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev7...HEAD
|
|
319
|
+
[0.1.0.dev7]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev6...v0.1.0.dev7
|
|
272
320
|
[0.1.0.dev6]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev5...v0.1.0.dev6
|
|
273
321
|
[0.1.0.dev5]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev4...v0.1.0.dev5
|
|
274
322
|
[0.1.0.dev4]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev2...v0.1.0.dev4
|
|
@@ -2,7 +2,8 @@ cff-version: 1.2.0
|
|
|
2
2
|
message: "If you use this software, please cite the Concept DOI below so the citation resolves to the latest version."
|
|
3
3
|
type: software
|
|
4
4
|
title: "GROUPOID: Groupoid-based aggregation for federated learning on Riemannian manifolds"
|
|
5
|
-
version: 0.1.0.
|
|
5
|
+
version: 0.1.0.dev8
|
|
6
|
+
date-released: 2026-10-30
|
|
6
7
|
license: Apache-2.0
|
|
7
8
|
repository-code: "https://github.com/smaniches/GROUPOID"
|
|
8
9
|
doi: 10.5281/zenodo.20563974
|
|
@@ -80,18 +80,20 @@ please open an issue using the "Mathematical Correction" template.
|
|
|
80
80
|
1. Open a release-cut PR that bumps the version across every metadata
|
|
81
81
|
file that carries it: `pyproject.toml`, `groupoid/__init__.py`,
|
|
82
82
|
`codemeta.json`, `CITATION.cff` (version and `date-released`),
|
|
83
|
-
`STATUS.md` (
|
|
84
|
-
description, and `
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
`STATUS.md` (version), and `.zenodo.json` (version, the correction
|
|
84
|
+
description, and its concept DOI `isVersionOf` relationship). Only include
|
|
85
|
+
`isNewVersionOf` when the immediately preceding record DOI has been
|
|
86
|
+
independently verified; never inherit a stale predecessor. Roll
|
|
87
|
+
`CHANGELOG.md`'s `Unreleased` section into a new version heading with
|
|
88
|
+
compare links. See PRs #40 or #48 for the
|
|
87
89
|
template.
|
|
88
90
|
2. Merge the PR to `main`.
|
|
89
91
|
|
|
90
92
|
That's it — merging is the release trigger, split across two workflows
|
|
91
93
|
with one job each:
|
|
92
94
|
|
|
93
|
-
- `.github/workflows/auto-tag-release.yml` runs
|
|
94
|
-
|
|
95
|
+
- `.github/workflows/auto-tag-release.yml` runs after successful CI for a
|
|
96
|
+
push to the **current** `main` commit. It reads the version out of
|
|
95
97
|
`pyproject.toml`, and if no `v<version>` tag exists yet, it creates and
|
|
96
98
|
pushes one (as `github-actions[bot]`) after checking the version has a
|
|
97
99
|
recognized format and that `CHANGELOG.md` documents it. A push with no
|
|
@@ -89,6 +89,15 @@ system. The following limitations apply.
|
|
|
89
89
|
The informative loop signal lives in `max_persistence` / the finite
|
|
90
90
|
bars; meaningful component counts require passing a finite
|
|
91
91
|
`max_edge_length` between the intra- and inter-cluster scales.
|
|
92
|
+
- The opt-in `track_divergence` metric measures only changes in the
|
|
93
|
+
**finite H0** persistence diagram. It is invariant under translations,
|
|
94
|
+
rotations, and other pairwise-distance-preserving changes, and ignores
|
|
95
|
+
changes confined to H1 or higher homology. Thus a zero bottleneck
|
|
96
|
+
does **not** demonstrate client-model convergence or predictive
|
|
97
|
+
stability. If one diagram has no finite H0 bars, its distance to a
|
|
98
|
+
nonempty diagram is half the longest unmatched interval's lifetime,
|
|
99
|
+
not zero. Validation against model optimization would require
|
|
100
|
+
independent parameter-space or task-loss evidence.
|
|
92
101
|
- No formal convergence rate analysis exists for the groupoid
|
|
93
102
|
aggregation method.
|
|
94
103
|
|
|
@@ -98,17 +107,19 @@ system. The following limitations apply.
|
|
|
98
107
|
- Requires `scipy < 1.16` for the same reason.
|
|
99
108
|
- The `ripser` and `persim` packages may have build issues on
|
|
100
109
|
some platforms (C++ compilation required).
|
|
101
|
-
- `torch
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
- The former required `torch` dependency was removed because the current
|
|
111
|
+
implementation and entire documented test suite do not import it. It had
|
|
112
|
+
constrained `filelock` and `setuptools` to vulnerable versions; no current
|
|
113
|
+
GROUPOID code requires PyTorch. Future PyTorch functionality requires
|
|
114
|
+
a new separately tested dependency contract.
|
|
115
|
+
- `pymanopt`, `POT`, and `einops` are still declared as required runtime
|
|
116
|
+
dependencies but not imported in the current implementation. Their removal
|
|
117
|
+
is a separate compatibility change, not part of this security correction.
|
|
107
118
|
|
|
108
119
|
## Test coverage
|
|
109
120
|
|
|
110
121
|
- Releases are gated on the repository's hard line and branch coverage checks
|
|
111
|
-
on Python 3.
|
|
122
|
+
on Python 3.11-3.12. Coverage is not validation: the scientific correction
|
|
112
123
|
adds explicit tests for basis dependence, general non-orthogonal gauge
|
|
113
124
|
dependence of the defect magnitude, the tangent/point representation
|
|
114
125
|
boundary, and the supported SO(3) point-action round trip.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: groupoid
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev8
|
|
4
4
|
Summary: Research prototype: groupoid-based aggregation for federated learning on Riemannian manifolds
|
|
5
5
|
Author-email: Santiago Maniches <santiago.maniches@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -13,12 +13,11 @@ Keywords: federated-learning,riemannian-geometry,groupoid,topology,sheaf-theory,
|
|
|
13
13
|
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
20
19
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
-
Requires-Python: <3.13,>=3.
|
|
20
|
+
Requires-Python: <3.13,>=3.11
|
|
22
21
|
Description-Content-Type: text/markdown
|
|
23
22
|
License-File: LICENSE
|
|
24
23
|
Requires-Dist: geomstats>=0.7
|
|
@@ -30,7 +29,6 @@ Requires-Dist: networkx>=3.0
|
|
|
30
29
|
Requires-Dist: einops>=0.7
|
|
31
30
|
Requires-Dist: numpy<2.0,>=1.24
|
|
32
31
|
Requires-Dist: scipy<1.16,>=1.10
|
|
33
|
-
Requires-Dist: torch>=2.0
|
|
34
32
|
Requires-Dist: pydantic>=2.0
|
|
35
33
|
Requires-Dist: loguru>=0.7
|
|
36
34
|
Provides-Extra: privacy
|
|
@@ -68,7 +66,7 @@ Dynamic: license-file
|
|
|
68
66
|
[](https://github.com/smaniches/GROUPOID/actions/workflows/ci.yml)
|
|
69
67
|
[](https://pypi.org/project/groupoid/)
|
|
70
68
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
71
|
-
[](https://www.python.org/downloads/)
|
|
72
70
|
[](#status)
|
|
73
71
|
[](https://doi.org/10.5281/zenodo.20563974)
|
|
74
72
|
|
|
@@ -139,8 +137,12 @@ integration tests:
|
|
|
139
137
|
retains a homology-dimension label, and `track_divergence` compares H0
|
|
140
138
|
against H0 only (it does not pool features across dimensions); this is
|
|
141
139
|
verified against an independent minimum-spanning-tree reconstruction of
|
|
142
|
-
the H0 diagram.
|
|
143
|
-
|
|
140
|
+
the H0 diagram. A zero value is a geometric diagnostic, **not** a
|
|
141
|
+
certificate of client-model convergence: translations and H1-only
|
|
142
|
+
changes can leave it unchanged. A finite H0 diagram compared with
|
|
143
|
+
an empty one incurs the nonzero bottleneck-to-diagonal cost.
|
|
144
|
+
The Betti numbers are degenerate under the default `thresh=inf`
|
|
145
|
+
filtration; see [LIMITATIONS.md](LIMITATIONS.md).
|
|
144
146
|
|
|
145
147
|
## Implemented and validated, not yet integrated
|
|
146
148
|
|
|
@@ -201,7 +203,8 @@ hypothesis remains **unvalidated on real federated learning tasks** (see
|
|
|
201
203
|
|
|
202
204
|
## Installation
|
|
203
205
|
|
|
204
|
-
Requires **Python 3.
|
|
206
|
+
Requires **Python 3.11 or 3.12**. Python 3.10 reached end of life on
|
|
207
|
+
October 1, 2026 and is no longer supported. Python 3.13+ is not supported: the
|
|
205
208
|
`numpy<2.0` / `scipy<1.16` pins (needed for geomstats compatibility, see
|
|
206
209
|
[LIMITATIONS.md](LIMITATIONS.md)) have no wheels there, so `pip` will refuse
|
|
207
210
|
with a `Requires-Python` message rather than attempt a source build.
|
|
@@ -266,7 +269,7 @@ pytest tests/ -v
|
|
|
266
269
|
```
|
|
267
270
|
|
|
268
271
|
The suite reaches 100% line and branch coverage of the `groupoid` package
|
|
269
|
-
on Python 3.
|
|
272
|
+
on Python 3.11-3.12, enforced in CI:
|
|
270
273
|
|
|
271
274
|
```bash
|
|
272
275
|
pytest tests/ --cov=groupoid --cov-branch --cov-fail-under=100
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/smaniches/GROUPOID/actions/workflows/ci.yml)
|
|
4
4
|
[](https://pypi.org/project/groupoid/)
|
|
5
5
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
|
-
[](https://www.python.org/downloads/)
|
|
7
7
|
[](#status)
|
|
8
8
|
[](https://doi.org/10.5281/zenodo.20563974)
|
|
9
9
|
|
|
@@ -74,8 +74,12 @@ integration tests:
|
|
|
74
74
|
retains a homology-dimension label, and `track_divergence` compares H0
|
|
75
75
|
against H0 only (it does not pool features across dimensions); this is
|
|
76
76
|
verified against an independent minimum-spanning-tree reconstruction of
|
|
77
|
-
the H0 diagram.
|
|
78
|
-
|
|
77
|
+
the H0 diagram. A zero value is a geometric diagnostic, **not** a
|
|
78
|
+
certificate of client-model convergence: translations and H1-only
|
|
79
|
+
changes can leave it unchanged. A finite H0 diagram compared with
|
|
80
|
+
an empty one incurs the nonzero bottleneck-to-diagonal cost.
|
|
81
|
+
The Betti numbers are degenerate under the default `thresh=inf`
|
|
82
|
+
filtration; see [LIMITATIONS.md](LIMITATIONS.md).
|
|
79
83
|
|
|
80
84
|
## Implemented and validated, not yet integrated
|
|
81
85
|
|
|
@@ -136,7 +140,8 @@ hypothesis remains **unvalidated on real federated learning tasks** (see
|
|
|
136
140
|
|
|
137
141
|
## Installation
|
|
138
142
|
|
|
139
|
-
Requires **Python 3.
|
|
143
|
+
Requires **Python 3.11 or 3.12**. Python 3.10 reached end of life on
|
|
144
|
+
October 1, 2026 and is no longer supported. Python 3.13+ is not supported: the
|
|
140
145
|
`numpy<2.0` / `scipy<1.16` pins (needed for geomstats compatibility, see
|
|
141
146
|
[LIMITATIONS.md](LIMITATIONS.md)) have no wheels there, so `pip` will refuse
|
|
142
147
|
with a `Requires-Python` message rather than attempt a source build.
|
|
@@ -201,7 +206,7 @@ pytest tests/ -v
|
|
|
201
206
|
```
|
|
202
207
|
|
|
203
208
|
The suite reaches 100% line and branch coverage of the `groupoid` package
|
|
204
|
-
on Python 3.
|
|
209
|
+
on Python 3.11-3.12, enforced in CI:
|
|
205
210
|
|
|
206
211
|
```bash
|
|
207
212
|
pytest tests/ --cov=groupoid --cov-branch --cov-fail-under=100
|