Skip to main content

lzcomplexity

LZ76-based complexity analysis for symbolic sequences and time-series.

MIT Python Rust

lzcomplexity computes information-theoretic measures of symbolic sequences using Lempel–Ziv 76 (LZ76) factorization [1]. The LZ76 complexity c(S) is the minimum number of factors needed to represent a sequence, where each factor is either a new symbol or the longest previously-seen substring. From c(S) you get a non-parametric entropy-rate estimator — h ≈ c(S)·log_k(n)/n — that converges to the true entropy rate of ergodic sources [2].

The library ships two things:

  1. A Python library (import lzcomplexity) built on a Rust core via PyO3.
  2. Two standalone command-line tools — lzcomplexity and lzdistance.

The core is implemented in Rust; the two front-ends share it. Common applications: neuroscience time-series, DNA analysis, anomaly detection, structural pattern analysis.

This is the Rust implementation, the current production backend. The original C++/nanobind implementation lives on the main branch. Numerical outputs are equivalent up to deterministic shuffle seeding (see Differences from the C++ version).

Spectral analysis (psd, spectral entropy, semc) has been removed from this library and now lives in a separate package.


Python library

Install

You need Python ≥ 3.9. From PyPI:

pip install lzcomplexity

Or from a clone of this repository (requires a Rust toolchain):

pip install .

pip invokes maturin, which compiles the Rust workspace, produces a wheel, and installs it. No CMake, no submodules, no C++ toolchain.

Development install

python3 -m venv .venv
source .venv/bin/activate
pip install maturin
maturin develop --release

Re-run maturin develop --release after Rust changes.

Quick start

import lzcomplexity as lz

# Complexity + factor boundaries — factor i spans [factors[i], factors[i+1])
complexity, factors = lz.factorization("banana")
# → (3, [0, 1, 2, 3, 7])

# Normalised entropy density / entropy-rate estimator — `h`
lz.h("01010101")
# → 0.75

# Effective measure complexity: the value and the terms that sum to it
emc_value, summands = lz.emc("01001010101101010101110101010101010000100101011")

# Everything in one call (returns a dict)
full = lz.lz76("ABRACADABRA")
full["complexity"], full["h"], full["factors"]
full["emc"]     # {"value", "summands", "max_block_size", "multi_information"}
full["extras"]  # {"rajski_distance", "redundancy", "fh_uncertainty", ...}

# Normalized information distance (NID) between two sequences
lz.nid("ABRACADABRA", "ABRACADABRZ")     # → small, similar
lz.nid("ABRACADABRA", "ZYXWVUTSRQP")     # → large, dissimilar

Public API

Symbol Signature Returns
lz.factorization(seq, ...) complexity + factor boundaries (int, list[int])
lz.h(seq, ...) normalised entropy density (entropy rate) float
lz.emc(seq, ...) effective measure complexity (float, list[float]) — (value, summands)
lz.nid(seq1, seq2, ...) normalised information distance float
lz.lz76(seq, ...) the full analysis dict (see below)

lz.lz76(...) returns a dict with keys: complexity, h, factors, emc (a nested dict), epsilon, factors_stddev, normal_error, poison_error, extras (a nested dict).

Common keyword arguments:

  • partitions (int, default 1) — suffix-array partition count; performance knob, no effect on results.
  • alphabet (int | None, default None) — auto-detect (distinct symbols, min 2) when None.
  • log_base (int | None, default None) — matches alphabet when None (normalised entropy in units of symbols); pass 2 for bits.
  • max_block_size (int, default −1) — shuffle block-size cap for emc/lz76; −1 auto-selects.
  • jobs (int, default 0) — reserved; currently ignored (rayon manages its pool).

Run help(lzcomplexity.<name>) for full per-function docs. Type stubs (__init__.pyi) ship with the package.

Accepted input types

Every sequence-accepting function accepts any of:

  • str — symbols taken from the string bytes directly.
  • bytes — raw byte sequence.
  • list[str] — concatenated as-is (e.g. ["A","C","G","T"]).
  • list[int] — each element becomes its decimal string, concatenated, so [0, 1, 10] → "0110".
  • Any iterable of ints — covers NumPy arrays; same conversion as list[int].

Standalone binaries

Two command-line tools are built from the same Rust core.

Build them from a clone:

cargo build --release
# → target/release/lzcomplexity   and   target/release/lzdistance

