koopman-dmd 0.2.0

Dynamic Mode Decomposition with Koopman operator theory
Documentation

koopman-dmd

Crates.io Documentation License: MIT

Dynamic Mode Decomposition (DMD) with Koopman operator theory extensions, in pure Rust.

DMD extracts spatiotemporal coherent structures from time-series data, giving a linear operator that approximates the dynamics of a possibly nonlinear system. This crate implements the core method plus the Koopman-theoretic extensions used for analyzing nonlinear and area-preserving systems.

Linear algebra is provided by faer; no external BLAS/LAPACK installation is required.

Features

  • Core DMD — standard DMD with truncated SVD and optional mean centering
  • Extended DMD — polynomial, trigonometric, and delay-coordinate lifting for nonlinear systems
  • Hankel-DMD — time-delay embedding via Krylov subspace, for scalar or low-dimensional signals
  • GLA — Generalized Laplace Analysis for direct Koopman eigenfunction computation
  • Harmonic time averages — phase space analysis and orbit classification via HTA
  • Mesochronic plots — grid-based HTA visualization of mixed dynamics, parallelized with rayon
  • Built-in maps — Chirikov standard, Froeschlé, extended standard, Hénon, and logistic
  • Prediction — mode-based and matrix-based forecasting with lifting-aware back-projection
  • Analysis — stability, spectrum, residuals, pseudospectrum, error metrics, dominant modes

Installation

[dependencies]
koopman-dmd = "0.1"

Requires Rust 1.85 or later.

Quick start

use koopman_dmd::{dmd, DmdConfig, dmd_spectrum, predict_modes};

// A 2-variable oscillating signal, as a 2 x 100 matrix
let n = 100;
let mut data = faer::Mat::<f64>::zeros(2, n);
for j in 0..n {
    let t = j as f64 * 0.1;
    data[(0, j)] = t.sin();
    data[(1, j)] = t.cos();
}

let result = dmd(&data, &DmdConfig::default()).unwrap();

// Inspect the spectrum
for m in &dmd_spectrum(&result, 0.1) {
    println!("freq={:.3} Hz, mag={:.3}, stability={:?}",
        m.frequency, m.magnitude, m.stability);
}

// Forecast 10 steps ahead
let pred = predict_modes(&result, 10, None).unwrap();

Extended DMD with lifting

Lifting maps observables into a higher-dimensional space where nonlinear dynamics become approximately linear:

use koopman_dmd::{dmd, DmdConfig, LiftingConfig};

let n = 100;
let mut data = faer::Mat::<f64>::zeros(2, n);
for j in 0..n {
    let t = j as f64 * 0.05;
    data[(0, j)] = t.sin();
    data[(1, j)] = t.sin() * t.sin();
}

let config = DmdConfig {
    lifting: Some(LiftingConfig::Polynomial { degree: 2 }),
    ..Default::default()
};
let result = dmd(&data, &config).unwrap();

Hankel-DMD

Time-delay embedding, for scalar signals or systems with limited measurements:

The signal is a 1 x n matrix (one row per measured variable):

use koopman_dmd::{hankel_dmd, HankelConfig};

let n = 200;
let mut signal = faer::Mat::<f64>::zeros(1, n);
for j in 0..n {
    signal[(0, j)] = (j as f64 * 0.1).sin();
}

let config = HankelConfig { delays: Some(20), rank: Some(4), dt: 0.01 };
let result = hankel_dmd(&signal, &config).unwrap();

Generalized Laplace Analysis

Direct computation of Koopman eigenfunctions via weighted time averages:

use koopman_dmd::{gla, GlaConfig};

let n = 200;
let mut data = faer::Mat::<f64>::zeros(2, n);
for j in 0..n {
    let t = j as f64 * 0.05;
    data[(0, j)] = t.sin();
    data[(1, j)] = t.cos();
}

let config = GlaConfig {
    eigenvalues: None,   // auto-detect
    n_eigenvalues: 4,
    tol: 1e-6,
    max_iter: None,
};
let result = gla(&data, &config).unwrap();

Harmonic time averages and mesochronic plots

Phase space analysis of area-preserving maps:

use koopman_dmd::{harmonic_time_average, mesochronic_compute, Observable, StandardMap};

let map = StandardMap { epsilon: 0.12 };

// HTA at a single initial condition
let hta = harmonic_time_average(&[0.5, 0.3], &map, &Observable::SinPi, 0.5, 1000).unwrap();

// Mesochronic plot over a grid (parallelized with rayon)
let mhp = mesochronic_compute(
    &map, (0.0, 1.0), (0.0, 1.0), 32, &Observable::SinPi, 0.5, 1000,
).unwrap();

Other languages

Python and R bindings live in the same repository:

Benchmarks

cargo bench

Representative results (Apple Silicon):

Operation Size Time
DMD 5 × 100 ~80 µs
DMD 50 × 1000 ~8.5 ms
Predict (modes) 2 vars, 100 steps ~215 µs
Predict (matrix) 2 vars, 100 steps ~36 µs
Hankel-DMD 1 × 200, 20 delays ~130 µs
GLA 2 × 200 ~344 µs

References

  • Schmid, P.J. (2010). Dynamic mode decomposition of numerical and experimental data. Journal of Fluid Mechanics, 656, 5–28. doi:10.1017/S0022112010001217
  • Kutz, J.N., Brunton, S.L., Brunton, B.W., & Proctor, J.L. (2016). Dynamic Mode Decomposition: Data-Driven Modeling of Complex Systems. SIAM. doi:10.1137/1.9781611974508
  • Mezić, I. (2020). Spectrum of the Koopman operator, spectral expansions in functional spaces, and state-space geometry. arXiv:2009.05883
  • Levnajić, Z. & Mezić, I. (2014). Ergodic theory and visualization. arXiv:0808.2182v2

License

MIT — see LICENSE.