Skip to content

dynachaos banner

CI PyPI Python License

dynachaos analyses time signals from simulations and experiments: maps and coupled-map lattices, Lyapunov exponents, recurrence quantification, entropy diagnostics, correlation dimension and multifractal spectra. Performance-critical kernels have Rust backends where those have parity tests, with pure-Python fallbacks everywhere else.

Why dynachaos?

dynachaos is a reusable Python/Rust package for inspecting simulated or measured dynamical-systems time signals. It collects maps, coupled-map lattices, recurrence analysis, entropy diagnostics, Grassberger-Procaccia correlation dimension, multifractal spectra, and reproducible analysis pipelines in one codebase. Performance-sensitive kernels use Rust backends where they have parity tests, while pure-Python fallbacks support portability and reference checks.

Features

Maps — logistic, circle, coupled logistic, delayed logistic, coupled delayed, modulated circle, torus doubling (Map I / Map IV)

Coupled Map Lattices — CML with nearest-neighbor diffusive coupling, globally coupled maps (GCM), pattern dynamics, cluster statistics

Diagnostics — Lyapunov exponents (1D + QR spectrum + flow systems), 0-1 test for chaos, SALI/GALI alignment indices, permutation entropy + complexity-entropy planes, sample/approximate/fuzzy/multiscale entropy, recurrence quantification analysis (RQA), Grassberger-Procaccia correlation dimension, multifractal spectra ($D_q$, $f(\alpha)$), AMI + Cao + FNN embedding

Rust backends — correlation integral (Grassberger-Procaccia), fuzzy entropy sum, recurrence line extraction, ordinal distribution counting, AMI histograms, Cao dimension selection, multifractal moments

Visualization — bifurcation diagrams, cobweb plots, return maps, curated Swiss-inspired style themes

Quick Start

From a fresh checkout, run the tested external-signal workflow recipe:

uv run dynachaos analyze examples/recipes/external_signal/external_signal_recipe.jsonc

The command writes examples/recipes/external_signal/outputs/external_signal_recipe/results.json, examples/recipes/external_signal/outputs/external_signal_recipe/metadata.json, and examples/recipes/external_signal/outputs/external_signal_recipe/summary.md. It is intentionally small so it runs in seconds; use the recipe gallery for the long-signal streaming example.

User documentation spine

Config-driven signal analysis workflow

Run scalar/reduced time-series analyses with a JSONC config; all tuning lives in the config, not CLI flags.

Config schema summary:

  • input: either { "path": "signal.npy" } / { "path": "signal.npz", "npz_key": "x" } for a 1D finite scalar/reduced signal, or { "generated": { "name": "logistic", "n": 1000, "seed": 0 } } for self-contained runs.
  • output.dir: stable output directory, resolved relative to the config file.
  • diagnostics: list of { "name": ... } entries. Supported workflow names are permutation_entropy, correlation_dimension, rqa_streaming, and rqa_dense.
  • scale_limits: optional dense-RQA guard. Dense RQA builds an N x N distance matrix costing 8*N^2 bytes; dense_rqa_max_bytes caps that, and allow_dense_rqa_beyond_envelope: true is required to exceed the cap.

Output layout is stable and referenceable by path: results.json (machine-readable diagnostic values), metadata.json (N, shape, wall time in seconds, peak RSS in MB, and per-diagnostic ReliabilityRecord metadata), and summary.md (human-readable report with relative artifact names). Reliability metadata records backend, parameters, data shape, sampling/downsampling notes, warnings, unresolved verdicts, and scale evidence. It helps you decide how much scientific confidence to place in a number; it is not an automatic pass/fail certificate.

For long-signal local RQA, avoid dense recurrence matrices and set an explicit threshold in config:

{
  "input": {"path": "long_signal.npy"},
  "output": {"dir": "results/long_signal_rqa"},
  "diagnostics": [
    {"name": "rqa_streaming", "embedding": {"d": 3, "tau": 2}, "eps": 0.08, "l_min": 2, "v_min": 2}
  ]
}

The local/full-run command uv run dynachaos analyze long_signal_rqa.jsonc requires a local long_signal_rqa.jsonc file and the long_signal.npy input it names. The tested commands live in the quickstart and in examples/README.md.