Prebuilt binaries for Linux/macOS/Windows are attached to each GitHub release.

lzcomplexity

Reads a sequence file and writes a JSON report with the LZ76 complexity, entropy density, and random-shuffle effective measure complexity.

lzcomplexity input.txt                 # → input.lz76.json
lzcomplexity input.txt -m -d           # multi-line + distance between consecutive lines
lzcomplexity input.txt -n              # entropy density only
lzcomplexity input.txt -a 4 -l 2       # explicit alphabet / log base

Key flags: -a/--alphabet, -l/--log-base, -p/--partitions, -m/--multi-line, -d/--dlz, -n/--entropy-density, -f/--factors <file>, -F/--format <fmt>, -o/--output, -v/--verbose, -V/--version.

lzdistance

Computes pairwise information-distance and shuffle-distance matrices between one or two data sources (files or directories).

lzdistance sequences.txt               # self-distance matrix (first_dim × first_dim)
lzdistance A.txt B.txt                  # cross matrix
lzdistance genomes/ -a                  # a directory of files, DNA complement-aware
lzdistance A.txt B.txt -g 5             # also emit the directed graph

Key flags: -a/--adn (DNA), -b/--binary, -r/--reverse, -y/--trajectory, -g/--get-direction [threshold], -I/--first-format, -S/--second-format, -i/--first #:#, -s/--second #:#, -p/--partitions, -o/--output, -L/--logs, -v/--version.

Input formats

Both tools auto-detect the format (or accept -F/-I/-S): raw text and binary, CSV/TSV, PBM/PGM images (P1/P2/P4/P5), and FASTA/DNA/RNA (including .gz). Use -m (or a directory) to treat each line/file as a separate sequence.


Contributing & releases

This repo uses Conventional Commits together with release-please so that versioning and PyPI publishing happen automatically — you never bump a version or push a tag by hand.

How to commit

Prefix every commit title with a type:

Prefix Use for Version effect (pre-1.0)
feat: a new feature bumps the minor (0.11 → 0.12)
fix: a bug fix bumps the patch (0.11.0 → 0.11.1)
perf: a performance improvement patch
refactor:, docs:, build:, ci:, test:, chore: everything else no release on its own

Add ! after the type (e.g. feat!:) or a BREAKING CHANGE: footer to force a larger bump.

feat: add spectral-free NID batch mode
fix: correct off-by-one in PGM reader
docs: document the lzdistance directed graph

What happens automatically

The Python package is released from the rust-backend branch; the C++ main branch is kept only as a verification reference and is not published.

  1. You merge conventional commits into rust-backend.
  2. release-please opens (and keeps updating) a "release PR" that bumps the version in Cargo.toml and pyproject.toml, and updates CHANGELOG.md.
  3. When you merge that release PR, release-please tags the release (vX.Y.Z) and creates a GitHub release.
  4. The Release workflow then builds the wheels with maturin, publishes them to PyPI via OIDC trusted publishing (no token needed), and attaches the standalone binaries to the GitHub release.

So the entire flow is: write conventional commits → merge the release PR → PyPI updates itself.

One-time setup on PyPI: the trusted publisher for the lzcomplexity project (Settings → Publishing) is keyed on the repository and the workflow filename (plus an optional environment) — not on a branch. Point its Workflow name at release.yml (the previous C++ setup used wheels.yml). No API token or secret is stored in the repo.

CI

Every push and PR runs CI: cargo fmt --check, cargo clippy -D warnings, cargo test, a smoke test of both standalone binaries, and a wheel build + Python API smoke test on Linux/macOS/Windows.


Repository layout

crates/
├── lzcomplexity-core/   Rust crate: algorithms (LZ76, suffix array, LPF,
│                        shuffle, metrics). No Python or CLI types.
├── lzcomplexity-py/     PyO3 bindings → the `lzcomplexity` Python extension.
└── lzcomplexity-cli/    The `lzcomplexity` and `lzdistance` binaries.
python/lzcomplexity/     Python package skin: __init__.py, __init__.pyi, py.typed.
pyproject.toml           Maturin build config.

cargo test --workspace exercises the algorithmic core.


Differences from the C++ version

