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 0.13.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 0.13.0
File Size Uploaded
lzcomplexity-0.13.0.tar.gz 32.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for lzcomplexity 0.13.0
File
lzcomplexity-0.13.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
lzcomplexity-0.13.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
lzcomplexity-0.13.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
lzcomplexity-0.13.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
lzcomplexity-0.13.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-0.13.0.tar.gz

Download URL lzcomplexity-0.13.0.tar.gz
Size 32.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3dc85336e9f439403ab49d58c24955348e0899732c9179e7f700a95fed242996
BLAKE2b-256 checksum
How to use checksums
9f15761b3f8f951e7fab5708a2c9cb6041754d1df8bcb604472bf847a4f89f7d
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-0.13.0-cp39-abi3-win_amd64.whl

Download URL lzcomplexity-0.13.0-cp39-abi3-win_amd64.whl
Size 203.4 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
b34b7e9d63303d65a29ac76f8fcc45907374f6321d7e14086e8eb8274fcca69b
BLAKE2b-256 checksum
How to use checksums
65746c4e523a4565b3a3f09e5cbd3e90c0aa4548355c4a819bfa3e440989a72b
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-0.13.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL lzcomplexity-0.13.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 301.7 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
10c3a58201b39989689546c46c7c6f49109d299b128eb89f0f6decebb6c81dde
BLAKE2b-256 checksum
How to use checksums
65fe2b6ba9926d2c100aaed67c2ba8b607ef028774a39734a1a19a542ec131ba
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-0.13.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL lzcomplexity-0.13.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
92ec9cb84e62dc3ae437c1fe0213c564d565b2af18278983ff6deafbf6ae69f5
BLAKE2b-256 checksum
How to use checksums
7d88d7d9186d40a8f02ad1485bd8b9adac08379f0642b17eed427e7d41787bba
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-0.13.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL lzcomplexity-0.13.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
f105dd68641e625e72325561a9eb7120792c1a3df1dc8f3566d7bea40223a81f
BLAKE2b-256 checksum
How to use checksums
a3fb5d794761ab4b9796641e652fdb235dc997d8e3ccb5c26d623a109d7dcf3c
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-0.13.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL lzcomplexity-0.13.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
9e6c8cfaced209c4c6bc94e91af11002b7919da18e299465587dacc38031c49c
BLAKE2b-256 checksum
How to use checksums
1189d4ab97e97f6bf73699da62dde69adb4813da66073bfe6919fe6be6e865a0
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

1.0.0

6 release files

This release

0.13.0 This release

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