Rust-Accelerated Backends

Performance-critical algorithms are implemented as Rust kernels. The Rust extension is required by default: import dynachaos fails loudly if it has not been built.

Build the extension in editable mode:

uv run maturin develop --release

Pure-Python fallback policy

The Rust kernels are the intended path for production-sized all-pairs and large-N diagnostics. Pure-Python paths are an explicit opt-in for parity testing and portability, not an automatic silent fallback. Set DYNACHAOS_NO_RUST=1 when you need to exercise them; the test suite checks parity on representative small workloads. Some fallback implementations remain exact and quadratic by design, so large pure-Python runs should be treated as diagnostic or development runs unless a future release explicitly makes large fallback performance a target.

Correlation integral (Grassberger-Procaccia)

The all-pairs kernel evaluates all N(N−1)/2 pairs with Theiler-window exclusion and multi-radius binning in a single pass. The implementation is designed for correctness and low memory use, offering several advantages over common baseline scripts (e.g., notsebastiano/GP_algorithm):

  • Algorithmic Correctness — Supports the Theiler window ($|i-j| > w$) to exclude temporally correlated pairs (Theiler 1986) and uses proper normalization ($C(r) \le 1$).
  • Scaling Region Detection — Employs a stable plateau search on local slopes instead of simple heuristics, making it robust to noise and saturation.
  • Memory Efficiency — Uses O(1) auxiliary memory per pair (streaming) instead of an $O(N^2)$ distance matrix.

The Rust kernel uses:

  • Raw slice indexing — C-contiguous slice access, avoiding ndarray's per-index Index overhead while staying in safe Rust
  • Prefix-sum binning — one write per pair instead of up to 50; converted to cumulative counts with a single O(n_r) pass after the loop
  • Squared-distance comparison — pre-squared thresholds eliminate sqrt() in Euclidean mode (saves 10–20 cycles per pair)
  • Branch-separated loops — Chebyshev and Euclidean paths are fully separated, enabling independent auto-vectorization
  • Rayon parallelism — outer loop distributed across all cores via Rayon; GIL released with py.detach() before the parallel region
  • Native compiler optimization — release builds can use the local CPU target configured under .cargo/.

Benchmark numbers should be regenerated on the release target hardware before being used in public documentation.

Fuzzy entropy sum

Computes Σ exp(−(d/r)ⁿ) over all upper-triangle pairs on mean-centered templates, using the same Rayon parallel fold + reduce pattern.

Algorithm Reference

Algorithm Module Rust kernel Reference
Lyapunov exponent (1D) diagnostics.lyapunov Benettin et al. 1980
Lyapunov spectrum (QR) diagnostics.lyapunov Benettin et al. 1980
Flow Lyapunov spectrum diagnostics.lyapunov Benettin et al. 1980
0-1 test for chaos diagnostics.zero_one_test Gottwald & Melbourne 2004
SALI / GALI diagnostics.sali_gali Skokos et al. 2007
Permutation entropy diagnostics.permutation ordinal dist. Bandt & Pompe 2002
Complexity-entropy plane diagnostics.permutation ordinal dist. Rosso et al. 2007
Sample entropy diagnostics.entropy correlation counts Richman & Moorman 2000
Approximate entropy diagnostics.entropy Pincus 1991
Fuzzy entropy diagnostics.entropy fuzzy sum Chen et al. 2007
Multiscale entropy diagnostics.entropy correlation counts Costa et al. 2002
RQA (DET, LAM, ENTR, …) diagnostics.recurrence line extraction Marwan et al. 2007
Correlation dimension diagnostics.correlation all-pairs kernel Grassberger & Procaccia 1983
Multifractal spectrum ($D_q$, $f(\alpha)$) diagnostics.multifractal multifractal moments Mukherjee et al. 2024
AMI (embedding) diagnostics.embedding histogram Fraser & Swinney 1986
Cao's method diagnostics.embedding dimension selector only Cao 1997
False nearest neighbors diagnostics.embedding Kennel et al. 1992