Aspect C++ (main branch) Rust (this branch)
Build system CMake + nanobind Cargo + maturin
Suffix array CaPS (custom parallel) suffix crate + Kasai LCP
Parallelism OpenMP / TBB / Cilk rayon
Shuffle RNG std::mt19937 (time-seeded) ChaCha8 (seeded from input → deterministic)
Spectral analysis included (psd, entropy, semc) removed (moved to a separate package)
Python surface many names, nid/rid, class exports factorization, h, emc, nid, lz76

Same input ⇒ same outputs across Rust and C++ within float tolerance for the deterministic measures (factorization, factors, entropy density, information distance) — verified by differential testing. Shuffle-based metrics (emc) differ only in that Rust is reproducible run-to-run.


References

  1. Lempel, A., & Ziv, J. (1976). On the complexity of finite sequences. IEEE Transactions on Information Theory, 22(1), 75–81.
  2. Kontoyiannis, I., Algoet, P. H., Suhov, Y. M., & Wyner, A. J. (1998). Nonparametric entropy estimation for stationary processes and random fields. IEEE Transactions on Information Theory, 44(3), 1319–1327.

Citation

@software{lzcomplexity_2025,
  title={lzcomplexity: an entropy measurement library},
  author={Efren Aragon-Perez},
  url={https://github.com/pleros-ai/lzcomplexity},
  year={2025}
}

License

MIT — see LICENSE.

Metadata

Release files for lzcomplexity 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lzcomplexity 1.0.0
File Size Uploaded
lzcomplexity-1.0.0.tar.gz 33.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for lzcomplexity 1.0.0
File
lzcomplexity-1.0.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
lzcomplexity-1.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
lzcomplexity-1.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
lzcomplexity-1.0.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
lzcomplexity-1.0.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 1.4 MB

Release files / lzcomplexity-1.0.0.tar.gz

Download URL lzcomplexity-1.0.0.tar.gz
Size 33.0 kB
Tags Source
SHA-256 checksum
How to use checksums
5d13262ba80ba18b9bf4330e438c804c272449ce7a124b1e95d07b574119dfc3
BLAKE2b-256 checksum
How to use checksums
db085b310f8cf8d4233248535797412be212f646dddf2836caa46d6c0bc95b43
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release files / lzcomplexity-1.0.0-cp39-abi3-win_amd64.whl

Download URL lzcomplexity-1.0.0-cp39-abi3-win_amd64.whl
Size 203.5 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
6053eab9a13ed9e978d0c6e9bd5ce6b177135ea936288ac03f55bf0092720941
BLAKE2b-256 checksum
How to use checksums
115b94cd5cb570197975d7bd8c37c9590ca5a5351a9871dc0f798fb81ed19de3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release files / lzcomplexity-1.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL lzcomplexity-1.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 301.8 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
7ab117f3d8e576688d5ca59938d9423784a3e77ec02fba144ddc9ad235556223
BLAKE2b-256 checksum
How to use checksums
a9565bdaae96f2e962f16af040cb594c5832c971344ba39521faff6c7373620a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release files / lzcomplexity-1.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL lzcomplexity-1.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 287.9 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
79ab26bebc0f2e8f401590d0eb859ec46435a3cf9c38203406869f81d6b8206f
BLAKE2b-256 checksum
How to use checksums
25809d5c8cf07deb37436873727c86527486eeab4d38a8a24c660894d12bd6d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release files / lzcomplexity-1.0.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL lzcomplexity-1.0.0-cp39-abi3-macosx_11_0_arm64.whl
Size 264.5 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d28a2ff96e1196a46629304437ecd6ce77a0766a2bdd030226977a0f524f31be
BLAKE2b-256 checksum
How to use checksums
20bc27db009a3d04a8f0ff7b8fdbc88b1b2176f7063d20007d95898407b93075
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release files / lzcomplexity-1.0.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL lzcomplexity-1.0.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 276.0 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
94f4680f55107fc38f74fb0cc03d699ef55fb9b32e5fe3bf5326b3a0e3c1fe15
BLAKE2b-256 checksum
How to use checksums
4c7e8b905d793bb743abbc626cb0ce08e5dc170340d009ada00ec7dbdc113f30
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.

Transparency log

Release history Release notifications | RSS feed

2.0.0

6 release files

1.0.2

6 release files

1.0.1

6 release files

This release

1.0.0 This release

6 release files

0.13.0

6 release files

0.12.0

6 release files

0.11.0

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page