Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
7dca294
Pure numpy/scipy replacements for all JIDT estimators, vectorized SPI…
willedibam Mar 17, 2026
f00f537
Update distance.py with improved pairwise distance computation
willedibam Mar 22, 2026
df84c1b
Fix label duplication, JVM startup, and add AIS auto-embed TE
willedibam Mar 26, 2026
b00ac87
Append _rmse suffix to CrossPairwiseDistance identifier
willedibam Apr 12, 2026
e27e36f
Remove stale JIDT/Java gates; make correctness test fork-tolerant
willedibam Apr 21, 2026
1eb6117
Modernize deps: pyproject.toml, numpy>=2, mne-connectivity, drop sktime
willedibam Apr 22, 2026
759ca96
Add VAR1 + Kuramoto drift regression suite vs upstream pyspi 2.0.1
willedibam Apr 22, 2026
8b3f85f
Redefine CrossPairwiseDistance as a shifted-path DTW upper bound
willedibam Apr 22, 2026
09b98dc
Ridge-regularise Gaussian entropy; apply Theiler window to Kernel TE
willedibam Apr 22, 2026
c125574
Make config.yaml the fork superset; comment out IGCI
willedibam Apr 22, 2026
91db76c
Pin setuptools>=68,<80 for pyEDM's pkg_resources import
willedibam Apr 22, 2026
d1f7279
Add benchmarked_config.yaml reference + commit uv.lock
willedibam Apr 23, 2026
d9770d9
Add parallel SPI execution with cache-aware scheduling and checkpointing
willedibam May 20, 2026
7df7685
Add verbose kwarg, extract YAML loader, test-suite cleanup, bench har…
willedibam May 20, 2026
bbcc28b
Drop dill dep; switch frozen-baseline pickles to stdlib pickle
willedibam May 20, 2026
fb225f3
Migrate console output to logging; add per-SPI parallel progress
willedibam May 20, 2026
cb073ef
Default to fork on Linux; harden parallel cleanup; upgrade bench suite
willedibam May 20, 2026
b4827c5
Add bench/ PBS script and README
willedibam May 20, 2026
5ffebdf
Pin cdt's thread pool in parallel workers
willedibam May 20, 2026
e8a9faa
Harden parallel pinning; add cut_config and cluster bench scripts
willedibam May 20, 2026
9775adf
run_benchmark_physics.pbs: whole-node defaults (48 cores, 192GB, 1 week)
willedibam May 25, 2026
badfb4e
bench: per-cell JSON output + dedicated PBS scripts for the 5x5 grid
willedibam May 25, 2026
b5eade6
config: per-config Mxx labels; merge logic + tests
willedibam May 26, 2026
2de678b
bench: cross-cell analysis, scaling forecast, comment-preserving cuts
willedibam May 26, 2026
360d4f6
bench/results: 20 per-cell JSONs + analysis artefacts (pyspi badfb4e)
willedibam May 26, 2026
baa109a
configs: rebuild benchmarked{80,90,95,99}_amortized at M=16,T=800
willedibam May 26, 2026
02bf4e4
bench: amortize cost per cache subkey, not per namespace
willedibam May 26, 2026
a391a65
bench: snap partial cache buckets to fully-kept; subkeys on all cache…
willedibam May 26, 2026
7ec22a8
configs: prune stale benchmarked variants
willedibam Jun 3, 2026
c608162
bench/results: M64_T800 cluster cell + refreshed analysis (21 cells)
willedibam Jun 3, 2026
7bc7794
bench/results: M64_T1600 cluster cell; refresh analysis (22 cells)
willedibam Jun 3, 2026
6e377b0
benchmarked90_amortized: manually keep te_kraskov DCE k=1,2
willedibam Jun 3, 2026
2cf3312
Fix Kernel entropy NORMALISE scale term; add JIDT parity benchmark
willedibam Jun 9, 2026
7fd9478
infotheory: fix Theiler-MI counting, auto-embed bias, AUTO routing; r…
willedibam Jun 9, 2026
0ae28be
infotheory: estimator-consistent KSG-AIS embedding for kraskov auto-e…
willedibam Jun 9, 2026
703c73a
bench/analysis + deps: add benchmark notebook, viz deps, project CLAU…
willedibam Jun 16, 2026
fb7a042
Remove JIDT/Java, rework config + Calculator API, fix packaging
willedibam Aug 13, 2026
6ef57ea
bench: prune derived artefacts, drop the JIDT parity harness, de-pers…
willedibam Aug 13, 2026
07706d0
tests: make the suite runnable, regenerate baselines, add analytic co…
willedibam Aug 13, 2026
13a6aae
bench: collapse the PBS scripts, drop cell forecasting
willedibam Aug 13, 2026
6654c8e
Fix directed spectral SPIs being transposed; smaller test fixtures
willedibam Aug 13, 2026
0f956f2
Release 3.0.0: version bump and CHANGELOG
willedibam Aug 13, 2026
d27fe19
demos: parallelism section, heading levels, verbosity trim
willedibam Aug 13, 2026
d2397b7
Fix CorrelationFrame's broken labelled path; untrack CLAUDE.md and an…
willedibam Aug 13, 2026
0d12f22
Guard against thread/process oversubscription
willedibam Aug 13, 2026
605d7a0
CHANGELOG: math notation for the KSG convergence rate
willedibam Aug 13, 2026
6543daa
uv.lock: resync after the pyEDM>=2.5 and pandas>=2.1 floors
willedibam Aug 13, 2026
799d04d
Results I/O on .npz; cache-bucket advice; library logging
willedibam Aug 13, 2026
3ea94c0
tests: red suite for state, identity, parity, estimator, and trait co…
willedibam Aug 14, 2026
c64a519
data: own the arrays, invalidate caches on mutation, validate inputs
willedibam Aug 14, 2026
18b5621
spectral: key the caches on every parameter that changes the result
willedibam Aug 14, 2026
5991ba7
execution: one validation and error-capture path, calc.errors, calc.r…
willedibam Aug 14, 2026
d0f69f3
identity: bind checkpoints to the run, reject collisions, drop pickle
willedibam Aug 14, 2026
06a2c61
estimators: compute what the identifier claims, or refuse
willedibam Aug 14, 2026
235df77
semantics: derive structural traits from implementations, not assumpt…
willedibam Aug 14, 2026
5299e38
Fix DirectedInfo, PSI max reduction, and five state/validation gaps
willedibam Aug 14, 2026
08727af
Close six remaining correctness gaps from the third review
willedibam Aug 14, 2026
557973c
Remove import-time RNG seed, resolve filter_spis, unify Gaussian JE/CE
willedibam Aug 14, 2026
ae5770f
CHANGELOG: merge the two wavelet PSI entries
willedibam Aug 14, 2026
e2748dc
Untrack critiques.md
willedibam Aug 14, 2026
a77fc67
Restore a validated nonlinear DirectedInfo; close checkpoint/KSG gaps
willedibam Aug 14, 2026
ac12e1f
CHANGELOG: document the SPI set changes; correct stale claims
willedibam Aug 14, 2026
ccd8662
Reject tied data in Kozachenko entropy; retire stale xfails
willedibam Aug 14, 2026
07d4c83
demos: one lean tutorial; add Calculator.to_frame() and .summary()
willedibam Aug 14, 2026
69937f2
Remove degenerate max-PLI variants; relabel CE; add repr; extend the …
willedibam Aug 14, 2026
1efa23f
Comment out disabled SPIs instead of deleting them; correct the max-P…
willedibam Aug 14, 2026
6d527e4
Correct the max-PLI justification: indicator, not band-dependent
willedibam Aug 14, 2026
14a363d
Reinstate the max-PLI variants with a documented caveat
willedibam Aug 14, 2026
0c88d8f
Fix empty-C CMI, restore CE as directed, disable unbounded dcoh
willedibam Aug 19, 2026
9a7ca87
Fix directed coherence rather than disable it; settle the max-PLI que…
willedibam Aug 19, 2026
9a8b3c9
CHANGELOG: log the CMI and ConditionalEntropy fixes; add references
willedibam Aug 19, 2026
964bf1c
Retract the max-PLI monotonicity claim; replace the invalid Wilson or…
willedibam Aug 19, 2026
fdc6b96
Weight directed coherence by the source variance; surface Wilson fail…
willedibam Aug 19, 2026
5371c93
Make CCM auto-embedding select an embedding, and stop pyEDM spawning …
willedibam Aug 19, 2026
fd5f278
Report CLI failures on stderr and exit non-zero on an empty table
willedibam Aug 19, 2026
ecff8f0
Grade drift per SPI, not per module; the loosened set measures as empty
willedibam Aug 19, 2026
0eedbe2
CHANGELOG: record the CCM, directed-coherence, CLI and tolerance changes
willedibam Aug 19, 2026
71c209d
Reinstate JIDT's k-NN normalisation and dither; one Gaussian ridge ev…
willedibam Aug 19, 2026
b08895a
Fix group delay against a known lag; make antisymmetric SPIs actually…
willedibam Aug 19, 2026
7efe861
Refuse the TE embedding parameters the symbolic and kernel estimators…
willedibam Aug 19, 2026
82ab531
Fix cross-correlation normalisation, lag window, orientation and sign…
willedibam Aug 19, 2026
0ab4db5
Spectral GC: pass fs to the parametric model, transform the NaN mask …
willedibam Aug 19, 2026
eaccf15
Make the test gates enforce what they measure; regenerate baselines
willedibam Aug 19, 2026
f716bed
Schedule on the cache SPIs actually share, not on the namespace
willedibam Aug 19, 2026
42c5202
Standardise information-theory units to nats; fix five semantic contr…
willedibam Aug 19, 2026
0c9947a
Close the result and identity contracts
willedibam Aug 19, 2026
d318ea1
Packaging: add a wheel/CLI CI job, fix the licence table, trim stale …
willedibam Aug 19, 2026
35001da
CHANGELOG: correct the parity and KSG-ties claims; record this pass
willedibam Aug 19, 2026
5e99d6c
bench: make per-cell seeds and resume identity independent of how it …
willedibam Aug 19, 2026
e3317b8
Validate bivariate process indices at the API boundary
willedibam Aug 19, 2026
39a5890
Validate kernel width, neighbour count and Theiler window at construc…
willedibam Aug 19, 2026
db6ead5
KSG: one dither draw per coordinate occurrence, not per column value
willedibam Aug 20, 2026
25e3085
Implement full MAX_CORR_AIS; refuse auto-embedding where it is not im…
willedibam Aug 20, 2026
a8322a7
Group delay: report samples, use |r| for fit quality, let traits win …
willedibam Aug 20, 2026
22fc797
Cross-correlation: `sigonly` returns zero when nothing clears the thr…
willedibam Aug 20, 2026
47b5431
Distances: keep `_rmse`, document what it claims, validate tau strictly
willedibam Aug 20, 2026
50003b3
Remove the cdt and torch dependencies
willedibam Aug 20, 2026
2def665
Reproducibility and packaging: bench seeds, name collisions, CLI exit…
willedibam Aug 20, 2026
a9ace20
Docs: correct stale claims about drift, spawn, units and the xfail set
willedibam Aug 20, 2026
36e9f30
Bump COMPUTATION_VERSION to 3.0.0.r2 and regenerate baselines
willedibam Aug 20, 2026
1e9ac2f
CHANGELOG: record the KSG dither, auto-embedding, group-delay and cdt…
willedibam Aug 20, 2026
972b07c
Correct the KSG auto-embedding boundary and the Gaussian TE oracle
willedibam Aug 20, 2026
fdd21b0
Validate the public numeric surface strictly instead of coercing it
willedibam Aug 20, 2026
4345577
Correct the KSG closed form and the remaining stale claims
willedibam Aug 20, 2026
81c34f4
Correct causal-statistic metadata; make structural traits authoritative
willedibam Aug 20, 2026
c094473
Make run_digest a content hash, not a path hash
willedibam Aug 20, 2026
dc7890a
Add a low-data stress suite; make KSG rescaling exact on tied data
willedibam Aug 20, 2026
ba2a7c4
Fix KSG conditioning and estimator contracts
willedibam Aug 20, 2026
979c87d
Tighten low-data contracts and correct stale guidance
willedibam Aug 20, 2026
b9fc709
Refuse tied inputs in KSG estimators
willedibam Aug 20, 2026
aa82545
Disable invalid edge inference and fix wavelet phase
willedibam Aug 20, 2026
8807108
Correct statistical contract documentation
willedibam Aug 20, 2026
9efb4e5
Fix strict KSG neighbour counts
willedibam Aug 20, 2026
61ebda7
Use circular reduction for coherence phase
willedibam Aug 20, 2026
9f6051d
Finish audit safeguards and migration docs
willedibam Aug 20, 2026
7f29d6a
Handle degenerate circular phase means
willedibam Aug 20, 2026
508fd7a
Clean tutorial and isolate slow CI runs
willedibam Aug 20, 2026
f5e4bc4
Trim benchmark artifacts and polish release notes
willedibam Aug 20, 2026
fd9c03e
Merge remote-tracking branch 'upstream/main' into v2
willedibam Aug 20, 2026
a552192
Support CalculatorFrame on pandas 3
willedibam Aug 22, 2026
1861be5
Accept singular directed-coherence stress refusals
willedibam Aug 22, 2026
65317c9
Drop pathological ANM from benchmarked p90
willedibam Aug 22, 2026
2e9a2e8
Merge remote-tracking branch 'upstream/main' into v3
willedibam Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions .github/workflows/run_dataset_generation.yaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
name: Generate benchmarking dataset tables

