statespacecheck 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. statespacecheck-0.1.0/.gitattributes +2 -0
  2. statespacecheck-0.1.0/.github/workflows/ci.yml +281 -0
  3. statespacecheck-0.1.0/.github/workflows/docs.yml +67 -0
  4. statespacecheck-0.1.0/.gitignore +155 -0
  5. statespacecheck-0.1.0/.pre-commit-config.yaml +42 -0
  6. statespacecheck-0.1.0/.python-version +1 -0
  7. statespacecheck-0.1.0/CHANGELOG.md +58 -0
  8. statespacecheck-0.1.0/CLAUDE.md +119 -0
  9. statespacecheck-0.1.0/CONTRIBUTING.md +478 -0
  10. statespacecheck-0.1.0/LICENSE +21 -0
  11. statespacecheck-0.1.0/PKG-INFO +373 -0
  12. statespacecheck-0.1.0/README.md +305 -0
  13. statespacecheck-0.1.0/docs/contributing.md +478 -0
  14. statespacecheck-0.1.0/docs/gen_ref_pages.py +36 -0
  15. statespacecheck-0.1.0/docs/index.md +144 -0
  16. statespacecheck-0.1.0/docs/javascripts/mathjax.js +8 -0
  17. statespacecheck-0.1.0/docs/tutorials/01_introduction.ipynb +1 -0
  18. statespacecheck-0.1.0/docs/tutorials/02_highest_density_regions.ipynb +1 -0
  19. statespacecheck-0.1.0/docs/tutorials/03_time_resolved_diagnostics.ipynb +1 -0
  20. statespacecheck-0.1.0/docs/tutorials/04_predictive_checks.ipynb +1 -0
  21. statespacecheck-0.1.0/docs/tutorials/index.md +120 -0
  22. statespacecheck-0.1.0/examples/01_introduction.ipynb +745 -0
  23. statespacecheck-0.1.0/examples/01_introduction.py +450 -0
  24. statespacecheck-0.1.0/examples/02_highest_density_regions.ipynb +1012 -0
  25. statespacecheck-0.1.0/examples/02_highest_density_regions.py +583 -0
  26. statespacecheck-0.1.0/examples/03_time_resolved_diagnostics.ipynb +951 -0
  27. statespacecheck-0.1.0/examples/03_time_resolved_diagnostics.py +565 -0
  28. statespacecheck-0.1.0/examples/04_predictive_checks.ipynb +973 -0
  29. statespacecheck-0.1.0/examples/04_predictive_checks.py +598 -0
  30. statespacecheck-0.1.0/examples/utils.py +314 -0
  31. statespacecheck-0.1.0/mkdocs.yml +124 -0
  32. statespacecheck-0.1.0/pyproject.toml +171 -0
  33. statespacecheck-0.1.0/src/statespacecheck/__init__.py +53 -0
  34. statespacecheck-0.1.0/src/statespacecheck/_validation.py +189 -0
  35. statespacecheck-0.1.0/src/statespacecheck/_version.py +34 -0
  36. statespacecheck-0.1.0/src/statespacecheck/highest_density.py +138 -0
  37. statespacecheck-0.1.0/src/statespacecheck/periods.py +567 -0
  38. statespacecheck-0.1.0/src/statespacecheck/predictive_checks.py +426 -0
  39. statespacecheck-0.1.0/src/statespacecheck/state_consistency.py +296 -0
  40. statespacecheck-0.1.0/src/statespacecheck/viz.py +137 -0
  41. statespacecheck-0.1.0/tests/conftest.py +205 -0
  42. statespacecheck-0.1.0/tests/test_edge_cases.py +268 -0
  43. statespacecheck-0.1.0/tests/test_highest_density.py +328 -0
  44. statespacecheck-0.1.0/tests/test_kl_subnormal.py +46 -0
  45. statespacecheck-0.1.0/tests/test_periods.py +562 -0
  46. statespacecheck-0.1.0/tests/test_predictive_consistency.py +242 -0
  47. statespacecheck-0.1.0/tests/test_predictive_density.py +293 -0
  48. statespacecheck-0.1.0/tests/test_predictive_pvalue.py +227 -0
  49. statespacecheck-0.1.0/tests/test_properties.py +390 -0
  50. statespacecheck-0.1.0/tests/test_state_consistency.py +310 -0
  51. statespacecheck-0.1.0/tests/test_validation.py +210 -0
  52. statespacecheck-0.1.0/tests/test_version.py +43 -0
  53. statespacecheck-0.1.0/tests/test_viz.py +204 -0
  54. statespacecheck-0.1.0/uv.lock +2829 -0
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,281 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - "v*"
9
+ pull_request:
10
+ branches:
11
+ - main
12
+
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ defaults:
18
+ run:
19
+ shell: bash
20
+
21
+ jobs:
22
+ quality:
23
+ name: Code Quality
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.12"
34
+
35
+ - name: Install uv
36
+ uses: astral-sh/setup-uv@v4
37
+
38
+ - name: Install dependencies
39
+ run: uv pip install --system -e .[dev]
40
+
41
+ - name: Run ruff format check
42
+ run: ruff format --check .
43
+
44
+ - name: Run ruff linting
45
+ run: ruff check . --output-format=github
46
+
47
+ - name: Run mypy type checking
48
+ run: mypy src/
49
+
50
+ test:
51
+ name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
52
+ runs-on: ${{ matrix.os }}
53
+ strategy:
54
+ fail-fast: false
55
+ matrix:
56
+ os: [ubuntu-latest, windows-latest, macos-latest]
57
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ with:
61
+ fetch-depth: 0
62
+
63
+ - name: Set up Python ${{ matrix.python-version }}
64
+ uses: actions/setup-python@v5
65
+ with:
66
+ python-version: ${{ matrix.python-version }}
67
+ allow-prereleases: true
68
+
69
+ - name: Install uv
70
+ uses: astral-sh/setup-uv@v4
71
+
72
+ - name: Install dependencies
73
+ run: uv pip install --system -e .[dev]
74
+
75
+ - name: Run tests with coverage
76
+ run: pytest --cov=statespacecheck --cov-report=xml --cov-report=term-missing
77
+
78
+ - name: Upload coverage to Codecov
79
+ if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest'
80
+ uses: codecov/codecov-action@v4
81
+ continue-on-error: true
82
+ with:
83
+ token: ${{ secrets.CODECOV_TOKEN }}
84
+ file: ./coverage.xml
85
+ flags: unittests
86
+ name: codecov-python-${{ matrix.python-version }}
87
+
88
+ build:
89
+ name: Build distribution
90
+ runs-on: ubuntu-latest
91
+ needs: [quality, test]
92
+ steps:
93
+ - uses: actions/checkout@v4
94
+ with:
95
+ fetch-depth: 0 # Required for hatch-vcs to get version from git tags
96
+
97
+ - name: Set up Python
98
+ uses: actions/setup-python@v5
99
+ with:
100
+ python-version: "3.12"
101
+
102
+ - name: Install uv
103
+ uses: astral-sh/setup-uv@v4
104
+
105
+ - name: Install build dependencies
106
+ run: uv pip install --system build twine
107
+
108
+ - name: Build sdist and wheel
109
+ run: python -m build
110
+
111
+ - name: Check distribution metadata
112
+ run: twine check dist/*
113
+
114
+ - name: List distribution contents
115
+ run: |
116
+ echo "=== Built distributions ==="
117
+ ls -lh dist/
118
+ echo ""
119
+ echo "=== Wheel contents ==="
120
+ unzip -l dist/*.whl || true
121
+ echo ""
122
+ echo "=== SDist contents ==="
123
+ tar -tzf dist/*.tar.gz | head -20 || true
124
+
125
+ - name: Upload distribution artifacts
126
+ uses: actions/upload-artifact@v4
127
+ with:
128
+ name: dist-${{ github.sha }}
129
+ path: dist/
130
+ retention-days: 7
131
+
132
+ test-install:
133
+ name: Test install from ${{ matrix.package }}
134
+ runs-on: ubuntu-latest
135
+ needs: [build]
136
+ strategy:
137
+ fail-fast: false
138
+ matrix:
139
+ package: ['wheel', 'sdist']
140
+ python-version: ["3.10", "3.13"]
141
+ steps:
142
+ - name: Download distribution artifacts
143
+ uses: actions/download-artifact@v4
144
+ with:
145
+ name: dist-${{ github.sha }}
146
+ path: dist/
147
+
148
+ - name: Set up Python ${{ matrix.python-version }}
149
+ uses: actions/setup-python@v5
150
+ with:
151
+ python-version: ${{ matrix.python-version }}
152
+
153
+ - name: Install from wheel
154
+ if: matrix.package == 'wheel'
155
+ run: pip install dist/*.whl
156
+
157
+ - name: Install from sdist
158
+ if: matrix.package == 'sdist'
159
+ run: pip install dist/*.tar.gz
160
+
161
+ - name: Verify installation
162
+ run: |
163
+ python -c "import statespacecheck; print('Package:', statespacecheck.__name__)"
164
+ python -c "import statespacecheck; print('Version:', statespacecheck.__version__)"
165
+ python -c "from statespacecheck import kl_divergence, hpd_overlap, highest_density_region; print('Imports successful')"
166
+
167
+ - name: Check public API
168
+ run: |
169
+ python -c "
170
+ import statespacecheck as ssc
171
+ expected = {'kl_divergence', 'hpd_overlap', 'highest_density_region',
172
+ 'predictive_density', 'log_predictive_density',
173
+ 'aggregate_over_period', 'predictive_pvalue',
174
+ 'DEFAULT_COVERAGE', 'DistributionArray'}
175
+ actual = set(ssc.__all__)
176
+ missing = expected - actual
177
+ extra = actual - expected
178
+ if missing:
179
+ raise ValueError(f'Missing from __all__: {missing}')
180
+ if extra:
181
+ print(f'Extra in __all__: {extra}')
182
+ print(f'✓ All {len(expected)} expected exports present')
183
+ "
184
+
185
+ publish-testpypi:
186
+ name: Publish to TestPyPI
187
+ runs-on: ubuntu-latest
188
+ needs: [test-install]
189
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
190
+ environment:
191
+ name: testpypi
192
+ url: https://test.pypi.org/project/statespacecheck/
193
+ permissions:
194
+ id-token: write
195
+ steps:
196
+ - name: Download distribution artifacts
197
+ uses: actions/download-artifact@v4
198
+ with:
199
+ name: dist-${{ github.sha }}
200
+ path: dist/
201
+
202
+ - name: Publish to TestPyPI
203
+ uses: pypa/gh-action-pypi-publish@release/v1
204
+ with:
205
+ repository-url: https://test.pypi.org/legacy/
206
+
207
+ publish-pypi:
208
+ name: Publish to PyPI
209
+ runs-on: ubuntu-latest
210
+ needs: [publish-testpypi]
211
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
212
+ environment:
213
+ name: pypi
214
+ url: https://pypi.org/project/statespacecheck/
215
+ permissions:
216
+ id-token: write
217
+ steps:
218
+ - name: Download distribution artifacts
219
+ uses: actions/download-artifact@v4
220
+ with:
221
+ name: dist-${{ github.sha }}
222
+ path: dist/
223
+
224
+ - name: Publish to PyPI
225
+ uses: pypa/gh-action-pypi-publish@release/v1
226
+
227
+ create-release:
228
+ name: Create GitHub Release
229
+ runs-on: ubuntu-latest
230
+ needs: [publish-pypi]
231
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
232
+ permissions:
233
+ contents: write
234
+ steps:
235
+ - uses: actions/checkout@v4
236
+ with:
237
+ fetch-depth: 0
238
+
239
+ - name: Download distribution artifacts
240
+ uses: actions/download-artifact@v4
241
+ with:
242
+ name: dist-${{ github.sha }}
243
+ path: dist/
244
+
245
+ - name: Extract version from tag
246
+ id: get_version
247
+ run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
248
+
249
+ - name: Generate release notes
250
+ id: release_notes
251
+ run: |
252
+ cat > release_notes.md << 'EOF'
253
+ ## statespacecheck v${{ steps.get_version.outputs.VERSION }}
254
+
255
+ Goodness-of-fit diagnostics for state space models in neuroscience.
256
+
257
+ ### Installation
258
+
259
+ ```bash
260
+ pip install statespacecheck==${{ steps.get_version.outputs.VERSION }}
261
+ ```
262
+
263
+ ### Documentation
264
+
265
+ See [README](https://github.com/edeno/statespacecheck#readme) for usage examples.
266
+
267
+ ### Changes
268
+
269
+ See [commit history](https://github.com/edeno/statespacecheck/commits/v${{ steps.get_version.outputs.VERSION }}) for detailed changes.
270
+ EOF
271
+
272
+ - name: Create GitHub Release
273
+ uses: softprops/action-gh-release@v2
274
+ with:
275
+ body_path: release_notes.md
276
+ files: dist/*
277
+ draft: false
278
+ prerelease: false
279
+ generate_release_notes: true
280
+ env:
281
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,67 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ paths:
11
+ - 'docs/**'
12
+ - 'mkdocs.yml'
13
+ - 'examples/**'
14
+ - '.github/workflows/docs.yml'
15
+
16
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
17
+ permissions:
18
+ contents: read
19
+ pages: write
20
+ id-token: write
21
+
22
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
23
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
24
+ concurrency:
25
+ group: "pages"
26
+ cancel-in-progress: false
27
+
28
+ jobs:
29
+ build:
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+
34
+ - name: Set up Python
35
+ uses: actions/setup-python@v5
36
+ with:
37
+ python-version: '3.12'
38
+
39
+ - name: Install uv
40
+ uses: astral-sh/setup-uv@v3
41
+ with:
42
+ enable-cache: true
43
+
44
+ - name: Install dependencies
45
+ run: |
46
+ uv pip install --system -e ".[docs]"
47
+
48
+ - name: Build docs
49
+ run: mkdocs build --strict
50
+
51
+ - name: Upload artifact
52
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
53
+ uses: actions/upload-pages-artifact@v3
54
+ with:
55
+ path: ./site
56
+
57
+ deploy:
58
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
59
+ environment:
60
+ name: github-pages
61
+ url: ${{ steps.deployment.outputs.page_url }}
62
+ runs-on: ubuntu-latest
63
+ needs: build
64
+ steps:
65
+ - name: Deploy to GitHub Pages
66
+ id: deployment
67
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,155 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ .pdm.toml
86
+ .pdm-python
87
+ .pdm-build/
88
+
89
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
90
+ __pypackages__/
91
+
92
+ # Celery stuff
93
+ celerybeat-schedule
94
+ celerybeat.pid
95
+
96
+ # SageMath parsed files
97
+ *.sage.py
98
+
99
+ # Environments
100
+ .env
101
+ .venv
102
+ env/
103
+ venv/
104
+ ENV/
105
+ env.bak/
106
+ venv.bak/
107
+
108
+ # Spyder project settings
109
+ .spyderproject
110
+ .spyproject
111
+
112
+ # Rope project settings
113
+ .ropeproject
114
+
115
+ # mkdocs documentation
116
+ /site
117
+ docs/.cache/
118
+ .mkdocs_cache/
119
+
120
+ # mypy
121
+ .mypy_cache/
122
+ .dmypy.json
123
+ dmypy.json
124
+
125
+ # Pyre type checker
126
+ .pyre/
127
+
128
+ # pytype static type analyzer
129
+ .pytype/
130
+
131
+ # Cython debug symbols
132
+ cython_debug/
133
+
134
+ # PyCharm
135
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
136
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
137
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
138
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
139
+ #.idea/
140
+
141
+ # Ruff stuff:
142
+ .ruff_cache/
143
+
144
+ # PyPI configuration file
145
+ .pypirc
146
+
147
+ # Cursor
148
+ # Cursor is an AI-powered code editor.`.cursorignore` specifies files/directories to
149
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
150
+ # refer to https://docs.cursor.com/context/ignore-files
151
+ .cursorignore
152
+ .cursorindexingignore
153
+ *.DS_Store
154
+ # VCS version file (auto-generated by hatch-vcs)
155
+ src/statespacecheck/_version.py
@@ -0,0 +1,42 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v6.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ exclude: '^mkdocs\.yml$'
9
+ - id: check-added-large-files
10
+ args: ['--maxkb=1000']
11
+ exclude: '^(docs/examples/.*\.ipynb|scripts/.*\.(pdf|png))$'
12
+ - id: check-merge-conflict
13
+ - id: debug-statements
14
+ - id: mixed-line-ending
15
+
16
+ - repo: https://github.com/astral-sh/ruff-pre-commit
17
+ rev: v0.14.3
18
+ hooks:
19
+ - id: ruff
20
+ args: [--fix]
21
+ exclude: '^docs/examples/.*\.(ipynb|py)$'
22
+ - id: ruff-format
23
+ exclude: '^docs/examples/.*\.(ipynb|py)$'
24
+
25
+ - repo: https://github.com/pre-commit/mirrors-mypy
26
+ rev: v1.13.0
27
+ hooks:
28
+ - id: mypy
29
+ files: ^src/
30
+ additional_dependencies:
31
+ - numpy>=1.26.0
32
+ - scipy>=1.11.0
33
+
34
+ - repo: local
35
+ hooks:
36
+ - id: pytest
37
+ name: pytest
38
+ entry: uv run pytest
39
+ language: system
40
+ pass_filenames: false
41
+ always_run: true
42
+ stages: [pre-commit]
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2025-11-11
9
+
10
+ ### Added
11
+
12
+ #### Core Diagnostics
13
+ - `kl_divergence()`: Measure information divergence between state distributions and likelihood
14
+ - `hpd_overlap()`: Compute spatial overlap between highest posterior density regions
15
+ - `highest_density_region()`: Compute boolean masks for highest density regions
16
+
17
+ #### Predictive Checks
18
+ - `predictive_density()`: Compute predictive density from state distribution and likelihood
19
+ - `log_predictive_density()`: Numerically stable log-space computation of predictive density
20
+ - `predictive_pvalue()`: Monte Carlo p-values for goodness-of-fit testing
21
+
22
+ #### Period Detection
23
+ - `flag_low_overlap()`: Identify time periods with poor posterior-likelihood agreement
24
+ - `flag_extreme_kl()`: Detect anomalous KL divergence using robust z-scores
25
+ - `flag_extreme_pvalues()`: Flag extreme predictive p-values
26
+ - `combine_flags()`: Aggregate multiple diagnostic flags with majority voting
27
+ - `find_low_overlap_intervals()`: Extract contiguous intervals of poor model fit
28
+ - `aggregate_over_period()`: Summarize metrics over time periods with flexible aggregation
29
+
30
+ #### Visualization
31
+ - `plot_diagnostics()`: Three-panel diagnostic visualization with time-resolved metrics
32
+ - Support for flagging problematic time periods in plots
33
+
34
+ #### Documentation
35
+ - Comprehensive README with neuroscience examples
36
+ - Four tutorial notebooks covering core concepts and workflows
37
+ - API reference documentation with mkdocs-material
38
+ - CONTRIBUTING.md with development guidelines
39
+
40
+ #### Infrastructure
41
+ - Full test suite with 230 tests and 100% code coverage
42
+ - Property-based testing with Hypothesis
43
+ - Type hints with strict mypy compliance
44
+ - Code quality enforcement with ruff (formatting and linting)
45
+ - Pre-commit hooks for automated checks
46
+ - CI/CD with GitHub Actions
47
+ - Automated documentation deployment
48
+
49
+ ### Features
50
+
51
+ - **Flexible Dimensionality**: Supports 1D `(n_time, n_position)` and 2D `(n_time, n_x, n_y)` spatial arrays
52
+ - **Robust Edge Cases**: Proper handling of NaN values, zero sums, and empty distributions
53
+ - **Automatic Normalization**: All functions normalize inputs automatically
54
+ - **Time-Resolved Analysis**: All metrics return time series for local model evaluation
55
+ - **Vectorized Operations**: Efficient NumPy-based implementation with no Python loops
56
+ - **Scientific Python Standards**: Follows SPEC 0 for version support and best practices
57
+
58
+ [0.1.0]: https://github.com/edeno/statespacecheck/releases/tag/v0.1.0