diagnostics.recurrence keeps recurrence_matrix() for callers that need the binary matrix. For large trajectories where only scalar RQA measures are needed, use rqa_from_trajectory() to avoid materializing the dense recurrence matrix. When starting from an existing recurrence matrix, compute public RQA metrics through rqa(), which validates that the matrix is non-empty, square, and symmetric. The direct line extractors, including the Rust-accelerated helpers, are lower-level square-matrix scanners and do not replace that public RQA validation boundary.

Reproduction gallery

The figures/ tree holds a section-indexed set of reproductions of Kunihiko Kaneko's published work on circle maps, torus doubling, fractalization, coupled map lattices, and globally coupled maps. Each section is regenerated from scratch by the same public entry points users call:

dynachaos list
dynachaos run sec02_circle_map
dynachaos run all

The committed .npz caches double as golden data for the reproducibility and determinism tests, so the gallery is both a worked example and a standing regression check. It is a demanding stress test of the package rather than its boundary: for general use on your own signals, see the quickstart and recipe gallery above.

Eight of the thirty-seven figures are shown below; click any of them for the full-resolution render. Browse the complete gallery for all thirty-seven, in section order, with captions.

Arnold tongues Torus doubling in Map IV
Rotation number over the circle-map parameter plane; the uniform wedges are frequency-locked Arnold tongues. Torus-doubling cascade of Map (IV): a fourfold torus, an eightfold torus, and chaos.
Double devil's staircase Torus fractalization
Double devil's staircase of the modulated circle map, showing locking plateaus in both rotation numbers. A smooth torus in the delayed logistic map develops wrinkles at finer and finer scales as it fractalizes.
Spatiotemporal intermittency Globally coupled map clusters
Spacetime diagrams of spatiotemporal intermittency in three coupled map lattice models. Cluster states in a globally coupled map, showing a partially ordered regime.
Complexity-entropy plane Type-I intermittency
Complexity-entropy plane locations for the logistic and delayed logistic maps. Type-I intermittency: a tangent-bifurcation channel, laminar-length statistics, and a Lorenz reinjection channel.

Benchmarks

The reproducible benchmark for Rust Grassberger-Procaccia parity and dense recurrence/RQA memory limits lives in benchmarks/scale_envelope.py. The local benchmark command is uv run python benchmarks/scale_envelope.py benchmarks/scale_envelope.jsonc; inspect benchmarks/results/scale_envelope.{json,md} after it runs. The checked artifact reports a 42.95x CI-mode Rust Grassberger-Procaccia speedup at N=1000 for the largest common logistic case, and a predicted dense-RQA distance-matrix cost of 8*N^2 bytes, which becomes impractical near N≈23170 under the default cap. The measured Rust acceleration roadmap and local hotspot profiler are documented in docs/rust-acceleration-roadmap.md and benchmarks/rust_hotspot_profile.py.

Development

These commands are for working on dynachaos itself. To use the package, see Quick Start above.

git clone https://github.com/openfluids/dynachaos.git
cd dynachaos
uv sync
uv run --extra viz pytest tests/ -q
uv run --extra viz ruff check src/ tests/ scripts/
uv run --extra viz ruff format --check src/ tests/ scripts/

To exercise the installed Rust extension locally:

uv run maturin develop --release
uv run --extra viz pytest tests/ -q

To verify the pure-Python fallback path:

DYNACHAOS_NO_RUST=1 uv run --extra viz pytest tests/ -q

To rebuild the gallery thumbnails and the static gallery site:

uv run --extra viz python scripts/build_gallery.py

Contributing

Contributions are welcome, and questions and bug reports count. See CONTRIBUTING.md for setup and the checks CI runs, and the openfluids Code of Conduct for how we work together.

Citation

If you use dynachaos in published work, please cite the software:

@software{dynachaos2026,
  author  = {Frantz, Ricardo},
  title   = {dynachaos: Dynamical-systems analysis for time signals with Rust-accelerated kernels},
  year    = {2026},
  version = {0.4.0},
  url     = {https://github.com/openfluids/dynachaos},
  license = {Apache-2.0}
}

License

This project is licensed under Apache-2.0.

Originally developed by Ricardo A S Frantz. See LICENSE and NOTICE for license terms and attribution notices. As of v0.3.0, this project is licensed under Apache-2.0; earlier (unpublished) versions were MIT.

Releases

Packages

Used by

Contributors

Languages