on:
on:
workflow_dispatch:

jobs:
test-ubuntu:
generate:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9"]
# Regenerating the baselines runs the full calculator many times over.
timeout-minutes: 360
steps:
- uses: actions/checkout@v4
- name: Setup python ${{ matrix.python-version }}

- name: Setup python 3.12
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
python-version: "3.12"
cache: 'pip'
- name: Install octave
run: |
sudo apt-get update
sudo apt-get install -y build-essential octave
- name: Install pyspi dependencies

- name: Install pyspi
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install .

- name: Run data generation
run: |
python tests/generate_benchmark_tables.py
run: python tests/tools/generate_benchmark_tables.py --dataset all

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: benchmark-tables
path: tests/CML7_benchmark_tables_new.pkl
# Glob rather than a fixed filename so this keeps working regardless of
# which baselines the script writes and what it names them.
path: tests/data/baselines/*.npz
if-no-files-found: error
108 changes: 108 additions & 0 deletions .github/workflows/run_package_tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Packaging Pipeline

# The unit-test job installs pyspi as an editable checkout, so it exercises the
# repository, not the artefact users receive. Everything that can only break in
# a built wheel -- a data file left out of package-data, a config or dataset
# resolved relative to the source tree, a console entry point that is not
# wired up -- is invisible to it. This job builds the wheel, installs it into a
# clean environment, and runs from a directory that contains no pyspi source.

on: [push, pull_request]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
wheel:
name: wheel / python ${{ matrix.python-version }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.12"]
steps:
- uses: actions/checkout@v4

- name: Setup python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Build the wheel
run: |
python -m pip install --upgrade pip build
python -m build --wheel --outdir dist/

- name: Install it into a clean environment
run: |
python -m venv /tmp/clean
/tmp/clean/bin/pip install --upgrade pip
/tmp/clean/bin/pip install dist/*.whl

# Run from an empty directory: from the repository root, `import pyspi`
# finds the source tree and the installed package is never touched.
- name: Import, resolve every bundled config and dataset, run fabfour
run: |
mkdir -p /tmp/run && cd /tmp/run
/tmp/clean/bin/python - <<'PY'
import os, tempfile
import numpy as np
import pyspi
from pyspi.calculator import (Calculator, bundled_configs, load_table,
load_spis_from_yaml, resolve_config)
from pyspi.data import available_datasets, load_dataset

for name in bundled_configs():
path = resolve_config(name)
assert os.path.exists(path), f"{name} -> {path}"
assert load_spis_from_yaml(path, quiet=True), name
for name in available_datasets():
load_dataset(name)

rng = np.random.default_rng(0)
calc = Calculator(dataset=rng.standard_normal((3, 100)), config="fabfour")
calc.compute()
assert not calc.errors, calc.errors

out = os.path.join(tempfile.mkdtemp(), "results.npz")
calc.save(out)
table = load_table(out)
assert np.allclose(table.to_numpy(), calc.table.to_numpy(), equal_nan=True)
assert table.attrs["run_digest"] == calc.run_digest
print("package smoke test OK")
PY

- name: Exercise the CLI
run: |
mkdir -p /tmp/cli && cd /tmp/cli
/tmp/clean/bin/python -c "import numpy as np; np.save('d.npy', np.random.default_rng(0).standard_normal((3, 100)))"
/tmp/clean/bin/python -m pyspi compute --data d.npy --config fabfour --output r.npz --quiet
/tmp/clean/bin/python -m pyspi --help
/tmp/clean/bin/python -c "
from pyspi.calculator import load_table
t = load_table('r.npz')
assert t.shape[0] == 3, t.shape
print('CLI round-trip OK')
"

lock:
name: locked resolution (uv.lock)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5

# The matrix above floats to the latest compatible dependencies, which is
# what catches upstream breakage. This pins to the committed lock, which
# is what makes a failure there attributable: if both jobs fail the change
# is ours, if only the floating one does it is a dependency's.
- name: Check the lock is current
run: uv lock --check

- name: Run the fast suite against the locked resolution
run: |
uv sync --locked --extra testing
uv run pytest -q
37 changes: 37 additions & 0 deletions .github/workflows/run_slow_tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Slow Regression Suite

# The slow suite compares every SPI against frozen baseline tables and takes
# a couple of minutes plus three full-config computations, so it is not run
# per-push. Pull requests, weekly, and on demand.
on:
pull_request:
schedule:
# 04:00 UTC every Monday.
- cron: '0 4 * * 1'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
slow-test:
name: regression (ubuntu / python 3.12)
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- uses: actions/checkout@v4

- name: Setup python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: 'pip'

- name: Install pyspi
run: |
python -m pip install --upgrade pip
pip install -e '.[testing]'

- name: Run regression tests
run: pytest -m slow
42 changes: 22 additions & 20 deletions .github/workflows/run_unit_tests.yaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
name: Unit Testing Pipeline

on:
push:
on: [push, pull_request]

# Supersede in-flight runs for the same ref; keep runs on different refs independent.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test-ubuntu:
runs-on: ubuntu-latest
test:
name: ${{ matrix.os }} / python ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
os: [ubuntu-latest, macos-latest]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4

- name: Setup python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install octave
run: |
sudo apt-get update
sudo apt-get install -y build-essential octave
- name: Install pyspi dependencies

- name: Install pyspi
run: |
python -m pip install --upgrade pip
pip install setuptools
pip install -r requirements.txt
pip install .
- name: Run pyspi calculator/utils unit tests
run: |
pytest -v ./tests/test_calc.py
pytest -v ./tests/test_utils.py
- name: Run pyspi SPI unit tests
run: |
pytest -v ./tests/test_SPIs.py
pip install -e '.[testing]'

- name: Run unit tests
# pyproject.toml sets addopts = "-m 'not slow'", so the baseline-drift
# suite is excluded here by design. See run_slow_tests.yaml for that.
run: pytest -q
36 changes: 29 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
pyspi.egg-info
pyspi/__pycache__
# Build artefacts
build/
dist/
*.egg-info/
**/__pycache__/**
dist

# Environments and tool caches
.venv/
.pytest_cache/
.ruff_cache/

# Data / logs. Regression baselines under tests/ are tracked deliberately.
*.pkl
!tests/*.pkl
*.log
*.bkp

# Editor / OS
.DS_Store
.vscode
build
octave-workspace
readme.html
.vscode/

# Exploratory notebooks: regenerable from bench/results/cells + analyse_cells,
# and they carry large non-rendering outputs. report.md is the tracked summary.
bench/results/analysis/*.ipynb

# Raw benchmark cells are large, machine-specific inputs to the tracked summaries.
bench/results/cells/physics_config*.json

# Local assistant instructions
CLAUDE.md
AGENTS.md
.claude/

# Review/critique artifacts (not part of the package)
critiques.md
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

Loading
Loading