groupoid 0.1.0.dev1__tar.gz → 0.1.0.dev2__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.dev1 → groupoid-0.1.0.dev2}/.github/workflows/ci.yml +13 -13
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.github/workflows/docs-deploy.yml +4 -4
- groupoid-0.1.0.dev2/.github/workflows/release.yml +107 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.zenodo.json +3 -3
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/CHANGELOG.md +16 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/CITATION.cff +2 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/PKG-INFO +10 -3
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/README.md +8 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/STATUS.md +3 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/codemeta.json +1 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/__init__.py +1 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/optimizer.py +6 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid.egg-info/PKG-INFO +10 -3
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid.egg-info/SOURCES.txt +1 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid.egg-info/requires.txt +1 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/pyproject.toml +2 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_smoke.py +21 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.github/ISSUE_TEMPLATE/mathematical_correction.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.github/dependabot.yml +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.gitignore +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.pre-commit-config.yaml +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/CONTRIBUTING.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/LICENSE +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/LIMITATIONS.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/PROBLEMS.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/REPRODUCE.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/SECURITY.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/benchmarks/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/benchmarks/conftest.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/benchmarks/test_karcher_benchmark.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/docs/api.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/docs/index.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/docs/overrides/404.html +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/docs/quickstart.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/docs/theory.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/examples/README.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/examples/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/examples/synthetic_curve_demo.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/aggregation.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/cohomology.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/groupoid.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/laplacian.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/manifold.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/persistence.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/sheaf.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid/transport.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid.egg-info/dependency_links.txt +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/groupoid.egg-info/top_level.txt +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/mkdocs.yml +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/scripts/reproduce_sheaf_laplacian.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/setup.cfg +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_aggregation_disconnected.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_cohomology_cocycle.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_coverage_gaps.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_defensive_paths.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_imports.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_integration.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_persistence.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_persistence_dimension_labels.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_sheaf_laplacian.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/test_transport_validation.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/theory/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/tests/theory/test_mathematical_invariants.py +0 -0
|
@@ -13,8 +13,8 @@ jobs:
|
|
|
13
13
|
lint:
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
17
|
-
- uses: actions/setup-python@
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- uses: actions/setup-python@v6
|
|
18
18
|
with:
|
|
19
19
|
python-version: "3.11"
|
|
20
20
|
- name: Install dependencies
|
|
@@ -40,8 +40,8 @@ jobs:
|
|
|
40
40
|
matrix:
|
|
41
41
|
python-version: ["3.10", "3.11", "3.12"]
|
|
42
42
|
steps:
|
|
43
|
-
- uses: actions/checkout@
|
|
44
|
-
- uses: actions/setup-python@
|
|
43
|
+
- uses: actions/checkout@v6
|
|
44
|
+
- uses: actions/setup-python@v6
|
|
45
45
|
with:
|
|
46
46
|
python-version: ${{ matrix.python-version }}
|
|
47
47
|
- name: Install dependencies
|
|
@@ -58,8 +58,8 @@ jobs:
|
|
|
58
58
|
security:
|
|
59
59
|
runs-on: ubuntu-latest
|
|
60
60
|
steps:
|
|
61
|
-
- uses: actions/checkout@
|
|
62
|
-
- uses: actions/setup-python@
|
|
61
|
+
- uses: actions/checkout@v6
|
|
62
|
+
- uses: actions/setup-python@v6
|
|
63
63
|
with:
|
|
64
64
|
python-version: "3.11"
|
|
65
65
|
- name: Install dependencies
|
|
@@ -95,8 +95,8 @@ jobs:
|
|
|
95
95
|
pre-commit:
|
|
96
96
|
runs-on: ubuntu-latest
|
|
97
97
|
steps:
|
|
98
|
-
- uses: actions/checkout@
|
|
99
|
-
- uses: actions/setup-python@
|
|
98
|
+
- uses: actions/checkout@v6
|
|
99
|
+
- uses: actions/setup-python@v6
|
|
100
100
|
with:
|
|
101
101
|
python-version: "3.11"
|
|
102
102
|
- name: Install pre-commit
|
|
@@ -107,8 +107,8 @@ jobs:
|
|
|
107
107
|
benchmark:
|
|
108
108
|
runs-on: ubuntu-latest
|
|
109
109
|
steps:
|
|
110
|
-
- uses: actions/checkout@
|
|
111
|
-
- uses: actions/setup-python@
|
|
110
|
+
- uses: actions/checkout@v6
|
|
111
|
+
- uses: actions/setup-python@v6
|
|
112
112
|
with:
|
|
113
113
|
python-version: "3.11"
|
|
114
114
|
- name: Install dependencies
|
|
@@ -128,7 +128,7 @@ jobs:
|
|
|
128
128
|
pytest benchmarks/ -v --benchmark-json=benchmark_results.json || true
|
|
129
129
|
- name: Upload benchmark results
|
|
130
130
|
if: always()
|
|
131
|
-
uses: actions/upload-artifact@
|
|
131
|
+
uses: actions/upload-artifact@v7
|
|
132
132
|
with:
|
|
133
133
|
name: benchmark-results
|
|
134
134
|
path: benchmark_results.json
|
|
@@ -137,8 +137,8 @@ jobs:
|
|
|
137
137
|
docs:
|
|
138
138
|
runs-on: ubuntu-latest
|
|
139
139
|
steps:
|
|
140
|
-
- uses: actions/checkout@
|
|
141
|
-
- uses: actions/setup-python@
|
|
140
|
+
- uses: actions/checkout@v6
|
|
141
|
+
- uses: actions/setup-python@v6
|
|
142
142
|
with:
|
|
143
143
|
python-version: "3.11"
|
|
144
144
|
- name: Install dependencies
|
|
@@ -18,8 +18,8 @@ jobs:
|
|
|
18
18
|
build:
|
|
19
19
|
runs-on: ubuntu-latest
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
22
|
-
- uses: actions/setup-python@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
- uses: actions/setup-python@v6
|
|
23
23
|
with:
|
|
24
24
|
python-version: "3.11"
|
|
25
25
|
- name: Install dependencies
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
pip install -e ".[docs]"
|
|
30
30
|
- name: Build docs
|
|
31
31
|
run: mkdocs build --strict
|
|
32
|
-
- uses: actions/upload-pages-artifact@
|
|
32
|
+
- uses: actions/upload-pages-artifact@v5
|
|
33
33
|
with:
|
|
34
34
|
path: site/
|
|
35
35
|
|
|
@@ -41,4 +41,4 @@ jobs:
|
|
|
41
41
|
url: ${{ steps.deployment.outputs.page_url }}
|
|
42
42
|
steps:
|
|
43
43
|
- id: deployment
|
|
44
|
-
uses: actions/deploy-pages@
|
|
44
|
+
uses: actions/deploy-pages@v5
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v[0-9]*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
ref:
|
|
10
|
+
description: "Existing tag/ref to build and publish to PyPI (e.g. v0.1.0.dev1). PyPI only — does NOT create a GitHub Release or Zenodo deposit. Leave blank for a normal tag-triggered release."
|
|
11
|
+
required: false
|
|
12
|
+
default: ""
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
id-token: write # provenance OIDC
|
|
23
|
+
attestations: write # actions/attest-build-provenance + attest-sbom
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
26
|
+
with:
|
|
27
|
+
ref: ${{ github.event.inputs.ref || github.ref }}
|
|
28
|
+
fetch-depth: 0
|
|
29
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
cache: pip
|
|
33
|
+
- name: Install build tooling
|
|
34
|
+
run: |
|
|
35
|
+
python -m pip install --upgrade pip build
|
|
36
|
+
pip install cyclonedx-bom
|
|
37
|
+
- name: Build sdist + wheel
|
|
38
|
+
run: python -m build
|
|
39
|
+
- name: Generate CycloneDX SBOM
|
|
40
|
+
run: cyclonedx-py requirements -o sbom.cdx.json <(pip freeze)
|
|
41
|
+
- name: Provenance attestation (dist)
|
|
42
|
+
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
|
|
43
|
+
with:
|
|
44
|
+
subject-path: "dist/*"
|
|
45
|
+
- name: SBOM attestation (CycloneDX)
|
|
46
|
+
uses: actions/attest-sbom@5026d3663739160db546203eeaffa6aa1c51a4d6 # v1
|
|
47
|
+
with:
|
|
48
|
+
subject-path: "dist/*"
|
|
49
|
+
sbom-path: "sbom.cdx.json"
|
|
50
|
+
- name: Upload artifacts
|
|
51
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
52
|
+
with:
|
|
53
|
+
name: release-artifacts
|
|
54
|
+
path: |
|
|
55
|
+
dist/*
|
|
56
|
+
sbom.cdx.json
|
|
57
|
+
|
|
58
|
+
publish-pypi:
|
|
59
|
+
needs: build
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
permissions:
|
|
62
|
+
contents: read
|
|
63
|
+
id-token: write # PyPI Trusted Publishing OIDC
|
|
64
|
+
environment:
|
|
65
|
+
name: pypi
|
|
66
|
+
url: https://pypi.org/project/groupoid/
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
69
|
+
with:
|
|
70
|
+
name: release-artifacts
|
|
71
|
+
path: .
|
|
72
|
+
- name: Publish to PyPI (Trusted Publishing, OIDC)
|
|
73
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
|
|
74
|
+
with:
|
|
75
|
+
packages-dir: dist
|
|
76
|
+
print-hash: true
|
|
77
|
+
|
|
78
|
+
sign-and-release:
|
|
79
|
+
needs: build
|
|
80
|
+
# Only on a real tag push — a manual workflow_dispatch (used to publish an
|
|
81
|
+
# already-released tag to PyPI) must NOT create a duplicate GitHub Release
|
|
82
|
+
# or trigger a second Zenodo deposit.
|
|
83
|
+
if: github.event_name == 'push'
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
permissions:
|
|
86
|
+
contents: write # create GitHub Release
|
|
87
|
+
id-token: write # Sigstore signing OIDC
|
|
88
|
+
steps:
|
|
89
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
90
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
91
|
+
with:
|
|
92
|
+
name: release-artifacts
|
|
93
|
+
path: .
|
|
94
|
+
- name: Sign artifacts with Sigstore
|
|
95
|
+
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
|
|
96
|
+
with:
|
|
97
|
+
inputs: |
|
|
98
|
+
dist/*.tar.gz
|
|
99
|
+
dist/*.whl
|
|
100
|
+
- name: Create GitHub Release
|
|
101
|
+
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
|
102
|
+
with:
|
|
103
|
+
generate_release_notes: true
|
|
104
|
+
files: |
|
|
105
|
+
dist/*
|
|
106
|
+
sbom.cdx.json
|
|
107
|
+
*.sigstore.json
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"upload_type": "software",
|
|
3
3
|
"title": "GROUPOID: Groupoid-based aggregation for federated learning on Riemannian manifolds",
|
|
4
|
-
"version": "0.1.0.
|
|
5
|
-
"description": "<p>Pre-alpha research prototype exploring groupoid-based aggregation for federated learning on Riemannian manifolds. Implements transport groupoid morphisms, first cohomology (H^1) for consistency detection, the cellular sheaf Laplacian for spectral analysis, parallel transport (Schild's and pole ladders), and Karcher mean aggregation via geomstats.</p><p><strong>Erratum / supersession notice:</strong> this version (v0.1.0.
|
|
4
|
+
"version": "0.1.0.dev2",
|
|
5
|
+
"description": "<p>Pre-alpha research prototype exploring groupoid-based aggregation for federated learning on Riemannian manifolds. Implements transport groupoid morphisms, first cohomology (H^1) for consistency detection, the cellular sheaf Laplacian for spectral analysis, parallel transport (Schild's and pole ladders), and Karcher mean aggregation via geomstats.</p><p><strong>Erratum / supersession notice:</strong> this version (v0.1.0.dev2) carries the mathematical corrections introduced in v0.1.0.dev1 over the earlier v0.1.0.dev0 snapshot (version DOI 10.5281/zenodo.20563975): the sheaf (connection) Laplacian is a verified positive-semidefinite operator with a transport-consistent kernel; persistence diagrams retain the homology-dimension label so H0 and H1 are no longer conflated; and H^1 cohomology raises on incomplete cocycles instead of forming partial holonomy. It additionally corrects a first-step magnitude inflation in the RiemannianAdam optimizer's bias initialization (a component not used by the aggregation results). The v0.1.0.dev0 version DOI must not be cited for results. Cite the concept DOI (10.5281/zenodo.20563974), which always resolves to the latest corrected version, or this version or later.</p>",
|
|
6
6
|
"creators": [
|
|
7
7
|
{
|
|
8
8
|
"name": "Maniches, Santiago",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"scheme": "doi"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
"identifier": "10.5281/zenodo.
|
|
29
|
+
"identifier": "10.5281/zenodo.20719394",
|
|
30
30
|
"relation": "isNewVersionOf",
|
|
31
31
|
"scheme": "doi"
|
|
32
32
|
},
|
|
@@ -10,6 +10,20 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
10
10
|
|
|
11
11
|
Nothing yet.
|
|
12
12
|
|
|
13
|
+
## [0.1.0.dev2] - 2026-06-21
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **RiemannianAdam first-moment bias initialization**: the first moment was
|
|
17
|
+
seeded as `grad` while the zero-init bias correction `m / (1 - beta1**t)` was
|
|
18
|
+
still applied, leaving `1/(1 - beta1)` uncancelled and inflating the first
|
|
19
|
+
optimization step ~10x (beta1 = 0.9). Now seeded as `(1 - beta1) * grad` so the
|
|
20
|
+
bias correction recovers `grad`, matching standard Adam. The optimizer is not
|
|
21
|
+
integrated into the aggregation pipeline, so no published result changes (#39).
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- `STATUS.md` corrected to state the package is published on PyPI as a development
|
|
25
|
+
pre-release (`groupoid 0.1.0.dev2`) rather than "not published on PyPI" (#39).
|
|
26
|
+
|
|
13
27
|
## [0.1.0.dev1] - 2026-06-16
|
|
14
28
|
|
|
15
29
|
First tag cut on mathematically corrected code. The earlier `v0.1.0.dev0` tag and
|
|
@@ -72,6 +86,7 @@ Date shown is the tag commit (`v0.1.0.dev0` -> 2a02954). `CITATION.cff` records
|
|
|
72
86
|
`date-released: 2026-05-25`, when the core implementation landed; the tag was
|
|
73
87
|
later placed on the metadata commit.
|
|
74
88
|
|
|
75
|
-
[Unreleased]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.
|
|
89
|
+
[Unreleased]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev2...HEAD
|
|
90
|
+
[0.1.0.dev2]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev1...v0.1.0.dev2
|
|
76
91
|
[0.1.0.dev1]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev0...v0.1.0.dev1
|
|
77
92
|
[0.1.0.dev0]: https://github.com/smaniches/GROUPOID/releases/tag/v0.1.0.dev0
|
|
@@ -2,8 +2,8 @@ cff-version: 1.2.0
|
|
|
2
2
|
message: "If you use this software, please cite it as below."
|
|
3
3
|
type: software
|
|
4
4
|
title: "GROUPOID: Groupoid-based aggregation for federated learning on Riemannian manifolds"
|
|
5
|
-
version: 0.1.0.
|
|
6
|
-
date-released: 2026-06-
|
|
5
|
+
version: 0.1.0.dev2
|
|
6
|
+
date-released: 2026-06-21
|
|
7
7
|
license: Apache-2.0
|
|
8
8
|
repository-code: "https://github.com/smaniches/GROUPOID"
|
|
9
9
|
doi: 10.5281/zenodo.20563974
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: groupoid
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
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
|
|
@@ -29,7 +29,7 @@ Requires-Dist: POT>=0.9
|
|
|
29
29
|
Requires-Dist: networkx>=3.0
|
|
30
30
|
Requires-Dist: einops>=0.7
|
|
31
31
|
Requires-Dist: numpy<2.0,>=1.24
|
|
32
|
-
Requires-Dist: scipy<1.
|
|
32
|
+
Requires-Dist: scipy<1.16,>=1.10
|
|
33
33
|
Requires-Dist: torch>=2.0
|
|
34
34
|
Requires-Dist: pydantic>=2.0
|
|
35
35
|
Requires-Dist: loguru>=0.7
|
|
@@ -66,6 +66,7 @@ Dynamic: license-file
|
|
|
66
66
|
# GROUPOID
|
|
67
67
|
|
|
68
68
|
[](https://github.com/smaniches/GROUPOID/actions/workflows/ci.yml)
|
|
69
|
+
[](https://pypi.org/project/groupoid/)
|
|
69
70
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
70
71
|
[](https://www.python.org/downloads/)
|
|
71
72
|
[](#status)
|
|
@@ -187,7 +188,13 @@ Requires **Python 3.10, 3.11, or 3.12**. Python 3.13+ is not supported: the
|
|
|
187
188
|
[LIMITATIONS.md](LIMITATIONS.md)) have no wheels there, so `pip` will refuse
|
|
188
189
|
with a `Requires-Python` message rather than attempt a source build.
|
|
189
190
|
|
|
190
|
-
From
|
|
191
|
+
From PyPI:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
pip install groupoid
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
From source (for development):
|
|
191
198
|
|
|
192
199
|
```bash
|
|
193
200
|
git clone https://github.com/smaniches/GROUPOID.git
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# GROUPOID
|
|
2
2
|
|
|
3
3
|
[](https://github.com/smaniches/GROUPOID/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/groupoid/)
|
|
4
5
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
5
6
|
[](https://www.python.org/downloads/)
|
|
6
7
|
[](#status)
|
|
@@ -122,7 +123,13 @@ Requires **Python 3.10, 3.11, or 3.12**. Python 3.13+ is not supported: the
|
|
|
122
123
|
[LIMITATIONS.md](LIMITATIONS.md)) have no wheels there, so `pip` will refuse
|
|
123
124
|
with a `Requires-Python` message rather than attempt a source build.
|
|
124
125
|
|
|
125
|
-
From
|
|
126
|
+
From PyPI:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pip install groupoid
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
From source (for development):
|
|
126
133
|
|
|
127
134
|
```bash
|
|
128
135
|
git clone https://github.com/smaniches/GROUPOID.git
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
- No federated training loop with real neural networks exists yet.
|
|
33
33
|
- No differential privacy mechanism is implemented.
|
|
34
34
|
- No formal convergence analysis or proofs exist.
|
|
35
|
-
- The package is
|
|
35
|
+
- The package is published on PyPI only as an early development pre-release
|
|
36
|
+
(`groupoid 0.1.0.dev2`); no stable release exists yet.
|
|
36
37
|
|
|
37
38
|
## Validation status
|
|
38
39
|
|
|
@@ -70,5 +71,5 @@ not capture.
|
|
|
70
71
|
|
|
71
72
|
## Versioning
|
|
72
73
|
|
|
73
|
-
This project uses `0.1.0.
|
|
74
|
+
This project uses `0.1.0.dev2` to indicate pre-release development.
|
|
74
75
|
The API is unstable and will change without notice.
|
|
@@ -138,10 +138,14 @@ class RiemannianAdam:
|
|
|
138
138
|
grad = self.manifold.to_tangent(euclidean_grad, point)
|
|
139
139
|
grad_norm_sq = float(np.sum(grad**2))
|
|
140
140
|
|
|
141
|
-
# Update biased first moment (tangent vector)
|
|
141
|
+
# Update biased first moment (tangent vector). Seed from zero like the
|
|
142
|
+
# second moment below: m_1 = (1 - beta1) * grad, so the bias correction
|
|
143
|
+
# m_hat = m_1 / (1 - beta1) recovers `grad` on the first step. Seeding
|
|
144
|
+
# m_1 = grad directly would leave the 1/(1-beta1) factor uncancelled and
|
|
145
|
+
# inflate the first update by ~10x (beta1=0.9).
|
|
142
146
|
first_moment: npt.NDArray[np.float64]
|
|
143
147
|
if self._m is None:
|
|
144
|
-
first_moment =
|
|
148
|
+
first_moment = (1 - self.beta1) * grad
|
|
145
149
|
else:
|
|
146
150
|
first_moment = self.manifold.to_tangent(
|
|
147
151
|
self.beta1 * self._m + (1 - self.beta1) * grad, point
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: groupoid
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
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
|
|
@@ -29,7 +29,7 @@ Requires-Dist: POT>=0.9
|
|
|
29
29
|
Requires-Dist: networkx>=3.0
|
|
30
30
|
Requires-Dist: einops>=0.7
|
|
31
31
|
Requires-Dist: numpy<2.0,>=1.24
|
|
32
|
-
Requires-Dist: scipy<1.
|
|
32
|
+
Requires-Dist: scipy<1.16,>=1.10
|
|
33
33
|
Requires-Dist: torch>=2.0
|
|
34
34
|
Requires-Dist: pydantic>=2.0
|
|
35
35
|
Requires-Dist: loguru>=0.7
|
|
@@ -66,6 +66,7 @@ Dynamic: license-file
|
|
|
66
66
|
# GROUPOID
|
|
67
67
|
|
|
68
68
|
[](https://github.com/smaniches/GROUPOID/actions/workflows/ci.yml)
|
|
69
|
+
[](https://pypi.org/project/groupoid/)
|
|
69
70
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
70
71
|
[](https://www.python.org/downloads/)
|
|
71
72
|
[](#status)
|
|
@@ -187,7 +188,13 @@ Requires **Python 3.10, 3.11, or 3.12**. Python 3.13+ is not supported: the
|
|
|
187
188
|
[LIMITATIONS.md](LIMITATIONS.md)) have no wheels there, so `pip` will refuse
|
|
188
189
|
with a `Requires-Python` message rather than attempt a source build.
|
|
189
190
|
|
|
190
|
-
From
|
|
191
|
+
From PyPI:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
pip install groupoid
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
From source (for development):
|
|
191
198
|
|
|
192
199
|
```bash
|
|
193
200
|
git clone https://github.com/smaniches/GROUPOID.git
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "groupoid"
|
|
7
|
-
version = "0.1.0.
|
|
7
|
+
version = "0.1.0.dev2"
|
|
8
8
|
description = "Research prototype: groupoid-based aggregation for federated learning on Riemannian manifolds"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -44,7 +44,7 @@ dependencies = [
|
|
|
44
44
|
"networkx>=3.0",
|
|
45
45
|
"einops>=0.7",
|
|
46
46
|
"numpy>=1.24,<2.0",
|
|
47
|
-
"scipy>=1.10,<1.
|
|
47
|
+
"scipy>=1.10,<1.16",
|
|
48
48
|
"torch>=2.0",
|
|
49
49
|
"pydantic>=2.0",
|
|
50
50
|
"loguru>=0.7",
|
|
@@ -115,6 +115,27 @@ class TestOptimizerSmoke:
|
|
|
115
115
|
assert new_point.shape == (3,)
|
|
116
116
|
assert manifold.belongs(new_point, atol=1e-4)
|
|
117
117
|
|
|
118
|
+
def test_riemannian_adam_first_step_magnitude(self):
|
|
119
|
+
"""The first step moves ~lr in geodesic distance, not lr/(1 - beta1).
|
|
120
|
+
|
|
121
|
+
Standard Adam's bias correction yields m_hat_1 = grad on step 1, so the
|
|
122
|
+
update is -lr * grad / (||grad|| + eps) and the geodesic displacement is
|
|
123
|
+
~lr. Seeding the first moment as grad without the (1 - beta1) factor
|
|
124
|
+
leaves 1/(1 - beta1) uncancelled and inflates the first step to ~10*lr
|
|
125
|
+
(beta1 = 0.9). This test fails on that bug.
|
|
126
|
+
"""
|
|
127
|
+
from geomstats.geometry.hypersphere import Hypersphere
|
|
128
|
+
|
|
129
|
+
from groupoid.optimizer import RiemannianAdam
|
|
130
|
+
|
|
131
|
+
manifold = Hypersphere(dim=2)
|
|
132
|
+
point = np.array([0.0, 0.0, 1.0])
|
|
133
|
+
grad = np.array([0.1, 0.2, 0.3])
|
|
134
|
+
lr = 0.01
|
|
135
|
+
new_point = RiemannianAdam(manifold=manifold, lr=lr).step(point, grad)
|
|
136
|
+
dist = float(manifold.metric.dist(point, new_point))
|
|
137
|
+
assert abs(dist - lr) < 0.2 * lr
|
|
138
|
+
|
|
118
139
|
|
|
119
140
|
class TestAggregationSmoke:
|
|
120
141
|
"""Deterministic aggregation test."""
|
|
File without changes
|
|
File without changes
|
{groupoid-0.1.0.dev1 → groupoid-0.1.0.dev2}/.github/ISSUE_TEMPLATE/mathematical_correction.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|