lzsuite 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.
- lzsuite-0.1.0/.gitignore +11 -0
- lzsuite-0.1.0/CHANGELOG.md +23 -0
- lzsuite-0.1.0/CITATION.cff +12 -0
- lzsuite-0.1.0/CONTRIBUTING.md +130 -0
- lzsuite-0.1.0/LICENSE +21 -0
- lzsuite-0.1.0/Makefile +41 -0
- lzsuite-0.1.0/PKG-INFO +281 -0
- lzsuite-0.1.0/README.md +254 -0
- lzsuite-0.1.0/docs/api.md +91 -0
- lzsuite-0.1.0/docs/maintenance.md +124 -0
- lzsuite-0.1.0/examples/overview.py +110 -0
- lzsuite-0.1.0/pyproject.toml +59 -0
- lzsuite-0.1.0/scripts/check_commit.py +33 -0
- lzsuite-0.1.0/scripts/check_wheel.py +25 -0
- lzsuite-0.1.0/src/lzsuite/__init__.py +23 -0
- lzsuite-0.1.0/src/lzsuite/_analysis.py +171 -0
- lzsuite-0.1.0/src/lzsuite/_arrays.py +57 -0
- lzsuite-0.1.0/src/lzsuite/_discretization.py +162 -0
- lzsuite-0.1.0/src/lzsuite/_distance.py +63 -0
- lzsuite-0.1.0/src/lzsuite/_encoding.py +52 -0
- lzsuite-0.1.0/src/lzsuite/_execution.py +48 -0
- lzsuite-0.1.0/src/lzsuite/py.typed +0 -0
- lzsuite-0.1.0/tests/test_analysis.py +178 -0
- lzsuite-0.1.0/tests/test_discretization.py +105 -0
- lzsuite-0.1.0/tests/test_distance.py +118 -0
- lzsuite-0.1.0/tests/test_execution.py +61 -0
- lzsuite-0.1.0/tests/test_public_api.py +35 -0
lzsuite-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-11-01)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* simplify single-sequence results and enable interactive parallelism
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* create initial array analysis and discretization library ([0c1ae2f](https://github.com/El3ssar/lzsuite/commit/0c1ae2f63ab8f201cd529dc24ded8e092b6cf89c))
|
|
13
|
+
* simplify single-sequence results and enable interactive parallelism ([02b189f](https://github.com/El3ssar/lzsuite/commit/02b189f290b25a6c331c5ff11b2b222a383e9c97))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **api:** expose only user functions and privatize implementation modules ([3baa1fc](https://github.com/El3ssar/lzsuite/commit/3baa1fcf9c48aa9ab637a2de0b8e84dc681d5745))
|
|
19
|
+
* **release:** bootstrap the first release without a synthetic previous version ([89beb7a](https://github.com/El3ssar/lzsuite/commit/89beb7aa8fd6b2ff8730ecdc13ad3952c96ea769))
|
|
20
|
+
|
|
21
|
+
## Changelog
|
|
22
|
+
|
|
23
|
+
Changes will be recorded here by release-please. Initial local development: 0.1.0.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use lzsuite, please cite this software and the underlying lzcomplexity engine as appropriate."
|
|
3
|
+
type: software
|
|
4
|
+
title: "lzsuite: Array-oriented Lempel–Ziv analysis and discretization"
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: "Estévez Moya"
|
|
7
|
+
given-names: "Daniel"
|
|
8
|
+
alias: "El3ssar"
|
|
9
|
+
repository-code: "https://github.com/El3ssar/lzsuite"
|
|
10
|
+
url: "https://github.com/El3ssar/lzsuite"
|
|
11
|
+
license: MIT
|
|
12
|
+
abstract: "A Python wrapper around lzcomplexity for multidimensional arrays, signal discretization, parallel sequence analysis, and information distances."
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Contributing to lzsuite
|
|
2
|
+
|
|
3
|
+
## Set up once
|
|
4
|
+
|
|
5
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
git clone https://github.com/El3ssar/lzsuite.git
|
|
9
|
+
cd lzsuite
|
|
10
|
+
uv sync --locked
|
|
11
|
+
uv run pre-commit install --hook-type pre-commit --hook-type commit-msg
|
|
12
|
+
uv run ipython
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or run `make setup`. Everything lives in the repository's `.venv` and uv cache;
|
|
16
|
+
no global Python packages or manual virtual-environment activation are needed.
|
|
17
|
+
The editable install reflects source edits immediately. Restart an interactive
|
|
18
|
+
session after changing already-imported modules.
|
|
19
|
+
|
|
20
|
+
`.python-version` selects Python 3.12 for routine development. `requires-python`
|
|
21
|
+
in `pyproject.toml` sets the supported minimum to 3.10. `uv.lock` records the exact
|
|
22
|
+
development dependency versions across supported interpreters.
|
|
23
|
+
|
|
24
|
+
## Everyday workflow
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
git switch -c fix/describe-the-change
|
|
28
|
+
# Edit source, tests, documentation, or examples.
|
|
29
|
+
make check
|
|
30
|
+
make build
|
|
31
|
+
git add <changed-files>
|
|
32
|
+
git commit -m "fix: describe the resulting behavior"
|
|
33
|
+
git push -u origin HEAD
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The individual checks are:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
uv run --locked ruff check .
|
|
40
|
+
uv run --locked ruff format --check .
|
|
41
|
+
uv run --locked pytest --cov=lzsuite
|
|
42
|
+
uv build
|
|
43
|
+
uv run --locked twine check dist/*
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use `uv run ruff format .` to format edits, and `uv run ruff check . --fix` for
|
|
47
|
+
automatic lint fixes. Local hooks run lint/format checks and validate commit
|
|
48
|
+
subjects. CI also checks the PR title; use a Conventional Commit title so squash
|
|
49
|
+
merging preserves the release intent.
|
|
50
|
+
|
|
51
|
+
## Code map
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
src/lzsuite/
|
|
55
|
+
__init__.py Public function exports and installed package version
|
|
56
|
+
_analysis.py Complexity, h, factorization, E, full results
|
|
57
|
+
_distance.py All-pairs and corresponding-pair NID
|
|
58
|
+
_discretization.py Built-ins, registry, callable validation
|
|
59
|
+
_arrays.py Axis handling and sequence preparation
|
|
60
|
+
_encoding.py Byte encodings and shared distance codebooks
|
|
61
|
+
_execution.py Inline execution and joblib/loky process workers
|
|
62
|
+
tests/ Backend comparisons, contracts, execution, namespace
|
|
63
|
+
examples/overview.py Commented executable walkthrough
|
|
64
|
+
docs/ API and maintenance guides
|
|
65
|
+
.github/workflows/ CI and release automation
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Keep implementation modules private. Add a top-level export only when it is a
|
|
69
|
+
function users should call, and update `tests/test_public_api.py` deliberately.
|
|
70
|
+
Avoid adding helper imports to the public namespace.
|
|
71
|
+
|
|
72
|
+
## Tests that matter
|
|
73
|
+
|
|
74
|
+
Tests compare against the real installed lzcomplexity engine, including both E
|
|
75
|
+
estimators. Cover scientific encoding choices, arbitrary axes, shape preservation,
|
|
76
|
+
1D native return types, registry behavior, warning/error cases, and agreement
|
|
77
|
+
between serial and parallel execution.
|
|
78
|
+
|
|
79
|
+
When changing execution, check both the result and the process/thread budget.
|
|
80
|
+
Workers use one Rayon thread; the caller's configuration must remain unchanged.
|
|
81
|
+
When changing a discretizer, include meaningful edge cases such as ties, constant
|
|
82
|
+
signals, and shortened output. Custom methods need no output-length declaration.
|
|
83
|
+
|
|
84
|
+
CI runs Python 3.10–3.14 on Linux and Python 3.12 on macOS and Windows. To test
|
|
85
|
+
another interpreter locally without replacing the default environment:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
UV_PROJECT_ENVIRONMENT=.venv-py310 uv run --locked --python 3.10 pytest
|
|
89
|
+
UV_PROJECT_ENVIRONMENT=.venv-py314 uv run --locked --python 3.14 pytest
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
CI also checks an installed wheel and the minimum NumPy/joblib dependencies.
|
|
93
|
+
For interactive smoke testing, `uv run ipython` can call `lzs.h(data)` directly,
|
|
94
|
+
including its default parallel path.
|
|
95
|
+
|
|
96
|
+
## Dependencies and versioning
|
|
97
|
+
|
|
98
|
+
Runtime requirements live in `pyproject.toml`; reproducible development versions
|
|
99
|
+
live in `uv.lock`. Commit both files when a requirement changes. A lockfile pin
|
|
100
|
+
is not the same as a published package requirement.
|
|
101
|
+
|
|
102
|
+
Use Conventional Commits:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
feat(discretization): add fixed-edge binning
|
|
106
|
+
fix(distance): preserve category meanings across inputs
|
|
107
|
+
perf: reuse calculation work
|
|
108
|
+
refactor: simplify internal array handling
|
|
109
|
+
docs: explain normalization
|
|
110
|
+
feat!: change public result shapes
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`feat` proposes a minor bump; `fix` and `perf` propose patch bumps. A `!` or
|
|
114
|
+
`BREAKING CHANGE:` footer declares a breaking change. Under the current default
|
|
115
|
+
policy, breaking changes bump the major version even while the version is 0.x.
|
|
116
|
+
Merging a normal feature PR does not publish a release: release-please prepares
|
|
117
|
+
a separate release PR for review.
|
|
118
|
+
|
|
119
|
+
See [docs/maintenance.md](docs/maintenance.md) for the exact dependency-update
|
|
120
|
+
commands, release procedure, and remaining PyPI/Zenodo setup. Do not hand-edit
|
|
121
|
+
versions in several files: release-please updates `pyproject.toml`, `uv.lock`,
|
|
122
|
+
the release manifest, and the changelog together.
|
|
123
|
+
|
|
124
|
+
## Reporting problems
|
|
125
|
+
|
|
126
|
+
Open an [issue](https://github.com/El3ssar/lzsuite/issues) with a small input,
|
|
127
|
+
its dtype and shape, the call and parameters, the expected/actual behavior,
|
|
128
|
+
Python/platform information, and the lzsuite/lzcomplexity/NumPy versions. Include
|
|
129
|
+
`n_jobs` when reporting parallel-execution issues. Keep scientific data private
|
|
130
|
+
unless you have permission to share it.
|
lzsuite-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lzsuite contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lzsuite-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
.PHONY: help setup check test lint format build deps-backend deps-update
|
|
2
|
+
|
|
3
|
+
help:
|
|
4
|
+
@echo "setup Install locked dev environment and local hooks"
|
|
5
|
+
@echo "check Run lint, format checks, and tests"
|
|
6
|
+
@echo "test Run tests with coverage"
|
|
7
|
+
@echo "lint Check lint and formatting"
|
|
8
|
+
@echo "format Apply lint fixes and formatting"
|
|
9
|
+
@echo "build Build and validate wheel and source archive"
|
|
10
|
+
@echo "deps-backend Update lzcomplexity within its declared range"
|
|
11
|
+
@echo "deps-update Update all dependency locks within declared ranges"
|
|
12
|
+
|
|
13
|
+
setup:
|
|
14
|
+
uv sync --locked
|
|
15
|
+
uv run --no-sync pre-commit install --hook-type pre-commit --hook-type commit-msg
|
|
16
|
+
|
|
17
|
+
check: lint test
|
|
18
|
+
|
|
19
|
+
lint:
|
|
20
|
+
uv run --locked ruff check .
|
|
21
|
+
uv run --locked ruff format --check .
|
|
22
|
+
|
|
23
|
+
test:
|
|
24
|
+
uv run --locked pytest --cov=lzsuite
|
|
25
|
+
|
|
26
|
+
format:
|
|
27
|
+
uv run --locked ruff check . --fix
|
|
28
|
+
uv run --locked ruff format .
|
|
29
|
+
|
|
30
|
+
build:
|
|
31
|
+
uv build
|
|
32
|
+
uv run --locked twine check dist/*
|
|
33
|
+
|
|
34
|
+
deps-backend:
|
|
35
|
+
uv lock --upgrade-package lzcomplexity
|
|
36
|
+
uv sync --locked
|
|
37
|
+
|
|
38
|
+
# Review the lockfile diff and run make check/build before committing updates.
|
|
39
|
+
deps-update:
|
|
40
|
+
uv lock --upgrade
|
|
41
|
+
uv sync --locked
|
lzsuite-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: lzsuite
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Array-oriented Lempel–Ziv analysis and signal discretization.
|
|
5
|
+
Project-URL: Homepage, https://github.com/El3ssar/lzsuite
|
|
6
|
+
Project-URL: Repository, https://github.com/El3ssar/lzsuite
|
|
7
|
+
Project-URL: Documentation, https://github.com/El3ssar/lzsuite#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/El3ssar/lzsuite/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/El3ssar/lzsuite/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Daniel Estévez Moya
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: joblib<2,>=1.5
|
|
24
|
+
Requires-Dist: lzcomplexity<4,>=3.0.0
|
|
25
|
+
Requires-Dist: numpy>=1.24
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# lzsuite
|
|
29
|
+
|
|
30
|
+
[](https://github.com/El3ssar/lzsuite/actions/workflows/ci.yml)
|
|
31
|
+
[](https://github.com/El3ssar/lzsuite/blob/main/pyproject.toml)
|
|
32
|
+
[](LICENSE)
|
|
33
|
+
|
|
34
|
+
Lempel–Ziv analysis for multidimensional NumPy arrays. Choose the axis containing
|
|
35
|
+
observations, optionally discretize continuous signals, and calculate complexity,
|
|
36
|
+
entropy density, effective measure complexity, or information distances across
|
|
37
|
+
all remaining positions.
|
|
38
|
+
|
|
39
|
+
[lzcomplexity](https://github.com/pleros-ai/lzcomplexity) supplies the numerical
|
|
40
|
+
engine. lzsuite adds array handling, discretization, shared symbol encodings,
|
|
41
|
+
and parallel calculation across sequences.
|
|
42
|
+
|
|
43
|
+
**Early development:** the API can evolve. The repository is available on GitHub;
|
|
44
|
+
PyPI publication and Zenodo registration are planned separately.
|
|
45
|
+
|
|
46
|
+
## Install and try it
|
|
47
|
+
|
|
48
|
+
From the repository, using [uv](https://docs.astral.sh/uv/):
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
git clone https://github.com/El3ssar/lzsuite.git
|
|
52
|
+
cd lzsuite
|
|
53
|
+
uv sync --locked
|
|
54
|
+
uv run ipython
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This creates a local `.venv`, installs lzsuite in editable mode, and installs the
|
|
58
|
+
locked development tools. No activation or global Python packages are needed.
|
|
59
|
+
For a regular environment without uv, use `python -m pip install .` after cloning.
|
|
60
|
+
Python 3.10+ is required; development defaults to Python 3.12.
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
These are separate snippets you can run in the same IPython session.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import numpy as np
|
|
68
|
+
import lzsuite as lzs
|
|
69
|
+
|
|
70
|
+
rng = np.random.default_rng(42)
|
|
71
|
+
signal = rng.normal(size=1000)
|
|
72
|
+
data = rng.normal(size=(1000, 4, 3)) # observations × channels × trials
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
One sequence returns an ordinary Python value. No scalar extraction is needed:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
entropy = lzs.h(signal) # float
|
|
79
|
+
count = lzs.complexity(signal) # int
|
|
80
|
+
count, boundaries = lzs.factorization(signal)
|
|
81
|
+
score, increments = lzs.emc(signal) # float and list
|
|
82
|
+
result = lzs.lz76(signal) # dict
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Arrays retain the dimensions outside the sequence axis, which defaults to 0:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
entropy = lzs.h(data) # shape (4, 3)
|
|
89
|
+
counts = lzs.complexity(data) # shape (4, 3)
|
|
90
|
+
scores, profiles = lzs.emc(data, max_block_size=8)
|
|
91
|
+
results = lzs.lz76(data, max_block_size=8)
|
|
92
|
+
results[0, 0]["emc"]["value"] # first channel, first trial
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Other axes and noncontiguous views work too:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
observations_last = np.moveaxis(data, 0, -1) # shape (4, 3, 1000)
|
|
99
|
+
np.allclose(entropy, lzs.h(observations_last, axis=-1)) # True
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
A singleton batch dimension is preserved: input `(1000, 1)` returns shape `(1,)`.
|
|
103
|
+
Only a truly 1D input gets the direct Python result. See the full
|
|
104
|
+
[API reference](docs/api.md) for return types.
|
|
105
|
+
|
|
106
|
+
## Discretization
|
|
107
|
+
|
|
108
|
+
Float arrays use mean binarization by default, independently for each sequence.
|
|
109
|
+
Integers, booleans, and string-array elements are already symbols. An explicitly
|
|
110
|
+
selected discretizer overrides the default for numeric inputs; strings cannot
|
|
111
|
+
be passed to a discretizer.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
lzs.available_discretizers()
|
|
115
|
+
# ('bins', 'mean', 'median', 'permutation', 'quantile')
|
|
116
|
+
|
|
117
|
+
labels = lzs.discretize(signal, method="median") # use a method directly
|
|
118
|
+
entropy = lzs.h(data, discretization="median") # or inside a calculation
|
|
119
|
+
entropy = lzs.h(data, discretization="bins", discretization_kwargs={"n_bins": 4})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
| Method | Rule | Parameters |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `mean` | Above the sequence mean → 1; equality/below → 0 | — |
|
|
125
|
+
| `median` | Above the sequence median → 1; equality/below → 0 | — |
|
|
126
|
+
| `bins` | Equally wide bins spanning the sequence's range | `n_bins=2` |
|
|
127
|
+
| `quantile` | Bins using empirical quantile edges | `n_bins=2` |
|
|
128
|
+
| `permutation` | Labels for the ordering within delayed windows | `order=3`, `delay=1` |
|
|
129
|
+
|
|
130
|
+
Values on internal bin edges go right. Repeated quantile edges collapse, and
|
|
131
|
+
constant signals yield zero labels. Bin edges are fitted separately per sequence;
|
|
132
|
+
pass a custom method using fixed edges if comparisons require shared thresholds.
|
|
133
|
+
Permutation ties are ordered by position, earlier first. Permutation output has
|
|
134
|
+
`len(signal) - (order - 1) * delay` entries; it is a discretization, not a
|
|
135
|
+
permutation-entropy calculation.
|
|
136
|
+
|
|
137
|
+
### Your own methods
|
|
138
|
+
|
|
139
|
+
A method receives a numeric 1D array and returns a nonempty 1D array of integer
|
|
140
|
+
labels. Its output length can change. The input is copied before calling it, so
|
|
141
|
+
in-place changes do not modify your original data.
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
def threshold(values, *, level=0.0):
|
|
145
|
+
return (values > level).astype(np.uint8)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
lzs.h(data, discretization=threshold) # directly supplied callable
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Register the same function for reuse by name:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
lzs.register_discretizer("threshold", threshold, replace=True)
|
|
155
|
+
lzs.h(data, discretization="threshold", discretization_kwargs={"level": 0.5})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Decorator registration is also supported:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
@lzs.register_discretizer("every_other", replace=True)
|
|
162
|
+
def every_other(values):
|
|
163
|
+
return (values[::2] > 0).astype(np.uint8)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
lzs.h(data, discretization="every_other")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Registration is local to the Python session. Existing names require
|
|
170
|
+
`replace=True` to overwrite. Discretization runs in the calling process, so
|
|
171
|
+
functions defined interactively work with parallel calculations too.
|
|
172
|
+
|
|
173
|
+
## Information distances
|
|
174
|
+
|
|
175
|
+
One input calculates every pair of sequences:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
matrix = lzs.distance(data) # shape (12, 12)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Rows and columns follow C-order flattening of `(channel, trial)`. Here,
|
|
182
|
+
`(channel, trial)` corresponds to row `channel * 3 + trial`. The matrix is
|
|
183
|
+
symmetric and retains actual self-distances, which may be nonzero.
|
|
184
|
+
|
|
185
|
+
Two inputs compare corresponding sequences:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
other = rng.normal(size=(800, 4, 3))
|
|
189
|
+
paired = lzs.distance(data, other) # shape (4, 3)
|
|
190
|
+
single = lzs.nid(signal, other[:, 0, 0]) # float; nid is an alias for distance
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Shapes outside the sequence axis must match exactly; sequence lengths may differ.
|
|
194
|
+
There is no broadcasting. A shared codebook keeps category meanings consistent
|
|
195
|
+
across the inputs. The two-input mode does not compute all cross-pairs.
|
|
196
|
+
A single 1D input to `distance` still gives a `(1, 1)` all-pairs matrix.
|
|
197
|
+
|
|
198
|
+
Both modes accept `axis`, `discretization`, `discretization_kwargs`, and `n_jobs`.
|
|
199
|
+
For float inputs, the default mean threshold is fitted independently to each
|
|
200
|
+
sequence in each input.
|
|
201
|
+
|
|
202
|
+
## Parallel execution and Rayon
|
|
203
|
+
|
|
204
|
+
**Default: up to four worker processes**, capped by available CPUs and the number
|
|
205
|
+
of calculations. This works in scripts, IPython, and notebooks using joblib's
|
|
206
|
+
loky process runner. Workers are reused across calls to reduce repeated startup.
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
lzs.h(data) # up to 4 processes
|
|
210
|
+
lzs.h(data, n_jobs=1) # inline calculation; no worker processes
|
|
211
|
+
lzs.h(data, n_jobs=2) # up to 2 processes
|
|
212
|
+
lzs.distance(data, n_jobs=-1) # all available CPUs, capped by pair count
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Each worker uses **one Rayon thread**. Thus four worker processes share the
|
|
216
|
+
calculation workload without each starting a full native thread pool. Worker
|
|
217
|
+
configuration is local to those processes; lzsuite does not change the calling
|
|
218
|
+
process's `RAYON_NUM_THREADS` or initialized Rayon pool. Other common native
|
|
219
|
+
thread pools are also limited to one thread per worker.
|
|
220
|
+
|
|
221
|
+
The inline path (`n_jobs=1`, a single calculation, or one available CPU) preserves
|
|
222
|
+
the calling process's existing native configuration, so lzcomplexity can still
|
|
223
|
+
use Rayon internally there. Discretization, validation, and encoding happen in
|
|
224
|
+
the calling process before native work is distributed.
|
|
225
|
+
|
|
226
|
+
Parallelism can use more memory and is not necessarily faster for small inputs.
|
|
227
|
+
Use `n_jobs=1` when process startup outweighs the calculation. All-pairs matrices
|
|
228
|
+
require quadratic result storage.
|
|
229
|
+
|
|
230
|
+
## Scientific conventions and validation
|
|
231
|
+
|
|
232
|
+
- The logarithm base defaults to each discretized sequence's distinct-symbol
|
|
233
|
+
count, with a minimum of 2. Use `log_base=2` for explicit bit units. Different
|
|
234
|
+
observed alphabet sizes imply different normalization bases.
|
|
235
|
+
- E defaults to Chao–Shen. `method="shuffle"` selects the alternative estimator
|
|
236
|
+
in `emc` and `lz76`; this option is separate from `discretization`.
|
|
237
|
+
- Numeric symbols are encoded as individual bytes. Each string-array element is
|
|
238
|
+
one category, including multi-character strings. To analyze text characters,
|
|
239
|
+
use `np.array(list("banana"))`.
|
|
240
|
+
- More than 256 distinct symbols emits `RuntimeWarning` and continues with
|
|
241
|
+
category codes reduced modulo 256. Some categories then merge, so results do
|
|
242
|
+
not faithfully describe the original alphabet. Analysis normalization still
|
|
243
|
+
uses the original symbol count; distances check the shared vocabulary.
|
|
244
|
+
- Empty sequences, NaN, infinity, complex values, and object arrays are rejected.
|
|
245
|
+
Empty collections with a nonempty sequence axis return empty arrays.
|
|
246
|
+
- Factor boundaries retain the backend's final-tail convention and can extend
|
|
247
|
+
beyond the sequence end. NID does not force self-distance to zero.
|
|
248
|
+
|
|
249
|
+
Save the discretization settings, sequence length, log base, E method/range,
|
|
250
|
+
package versions, and input data or fingerprint with scientific results.
|
|
251
|
+
|
|
252
|
+
## Development and maintenance
|
|
253
|
+
|
|
254
|
+
```sh
|
|
255
|
+
make setup # editable install plus local lint/commit hooks
|
|
256
|
+
make check # lint, formatting, tests
|
|
257
|
+
make build # wheel, source archive, package metadata checks
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The commands are also listed individually in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
261
|
+
The development environment is locked in `uv.lock`; runtime compatibility ranges
|
|
262
|
+
are declared in `pyproject.toml`. The backend dependency is currently
|
|
263
|
+
`lzcomplexity>=3.0.0,<4`, preventing an unreviewed major-version upgrade. See the
|
|
264
|
+
[maintenance and release guide](docs/maintenance.md) for dependency updates,
|
|
265
|
+
versioning, GitHub releases, and the future PyPI/Zenodo steps.
|
|
266
|
+
|
|
267
|
+
Conventional Commits drive release-please version/changelog PRs. Merging a release
|
|
268
|
+
PR creates the `vX.Y.Z` tag and GitHub release. CI checks Python 3.10–3.14 on Linux,
|
|
269
|
+
plus macOS and Windows, and builds package distributions. **There is no PyPI
|
|
270
|
+
upload or Zenodo registration in the current workflows.**
|
|
271
|
+
|
|
272
|
+
The public API contains only callable user functions; implementation modules are
|
|
273
|
+
private. `lzs.__version__` gives the installed version. A complete executable
|
|
274
|
+
walkthrough is in [examples/overview.py](examples/overview.py).
|
|
275
|
+
|
|
276
|
+
## License and attribution
|
|
277
|
+
|
|
278
|
+
MIT licensed; see [LICENSE](LICENSE). The LZ76 engine and estimator implementation
|
|
279
|
+
are provided by [lzcomplexity](https://github.com/pleros-ai/lzcomplexity), with its
|
|
280
|
+
own authorship and scientific references. Software citation metadata for this
|
|
281
|
+
wrapper is in [CITATION.cff](CITATION.cff).
|