groupoid 0.1.0.dev1__tar.gz → 0.1.0.dev4__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.dev4/.github/dependabot.yml +78 -0
- groupoid-0.1.0.dev4/.github/scripts/install_torch_cpu.sh +25 -0
- groupoid-0.1.0.dev4/.github/workflows/auto-tag-release.yml +72 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.github/workflows/ci.yml +18 -18
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.github/workflows/docs-deploy.yml +8 -7
- groupoid-0.1.0.dev4/.github/workflows/release.yml +107 -0
- groupoid-0.1.0.dev4/.zenodo.json +39 -0
- groupoid-0.1.0.dev4/CHANGELOG.md +162 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/CITATION.cff +2 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/CONTRIBUTING.md +39 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/LIMITATIONS.md +14 -5
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/PKG-INFO +40 -26
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/PROBLEMS.md +19 -6
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/README.md +38 -24
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/STATUS.md +28 -14
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/codemeta.json +1 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/docs/index.md +12 -10
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/docs/quickstart.md +15 -6
- groupoid-0.1.0.dev4/experiments/PREREGISTRATION.md +154 -0
- groupoid-0.1.0.dev4/experiments/README.md +64 -0
- groupoid-0.1.0.dev4/experiments/RESULTS.md +163 -0
- groupoid-0.1.0.dev4/experiments/analyze.py +261 -0
- groupoid-0.1.0.dev4/experiments/results.json +12615 -0
- groupoid-0.1.0.dev4/experiments/run_benchmark.py +213 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/__init__.py +1 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/aggregation.py +66 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/groupoid.py +5 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/optimizer.py +70 -10
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid.egg-info/PKG-INFO +40 -26
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid.egg-info/SOURCES.txt +11 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid.egg-info/requires.txt +1 -1
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/pyproject.toml +2 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_coverage_gaps.py +4 -2
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_defensive_paths.py +12 -0
- groupoid-0.1.0.dev4/tests/test_optimizer_validation.py +141 -0
- groupoid-0.1.0.dev4/tests/test_pipeline_integration.py +130 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_smoke.py +21 -0
- groupoid-0.1.0.dev1/.github/dependabot.yml +0 -29
- groupoid-0.1.0.dev1/.zenodo.json +0 -39
- groupoid-0.1.0.dev1/CHANGELOG.md +0 -77
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.github/ISSUE_TEMPLATE/mathematical_correction.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.gitignore +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/.pre-commit-config.yaml +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/LICENSE +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/REPRODUCE.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/SECURITY.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/benchmarks/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/benchmarks/conftest.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/benchmarks/test_karcher_benchmark.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/docs/api.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/docs/overrides/404.html +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/docs/theory.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/examples/README.md +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/examples/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/examples/synthetic_curve_demo.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/cohomology.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/laplacian.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/manifold.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/persistence.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/sheaf.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid/transport.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid.egg-info/dependency_links.txt +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/groupoid.egg-info/top_level.txt +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/mkdocs.yml +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/scripts/reproduce_sheaf_laplacian.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/setup.cfg +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_aggregation_disconnected.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_cohomology_cocycle.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_imports.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_integration.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_persistence.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_persistence_dimension_labels.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_sheaf_laplacian.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/test_transport_validation.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/theory/__init__.py +0 -0
- {groupoid-0.1.0.dev1 → groupoid-0.1.0.dev4}/tests/theory/test_mathematical_invariants.py +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Dependabot configuration.
|
|
2
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
3
|
+
#
|
|
4
|
+
# Opens reviewable update PRs (never auto-merged) so security and version bumps
|
|
5
|
+
# are surfaced proactively, rather than relying on a manual read of the CI
|
|
6
|
+
# dependency-audit output. Complements the CI dependency-vulnerability scan.
|
|
7
|
+
version: 2
|
|
8
|
+
updates:
|
|
9
|
+
# Python dependencies declared in pyproject.toml.
|
|
10
|
+
- package-ecosystem: "pip"
|
|
11
|
+
directory: "/"
|
|
12
|
+
schedule:
|
|
13
|
+
interval: "weekly"
|
|
14
|
+
day: "monday"
|
|
15
|
+
# Pin the run to a predictable local hour. With no time/timezone,
|
|
16
|
+
# Dependabot fires at its default slot in UTC, which lands in the middle
|
|
17
|
+
# of the night for the maintainer. Adjust `timezone` to your actual IANA
|
|
18
|
+
# zone if America/New_York is not yours.
|
|
19
|
+
time: "09:00"
|
|
20
|
+
timezone: "America/New_York"
|
|
21
|
+
open-pull-requests-limit: 5
|
|
22
|
+
# Manage DIRECT dependencies only — the ones declared in pyproject.toml.
|
|
23
|
+
# GROUPOID ships no committed/compiled lockfile, so this is currently a
|
|
24
|
+
# no-op (Dependabot already only edits the pyproject declarations). It is
|
|
25
|
+
# kept for consistency and as a guard: should a compiled lock ever be added,
|
|
26
|
+
# its transitive pins must advance by recompiling the lock, not by standalone
|
|
27
|
+
# Dependabot line-edits. Transitive CVEs are NOT lost: Dependabot *security*
|
|
28
|
+
# updates patch vulnerable dependencies regardless of this allow filter.
|
|
29
|
+
allow:
|
|
30
|
+
- dependency-type: "direct"
|
|
31
|
+
groups:
|
|
32
|
+
# Batch updates by area into a single PR per group to limit noise instead
|
|
33
|
+
# of one PR per package.
|
|
34
|
+
runtime:
|
|
35
|
+
patterns:
|
|
36
|
+
- "torch"
|
|
37
|
+
- "geomstats"
|
|
38
|
+
- "pymanopt"
|
|
39
|
+
- "ripser"
|
|
40
|
+
- "persim"
|
|
41
|
+
- "POT"
|
|
42
|
+
- "networkx"
|
|
43
|
+
- "einops"
|
|
44
|
+
- "numpy"
|
|
45
|
+
- "scipy"
|
|
46
|
+
- "pydantic"
|
|
47
|
+
- "loguru"
|
|
48
|
+
dev:
|
|
49
|
+
patterns:
|
|
50
|
+
- "pytest*"
|
|
51
|
+
- "ruff"
|
|
52
|
+
- "black"
|
|
53
|
+
- "mypy"
|
|
54
|
+
- "hypothesis"
|
|
55
|
+
- "bandit"
|
|
56
|
+
- "pip-audit"
|
|
57
|
+
- "pre-commit"
|
|
58
|
+
docs:
|
|
59
|
+
patterns: ["mkdocs*", "mkdocstrings*"]
|
|
60
|
+
# Fallback batcher. With `allow: direct` and the groups above, this should
|
|
61
|
+
# stay empty; if a future declared dep is not matched above, this keeps it
|
|
62
|
+
# to a single PR instead of one-per-package.
|
|
63
|
+
other:
|
|
64
|
+
patterns: ["*"]
|
|
65
|
+
|
|
66
|
+
# GitHub Actions used in the workflows (keeps action versions current).
|
|
67
|
+
- package-ecosystem: "github-actions"
|
|
68
|
+
directory: "/"
|
|
69
|
+
schedule:
|
|
70
|
+
interval: "weekly"
|
|
71
|
+
day: "monday"
|
|
72
|
+
time: "09:00"
|
|
73
|
+
timezone: "America/New_York"
|
|
74
|
+
open-pull-requests-limit: 5
|
|
75
|
+
groups:
|
|
76
|
+
# Batch all action bumps into a single weekly PR instead of one each.
|
|
77
|
+
actions:
|
|
78
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Installs CPU-only torch from the PyTorch index with retries.
|
|
3
|
+
#
|
|
4
|
+
# That index (download.pytorch.org/whl/cpu, Cloudflare R2-backed as
|
|
5
|
+
# download-r2.pytorch.org) intermittently drops the TLS handshake
|
|
6
|
+
# (SSLV3_ALERT_HANDSHAKE_FAILURE) from GitHub-hosted runners. pip's own
|
|
7
|
+
# built-in retries reuse the same connection pool within one process and
|
|
8
|
+
# do not help here; a fresh `pip install` invocation gets a fresh TLS
|
|
9
|
+
# connection and has in practice succeeded where the retries within a
|
|
10
|
+
# single invocation did not. Five attempts with linear backoff (10s, 20s,
|
|
11
|
+
# 30s, 40s) before giving up.
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
max_attempts=5
|
|
15
|
+
attempt=1
|
|
16
|
+
until pip install torch --index-url https://download.pytorch.org/whl/cpu; do
|
|
17
|
+
if [ "${attempt}" -ge "${max_attempts}" ]; then
|
|
18
|
+
echo "::error::torch install failed after ${max_attempts} attempts" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
sleep_seconds=$((attempt * 10))
|
|
22
|
+
echo "torch install attempt ${attempt}/${max_attempts} failed; retrying in ${sleep_seconds}s" >&2
|
|
23
|
+
sleep "${sleep_seconds}"
|
|
24
|
+
attempt=$((attempt + 1))
|
|
25
|
+
done
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Auto Tag Release
|
|
2
|
+
|
|
3
|
+
# Creates the tag for a release-cut merge to main; it does nothing else.
|
|
4
|
+
# release.yml (build, attestations, PyPI publish, signing, GitHub Release)
|
|
5
|
+
# is triggered solely by that tag push, exactly as it would be from a
|
|
6
|
+
# manual `git tag vX.Y.Z && git push origin vX.Y.Z`. Keeping tag creation
|
|
7
|
+
# and publishing in two separate, single-purpose workflows means the
|
|
8
|
+
# actual publish path has exactly one trigger (a tag push) to reason
|
|
9
|
+
# about, instead of depending on GitHub's anti-recursion behavior for
|
|
10
|
+
# GITHUB_TOKEN-authored pushes not re-triggering the same push event.
|
|
11
|
+
#
|
|
12
|
+
# If a version needs a tag this workflow's format check rejects (see
|
|
13
|
+
# below), tag it manually -- this automation only ever creates a tag
|
|
14
|
+
# when one is missing, so a pre-existing manual tag always takes
|
|
15
|
+
# precedence and this workflow becomes a no-op for that version.
|
|
16
|
+
|
|
17
|
+
on:
|
|
18
|
+
push:
|
|
19
|
+
branches: [main]
|
|
20
|
+
paths:
|
|
21
|
+
- pyproject.toml
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
tag:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
permissions:
|
|
30
|
+
contents: write # push the tag; nothing else in this workflow needs it
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 0 # need full tag history to check for an existing tag
|
|
35
|
+
|
|
36
|
+
- name: Create the release tag if this version doesn't have one yet
|
|
37
|
+
run: |
|
|
38
|
+
set -euo pipefail
|
|
39
|
+
|
|
40
|
+
version=$(grep -m1 '^version = "' pyproject.toml | sed -E 's/version = "(.*)"/\1/')
|
|
41
|
+
if [ -z "${version}" ]; then
|
|
42
|
+
echo "::error::could not extract a version from pyproject.toml"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# PEP 440-ish release/pre-release only: X.Y.Z, optionally with
|
|
47
|
+
# .devN / aN / bN / rcN. No local version segment (+...), no
|
|
48
|
+
# anything else. A version that doesn't match this is presumably
|
|
49
|
+
# intentional and unusual enough to want a human tagging it by
|
|
50
|
+
# hand rather than this automation guessing.
|
|
51
|
+
if ! echo "${version}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(\.dev[0-9]+|a[0-9]+|b[0-9]+|rc[0-9]+)?$'; then
|
|
52
|
+
echo "::error::version '${version}' is not a recognized release format (expected X.Y.Z, optionally with .devN/aN/bN/rcN, no local metadata); refusing to tag automatically. Tag it manually if this is intentional."
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
tag="v${version}"
|
|
57
|
+
|
|
58
|
+
if git rev-parse "refs/tags/${tag}" >/dev/null 2>&1; then
|
|
59
|
+
echo "Tag ${tag} already exists; nothing to do."
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
if ! grep -qF "[${version}]" CHANGELOG.md; then
|
|
64
|
+
echo "::error::CHANGELOG.md has no [${version}] heading; refusing to tag an undocumented release. Add the changelog section as part of the version-bump PR."
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
echo "Version ${version} has no matching tag; creating ${tag}."
|
|
69
|
+
git config user.name "github-actions[bot]"
|
|
70
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
71
|
+
git tag -a "${tag}" -m "Release ${tag}"
|
|
72
|
+
git push origin "refs/tags/${tag}"
|
|
@@ -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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
17
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
18
18
|
with:
|
|
19
19
|
python-version: "3.11"
|
|
20
20
|
- name: Install dependencies
|
|
@@ -25,7 +25,7 @@ jobs:
|
|
|
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
27
|
# Consistent with the test / security / docs jobs. CPU torch keeps it lean.
|
|
28
|
-
|
|
28
|
+
.github/scripts/install_torch_cpu.sh
|
|
29
29
|
pip install -e ".[dev]"
|
|
30
30
|
- name: Run ruff
|
|
31
31
|
run: ruff check .
|
|
@@ -40,14 +40,14 @@ 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
44
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
45
45
|
with:
|
|
46
46
|
python-version: ${{ matrix.python-version }}
|
|
47
47
|
- name: Install dependencies
|
|
48
48
|
run: |
|
|
49
49
|
python -m pip install --upgrade pip
|
|
50
|
-
|
|
50
|
+
.github/scripts/install_torch_cpu.sh
|
|
51
51
|
pip install -e ".[dev]"
|
|
52
52
|
- name: Run tests with coverage gate
|
|
53
53
|
run: >-
|
|
@@ -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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
62
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
63
63
|
with:
|
|
64
64
|
python-version: "3.11"
|
|
65
65
|
- name: Install dependencies
|
|
@@ -69,7 +69,7 @@ jobs:
|
|
|
69
69
|
# packages GROUPOID actually depends on. The previous `safety` step
|
|
70
70
|
# installed only the tools and never the project, so it audited the
|
|
71
71
|
# wrong environment. CPU torch keeps the install lean.
|
|
72
|
-
|
|
72
|
+
.github/scripts/install_torch_cpu.sh
|
|
73
73
|
pip install -e .
|
|
74
74
|
pip install bandit pip-audit
|
|
75
75
|
# Pin setuptools LAST. torch requires setuptools<82 and pulls in a
|
|
@@ -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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
99
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
100
100
|
with:
|
|
101
101
|
python-version: "3.11"
|
|
102
102
|
- name: Install pre-commit
|
|
@@ -107,14 +107,14 @@ 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
111
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
112
112
|
with:
|
|
113
113
|
python-version: "3.11"
|
|
114
114
|
- name: Install dependencies
|
|
115
115
|
run: |
|
|
116
116
|
python -m pip install --upgrade pip
|
|
117
|
-
|
|
117
|
+
.github/scripts/install_torch_cpu.sh
|
|
118
118
|
pip install -e ".[dev]"
|
|
119
119
|
# Benchmarks run for information only. There is no regression gate:
|
|
120
120
|
# timing baselines recorded on one machine are not comparable to a
|
|
@@ -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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
132
132
|
with:
|
|
133
133
|
name: benchmark-results
|
|
134
134
|
path: benchmark_results.json
|
|
@@ -137,14 +137,14 @@ 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
141
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
142
142
|
with:
|
|
143
143
|
python-version: "3.11"
|
|
144
144
|
- name: Install dependencies
|
|
145
145
|
run: |
|
|
146
146
|
python -m pip install --upgrade pip
|
|
147
|
-
|
|
147
|
+
.github/scripts/install_torch_cpu.sh
|
|
148
148
|
pip install -e ".[docs]"
|
|
149
149
|
- name: Build docs
|
|
150
150
|
run: mkdocs build --strict
|
|
@@ -7,8 +7,6 @@ on:
|
|
|
7
7
|
|
|
8
8
|
permissions:
|
|
9
9
|
contents: read
|
|
10
|
-
pages: write
|
|
11
|
-
id-token: write
|
|
12
10
|
|
|
13
11
|
concurrency:
|
|
14
12
|
group: pages
|
|
@@ -18,27 +16,30 @@ jobs:
|
|
|
18
16
|
build:
|
|
19
17
|
runs-on: ubuntu-latest
|
|
20
18
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
22
|
-
- uses: actions/setup-python@
|
|
19
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
20
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
23
21
|
with:
|
|
24
22
|
python-version: "3.11"
|
|
25
23
|
- name: Install dependencies
|
|
26
24
|
run: |
|
|
27
25
|
python -m pip install --upgrade pip
|
|
28
|
-
|
|
26
|
+
.github/scripts/install_torch_cpu.sh
|
|
29
27
|
pip install -e ".[docs]"
|
|
30
28
|
- name: Build docs
|
|
31
29
|
run: mkdocs build --strict
|
|
32
|
-
- uses: actions/upload-pages-artifact@
|
|
30
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
|
33
31
|
with:
|
|
34
32
|
path: site/
|
|
35
33
|
|
|
36
34
|
deploy:
|
|
37
35
|
needs: build
|
|
38
36
|
runs-on: ubuntu-latest
|
|
37
|
+
permissions:
|
|
38
|
+
pages: write
|
|
39
|
+
id-token: write
|
|
39
40
|
environment:
|
|
40
41
|
name: github-pages
|
|
41
42
|
url: ${{ steps.deployment.outputs.page_url }}
|
|
42
43
|
steps:
|
|
43
44
|
- id: deployment
|
|
44
|
-
uses: actions/deploy-pages@
|
|
45
|
+
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
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@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0
|
|
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@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
90
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
91
|
+
with:
|
|
92
|
+
name: release-artifacts
|
|
93
|
+
path: .
|
|
94
|
+
- name: Sign artifacts with Sigstore
|
|
95
|
+
uses: sigstore/gh-action-sigstore-python@5b79a39c381910c090341a2c9b0bf022c8b387e1 # v3.4.0
|
|
96
|
+
with:
|
|
97
|
+
inputs: |
|
|
98
|
+
dist/*.tar.gz
|
|
99
|
+
dist/*.whl
|
|
100
|
+
- name: Create GitHub Release
|
|
101
|
+
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
|
102
|
+
with:
|
|
103
|
+
generate_release_notes: true
|
|
104
|
+
files: |
|
|
105
|
+
dist/*
|
|
106
|
+
sbom.cdx.json
|
|
107
|
+
*.sigstore.json
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"upload_type": "software",
|
|
3
|
+
"title": "GROUPOID: Groupoid-based aggregation for federated learning on Riemannian manifolds",
|
|
4
|
+
"version": "0.1.0.dev4",
|
|
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), Riemannian optimizers, and Karcher mean aggregation via geomstats.</p><p><strong>Erratum / supersession notice:</strong> this version (v0.1.0.dev4) 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 also carries the v0.1.0.dev2 correction of a first-step magnitude inflation in the RiemannianAdam optimizer's bias initialization, and the v0.1.0.dev3 Morphism str()/format() display fix and documentation-accuracy corrections (v0.1.0.dev3 was cut in source control but never separately tagged or deposited, so this is the first deposit carrying its changes). New in v0.1.0.dev4: the Riemannian SGD and Adam optimizers now parallel-transport their accumulated moments between iterates instead of projecting them (projection could annihilate a geodesic-aligned moment); the parallel-transport and persistent-homology modules are wired into the aggregation pipeline; and a preregistered synthetic benchmark (see the repository's experiments/ directory) tests the central transport-aggregation hypothesis, finding it supported on synthetic frame-misaligned data and still unvalidated on real federated learning tasks. 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
|
+
"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
|
+
"cohomology",
|
|
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": "10.5281/zenodo.20787126",
|
|
30
|
+
"relation": "isNewVersionOf",
|
|
31
|
+
"scheme": "doi"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"identifier": "https://github.com/smaniches/GROUPOID",
|
|
35
|
+
"relation": "isSupplementTo",
|
|
36
|
+
"scheme": "url"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to GROUPOID are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
6
|
+
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
|
7
|
+
(with PEP 440 identifiers for Python pre-releases).
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
Nothing yet.
|
|
12
|
+
|
|
13
|
+
## [0.1.0.dev4] - 2026-07-06
|
|
14
|
+
|
|
15
|
+
`v0.1.0.dev3` was cut in source control (below) but never tagged or
|
|
16
|
+
released: no `v0.1.0.dev3` tag was ever pushed, so PyPI, the GitHub
|
|
17
|
+
Release, and the Zenodo deposit all skip directly from `0.1.0.dev2` to
|
|
18
|
+
this version, which carries both the `0.1.0.dev3` changes and the ones
|
|
19
|
+
below. See the "Releasing" section of `CONTRIBUTING.md` for the
|
|
20
|
+
automation added in this version that prevents this gap from recurring.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **Optimizer moment accumulators are now parallel-transported between
|
|
24
|
+
iterates**: Adam's first moment was previously carried across steps by
|
|
25
|
+
tangent projection (which can annihilate a geodesic-aligned moment) and
|
|
26
|
+
the SGD momentum velocity was not moved at all (leaving it non-tangent
|
|
27
|
+
at the new iterate). Both now use the metric's parallel transport (the
|
|
28
|
+
Becigneul-Ganea construction), with projection kept as the fallback for
|
|
29
|
+
metrics without parallel transport. Regression tests discriminate
|
|
30
|
+
transport from projection by exact norm preservation (#49).
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- `TransportGroupoidAggregator.register_transport_from_points`: computes
|
|
34
|
+
and registers the transport matrix from two client base points via the
|
|
35
|
+
pole or Schild ladder, wiring `groupoid.transport` into the pipeline
|
|
36
|
+
(#49).
|
|
37
|
+
- Opt-in `track_divergence` flag on the aggregator: each round computes
|
|
38
|
+
the persistent-homology summary of the transported parameters with the
|
|
39
|
+
H0-vs-H0 bottleneck distance to the previous round, exposed as
|
|
40
|
+
`FederatedRound.divergence` (default off; existing behavior unchanged),
|
|
41
|
+
wiring `groupoid.persistence` into the pipeline (#49).
|
|
42
|
+
- Descent validation for the Riemannian optimizers: SGD, momentum SGD,
|
|
43
|
+
and Adam descend to a known target on S^2; the optimizer status labels
|
|
44
|
+
in STATUS.md and the docs are upgraded accordingly (general
|
|
45
|
+
convergence-rate analysis still does not exist and is not claimed)
|
|
46
|
+
(#49).
|
|
47
|
+
- A preregistered synthetic benchmark (`experiments/`): preregistration
|
|
48
|
+
pushed before execution, 600 seeded runs, 2x2 transport/mean ablation
|
|
49
|
+
against an oracle estimand, corrupted-cocycle conditions, and a
|
|
50
|
+
committed preregistered analysis (`experiments/RESULTS.md`). Supports
|
|
51
|
+
the transport benefit under frame misalignment (largely by
|
|
52
|
+
construction) and the pooled H^1-error correlation under corruption,
|
|
53
|
+
with the within-level caveat, a failed null check reported as failed,
|
|
54
|
+
and one documented seeding deviation (#49).
|
|
55
|
+
- Release automation: pushing a version bump to `main` now tags and
|
|
56
|
+
releases automatically, removing the manual tag-push step.
|
|
57
|
+
|
|
58
|
+
## [0.1.0.dev3] - 2026-07-06
|
|
59
|
+
|
|
60
|
+
Cut in source control but never tagged or released; see `0.1.0.dev4` above.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
- **`Morphism` `str()`/`format()` output**: pydantic's `BaseModel` defines
|
|
64
|
+
`__str__` separately from `__repr__`, so `print()`, f-strings, and loguru's
|
|
65
|
+
`{}` formatting dumped the full transport matrix instead of the compact
|
|
66
|
+
`Morphism(A -> B)` form the `__repr__` override implements. `__str__` now
|
|
67
|
+
aliases `__repr__`, with a regression test (#47).
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
- Docs-site installation pages corrected to state the package is published on
|
|
71
|
+
PyPI as a development pre-release, aligning `docs/index.md` and
|
|
72
|
+
`docs/quickstart.md` with the README and `STATUS.md` corrections from #37
|
|
73
|
+
and #39 (#47).
|
|
74
|
+
- `curvature_adaptive_lr` docstring corrected to describe the implemented
|
|
75
|
+
behavior: the rate is damped in positive curvature and returned unchanged
|
|
76
|
+
otherwise; no enlargement is applied in negative curvature (#47).
|
|
77
|
+
- `LIMITATIONS.md` now records that `torch`, `pymanopt`, `POT`, and `einops`
|
|
78
|
+
are declared runtime dependencies with no current code path (the suite
|
|
79
|
+
passes with all four uninstalled) (#47).
|
|
80
|
+
|
|
81
|
+
## [0.1.0.dev2] - 2026-06-21
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- **RiemannianAdam first-moment bias initialization**: the first moment was
|
|
85
|
+
seeded as `grad` while the zero-init bias correction `m / (1 - beta1**t)` was
|
|
86
|
+
still applied, leaving `1/(1 - beta1)` uncancelled and inflating the first
|
|
87
|
+
optimization step ~10x (beta1 = 0.9). Now seeded as `(1 - beta1) * grad` so the
|
|
88
|
+
bias correction recovers `grad`, matching standard Adam. The optimizer is not
|
|
89
|
+
integrated into the aggregation pipeline, so no published result changes (#39).
|
|
90
|
+
|
|
91
|
+
### Changed
|
|
92
|
+
- `STATUS.md` corrected to state the package is published on PyPI as a development
|
|
93
|
+
pre-release (`groupoid 0.1.0.dev2`) rather than "not published on PyPI" (#39).
|
|
94
|
+
|
|
95
|
+
## [0.1.0.dev1] - 2026-06-16
|
|
96
|
+
|
|
97
|
+
First tag cut on mathematically corrected code. The earlier `v0.1.0.dev0` tag and
|
|
98
|
+
its Zenodo version DOI (`10.5281/zenodo.20563975`) predate the correctness fixes
|
|
99
|
+
below and are **superseded**; that snapshot must not be cited for results. The
|
|
100
|
+
concept DOI (`10.5281/zenodo.20563974`) resolves to this version.
|
|
101
|
+
|
|
102
|
+
### Fixed
|
|
103
|
+
- **Sheaf (connection) Laplacian** corrected to a positive-semidefinite operator
|
|
104
|
+
`L = delta^T delta` with a transport-consistent kernel, verified against an
|
|
105
|
+
independently constructed coboundary (#13, closes #8).
|
|
106
|
+
- **Persistence diagrams** now retain the homology-dimension label, so H0 and H1
|
|
107
|
+
bars are no longer conflated; `track_divergence` compares H0 against H0 only,
|
|
108
|
+
verified against an independent scipy minimum-spanning-tree reconstruction
|
|
109
|
+
(#21, closes #10).
|
|
110
|
+
- **Cohomology**: `compute_h1` raises `IncompleteCocycleError` naming the missing
|
|
111
|
+
edge instead of forming a meaningless partial holonomy, and disconnected-graph
|
|
112
|
+
transport is re-raised as an explicit domain error (#20).
|
|
113
|
+
- Benchmark CI regression check soft-skips on a missing JSON baseline instead of
|
|
114
|
+
failing the job (#15).
|
|
115
|
+
|
|
116
|
+
### Added
|
|
117
|
+
- 100% line + branch test coverage of the `groupoid` package on Python 3.10-3.12,
|
|
118
|
+
enforced in CI via `--cov-branch --cov-fail-under=100` (#18).
|
|
119
|
+
- Cold-clone reproducibility: a seeded determinism receipt and reproduction guide
|
|
120
|
+
(`REPRODUCE.md`), install cap, stub clarity, and a real CI gate (#16).
|
|
121
|
+
- Aggregation tests covering forward-edge traversal, weighted mean, and the
|
|
122
|
+
inconsistency flag (#17).
|
|
123
|
+
- Zenodo concept-DOI badge and `CITATION.cff` DOI metadata (#11).
|
|
124
|
+
- A `Documentation` project URL and keywords aligned across `pyproject.toml`,
|
|
125
|
+
`codemeta.json`, and `CITATION.cff` (#19).
|
|
126
|
+
- A consolidated `PROBLEMS.md` self-audit recording corrected bugs, known
|
|
127
|
+
limitations, and deferred work (#23).
|
|
128
|
+
- A `CHANGELOG.md` linked from package metadata (#24).
|
|
129
|
+
- A `.zenodo.json` so archival deposits carry curated metadata, a supersession
|
|
130
|
+
note for `v0.1.0.dev0`, and version-chain links to the concept and prior DOIs.
|
|
131
|
+
- Dependabot configuration for weekly `pip` and `github-actions` updates (#25).
|
|
132
|
+
|
|
133
|
+
### Changed
|
|
134
|
+
- Numpy array annotations parameterized to `NDArray[np.float64]`, with
|
|
135
|
+
`mypy --strict` enforced as a hard, gating CI step (#26).
|
|
136
|
+
|
|
137
|
+
### Security
|
|
138
|
+
- Replaced the deprecated soft `safety check` with a hard, gating `pip-audit`
|
|
139
|
+
step; the fix-less torch advisory CVE-2025-3000 is documented and explicitly
|
|
140
|
+
ignored with its rationale in `SECURITY.md` (#22).
|
|
141
|
+
|
|
142
|
+
## [0.1.0.dev0] - 2026-06-05
|
|
143
|
+
|
|
144
|
+
Initial pre-alpha research prototype. Core implementation of groupoid-based
|
|
145
|
+
aggregation for federated learning on Riemannian manifolds: the transport groupoid
|
|
146
|
+
(morphism composition and inverse), the Karcher mean via geomstats, H^1
|
|
147
|
+
cohomological consistency, the sheaf Laplacian, parallel transport (Schild's and
|
|
148
|
+
pole ladders), and persistence-based divergence tracking. Ships machine-readable
|
|
149
|
+
citation metadata (`CITATION.cff`, `codemeta.json` with ORCID). Pre-alpha: APIs
|
|
150
|
+
may change and the central hypothesis is not yet validated (see `STATUS.md` and
|
|
151
|
+
`LIMITATIONS.md`).
|
|
152
|
+
|
|
153
|
+
Date shown is the tag commit (`v0.1.0.dev0` -> 2a02954). `CITATION.cff` records
|
|
154
|
+
`date-released: 2026-05-25`, when the core implementation landed; the tag was
|
|
155
|
+
later placed on the metadata commit.
|
|
156
|
+
|
|
157
|
+
[Unreleased]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev4...HEAD
|
|
158
|
+
[0.1.0.dev4]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev2...v0.1.0.dev4
|
|
159
|
+
[0.1.0.dev3]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev2...af42cb4
|
|
160
|
+
[0.1.0.dev2]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev1...v0.1.0.dev2
|
|
161
|
+
[0.1.0.dev1]: https://github.com/smaniches/GROUPOID/compare/v0.1.0.dev0...v0.1.0.dev1
|
|
162
|
+
[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.dev4
|
|
6
|
+
date-released: 2026-07-06
|
|
7
7
|
license: Apache-2.0
|
|
8
8
|
repository-code: "https://github.com/smaniches/GROUPOID"
|
|
9
9
|
doi: 10.5281/zenodo.20563974
|