Rust API Reference
Complete reference for the koopman_dmd Rust crate
Core Types
DmdConfig
Configuration struct for standard DMD. Implements Default.
pub struct DmdConfig {
pub rank: Option<usize>,
pub center: bool,
pub lifting: Option<LiftingConfig>,
}
| Field | Type | Default | Description |
|---|---|---|---|
rank |
Option<usize> |
None |
Truncation rank for the SVD. None selects rank
automatically via a singular-value threshold. |
center |
bool |
false |
Subtract the temporal mean from each row before decomposition. The mean is stored and added back during reconstruction. |
lifting |
Option<LiftingConfig> |
None |
Optional nonlinear lifting to augment the observable space (see Lifting). |
DmdResult
Output struct returned by dmd().
Contains the full spectral decomposition and metadata needed for
reconstruction and prediction.
pub struct DmdResult {
pub eigenvalues: Vec<C64>,
pub modes: Vec<Vec<C64>>,
pub amplitudes: Vec<C64>,
pub a_matrix: Vec<Vec<C64>>,
pub rank: usize,
pub data_dim: (usize, usize),
pub x_last: Vec<f64>,
pub center: bool,
pub x_mean: Option<Vec<f64>>,
pub lifting_info: Option<LiftingInfo>,
}
| Field | Type | Description |
|---|---|---|
eigenvalues |
Vec<C64> |
Complex DMD eigenvalues (discrete-time). |
modes |
Vec<Vec<C64>> |
DMD modes as column vectors. Each inner Vec is one mode. |
amplitudes |
Vec<C64> |
Amplitude coefficients weighting each mode's contribution. |
a_matrix |
Vec<Vec<C64>> |
Reduced linear operator in the POD basis. |
rank |
usize |
Truncation rank used in the decomposition. |
data_dim |
(usize, usize) |
Shape of the original data matrix (rows, columns). |
x_last |
Vec<f64> |
Last column of the data matrix, used as the default initial condition for prediction. |
center |
bool |
Whether mean centering was applied. |
x_mean |
Option<Vec<f64>> |
Row-wise mean vector, present when center = true. |
lifting_info |
Option<LiftingInfo> |
Metadata about applied lifting, present when a lifting config was supplied. |
C64
Custom complex number type used throughout the library. Wraps a 64-bit real and imaginary pair.
pub struct C64 {
pub re: f64,
pub im: f64,
}
| Method | Signature | Description |
|---|---|---|
new |
fn new(re: f64, im: f64) -> C64 |
Construct a complex number from real and imaginary parts. |
norm |
fn norm(&self) -> f64 |
Modulus (absolute value): sqrt(re^2 + im^2). |
arg |
fn arg(&self) -> f64 |
Phase angle in radians: atan2(im, re). |
conj |
fn conj(&self) -> C64 |
Complex conjugate: (re, -im). |
zero |
fn zero() -> C64 |
Returns 0 + 0i. |
DmdError
Error type for all fallible operations. Implements std::error::Error
and Display.
pub enum DmdError {
InvalidInput(String),
NumericalError(String),
ConvergenceError(String),
}
| Variant | Description |
|---|---|
InvalidInput(String) |
The input data or configuration is invalid (e.g., dimension mismatch, empty matrix, rank exceeding matrix dimensions). |
NumericalError(String) |
A numerical computation failed (e.g., singular matrix, NaN produced during SVD). |
ConvergenceError(String) |
An iterative algorithm did not converge within the allowed iterations or tolerance. |
DMD Functions
dmd
Perform Dynamic Mode Decomposition on a snapshot matrix. Returns the full spectral decomposition including eigenvalues, modes, and amplitudes.
pub fn dmd(
data: &Mat<f64>,
config: &DmdConfig,
) -> Result<DmdResult, DmdError>
| Parameter | Type | Description |
|---|---|---|
data |
&Mat<f64> |
Snapshot matrix with state variables as rows and time steps as columns. |
config |
&DmdConfig |
Decomposition configuration (rank, centering, lifting). |
Returns: Result<DmdResult, DmdError>
-- the full decomposition on success, or an error if the input is invalid
or the computation fails.
use koopman_dmd::{dmd, DmdConfig};
let config = DmdConfig { rank: Some(4), ..DmdConfig::default() };
let result = dmd(&data, &config)?;
println!("Eigenvalues: {:?}", result.eigenvalues);
predict_modes
Predict future states using the spectral formula. Each time step is computed independently from eigenvalues, modes, and amplitudes, so errors do not accumulate over long horizons.
pub fn predict_modes(
result: &DmdResult,
n_ahead: usize,
x0: Option<&[f64]>,
) -> Result<Mat<f64>, DmdError>
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
n_ahead |
usize |
Number of future time steps to predict. |
x0 |
Option<&[f64]> |
Initial condition. If None, uses result.x_last. |
Returns: Result<Mat<f64>, DmdError>
-- predicted state matrix with shape (n_vars, n_ahead).
predict_matrix
Predict future states by recursive application of the linear operator.
Each step multiplies the previous state by the reconstructed matrix
A.
pub fn predict_matrix(
result: &DmdResult,
n_ahead: usize,
x0: Option<&[f64]>,
) -> Result<Mat<f64>, DmdError>
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
n_ahead |
usize |
Number of future time steps to predict. |
x0 |
Option<&[f64]> |
Initial condition. If None, uses result.x_last. |
Returns: Result<Mat<f64>, DmdError>
-- predicted state matrix with shape (n_vars, n_ahead).
dmd_reconstruct
Reconstruct the original data from the DMD decomposition. If centering was applied, the stored mean is added back automatically.
pub fn dmd_reconstruct(
result: &DmdResult,
n_time: usize,
x0: Option<&[f64]>,
) -> Result<Mat<f64>, DmdError>
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
n_time |
usize |
Number of time steps to reconstruct. |
x0 |
Option<&[f64]> |
Initial condition. If None, uses the first snapshot
from the original data. |
Returns: Result<Mat<f64>, DmdError>
-- reconstructed data matrix.
use koopman_dmd::{dmd, dmd_reconstruct, predict_modes, DmdConfig};
let result = dmd(&data, &DmdConfig::default())?;
// Reconstruct the training window
let fitted = dmd_reconstruct(&result, 100, None)?;
// Predict 50 steps ahead from a custom initial condition
let ic = vec![1.0, 0.0, 0.0];
let forecast = predict_modes(&result, 50, Some(&ic))?;
Analysis Functions
dmd_spectrum
Extract frequency, growth rate, and energy information for each DMD mode.
Converts discrete-time eigenvalues to continuous-time frequencies using
the sampling interval dt.
pub fn dmd_spectrum(
result: &DmdResult,
dt: f64,
) -> Vec<ModeInfo>
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
dt |
f64 |
Sampling interval (time between consecutive snapshots). |
Returns: Vec<ModeInfo>
-- one entry per mode containing frequency, growth rate, amplitude, and energy.
dmd_stability
Classify eigenvalues as stable, unstable, or neutral based on their modulus relative to the unit circle.
pub fn dmd_stability(
result: &DmdResult,
tol: f64,
) -> StabilityResult
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
tol |
f64 |
Tolerance for classifying eigenvalues as neutral. Eigenvalues
with |lambda| - 1 < tol are considered neutral. |
Returns: StabilityResult
-- lists of stable, unstable, and neutral eigenvalue indices, plus an
overall stability classification.
dmd_error
Compute reconstruction error metrics by comparing the DMD reconstruction against the original data matrix.
pub fn dmd_error(
result: &DmdResult,
data: &Mat<f64>,
) -> Result<ErrorMetrics, DmdError>
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
data |
&Mat<f64> |
Original snapshot matrix to compare against. |
Returns: Result<ErrorMetrics, DmdError>
-- RMSE and relative Frobenius-norm error.
dmd_residual
Compute the residual of the DMD decomposition, measuring how well the linear operator reproduces the one-step dynamics.
pub fn dmd_residual(
result: &DmdResult,
) -> ResidualResult
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
Returns: ResidualResult
-- per-mode and aggregate residual norms.
dmd_dominant_modes
Select the most significant modes according to a ranking criterion (amplitude, energy, or growth rate).
pub fn dmd_dominant_modes(
result: &DmdResult,
criterion: DominantCriterion,
n: usize,
) -> Vec<ModeInfo>
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
criterion |
DominantCriterion |
Ranking criterion: Amplitude, Energy, or GrowthRate. |
n |
usize |
Number of top modes to return. |
Returns: Vec<ModeInfo>
-- the top n modes sorted by the chosen criterion in descending order.
dmd_pseudospectrum
Compute the pseudospectrum of the DMD operator on a grid in the complex plane. Useful for assessing sensitivity of eigenvalues to perturbations.
pub fn dmd_pseudospectrum(
result: &DmdResult,
re_range: (f64, f64),
im_range: (f64, f64),
resolution: usize,
) -> PseudospectrumResult
| Parameter | Type | Description |
|---|---|---|
result |
&DmdResult |
A previously computed DMD decomposition. |
re_range |
(f64, f64) |
Range of the real axis (min, max). |
im_range |
(f64, f64) |
Range of the imaginary axis (min, max). |
resolution |
usize |
Number of grid points along each axis. |
Returns: PseudospectrumResult
-- grid coordinates and resolvent norm values for contour plotting.
dmd_convergence
Evaluate how the DMD decomposition changes across a sequence of truncation ranks. Useful for selecting an appropriate rank.
pub fn dmd_convergence(
data: &Mat<f64>,
ranks: &[usize],
) -> Vec<ConvergenceResult>
| Parameter | Type | Description |
|---|---|---|
data |
&Mat<f64> |
Snapshot matrix. |
ranks |
&[usize] |
List of truncation ranks to evaluate. |
Returns: Vec<ConvergenceResult>
-- one entry per rank with eigenvalues, reconstruction error, and mode stability metrics.
use koopman_dmd::{dmd, dmd_spectrum, dmd_stability, dmd_convergence, DmdConfig};
let result = dmd(&data, &DmdConfig::default())?;
// Spectral analysis with dt = 0.01
let spectrum = dmd_spectrum(&result, 0.01);
for mode in &spectrum {
println!("freq={:.4} growth={:.4} energy={:.4}",
mode.frequency, mode.growth_rate, mode.energy);
}
// Stability classification
let stab = dmd_stability(&result, 1e-6);
println!("Stable modes: {:?}", stab.stable);
println!("Unstable modes: {:?}", stab.unstable);
// Convergence study
let conv = dmd_convergence(&data, &[2, 4, 8, 16]);
for c in &conv {
println!("rank={} error={:.6}", c.rank, c.error);
}
Lifting
Nonlinear lifting functions augment the observable space for Extended DMD. The lifted data is passed through standard DMD and the results are projected back to the original state space.
LiftingConfig
pub enum LiftingConfig {
Polynomial { degree: usize },
Trigonometric { harmonics: usize },
Delay { delays: usize },
}
| Variant | Fields | Description |
|---|---|---|
Polynomial |
degree: usize |
Augment with polynomial terms up to the given degree (e.g., degree 2
adds x^2, xy, y^2 for 2-D state). |
Trigonometric |
harmonics: usize |
Augment with sine and cosine terms at the specified number of harmonic frequencies. |
Delay |
delays: usize |
Augment via time-delay embedding, appending the specified number of lagged copies of the state. |
lift_data
Apply a lifting transformation to a snapshot matrix and return the augmented matrix together with metadata for inverse projection.
pub fn lift_data(
data: &Mat<f64>,
config: &LiftingConfig,
) -> (Mat<f64>, LiftingInfo)
| Parameter | Type | Description |
|---|---|---|
data |
&Mat<f64> |
Original snapshot matrix. |
config |
&LiftingConfig |
Lifting configuration specifying the augmentation strategy. |
Returns: a tuple of the lifted data matrix and a
LiftingInfo struct recording the original
dimensions and lifting parameters.
use koopman_dmd::{dmd, lift_data, DmdConfig, LiftingConfig};
// Polynomial lifting with degree 3
let config = DmdConfig {
lifting: Some(LiftingConfig::Polynomial { degree: 3 }),
..DmdConfig::default()
};
let result = dmd(&data, &config)?;
// Or lift manually
let (lifted, info) = lift_data(&data, &LiftingConfig::Trigonometric { harmonics: 5 });
Hankel-DMD
Hankel-DMD uses time-delay embedding via Hankel matrices to capture higher-order dynamics from scalar or low-dimensional measurements. The data is restructured into a block-Hankel matrix before the standard DMD algorithm is applied.
HankelConfig
pub struct HankelConfig {
pub delays: Option<usize>,
pub rank: Option<usize>,
pub dt: f64,
}
| Field | Type | Default | Description |
|---|---|---|---|
delays |
Option<usize> |
None |
Number of delay embeddings. None selects automatically. |
rank |
Option<usize> |
None |
Truncation rank for the SVD on the Hankel matrix. |
dt |
f64 |
1.0 |
Sampling interval for continuous-time frequency conversion. |
hankel_dmd
Perform Hankel-DMD on a snapshot matrix. Constructs the delay-embedded Hankel matrix internally and returns a specialized result type.
pub fn hankel_dmd(
data: &Mat<f64>,
config: &HankelConfig,
) -> Result<HankelDmdResult, DmdError>
| Parameter | Type | Description |
|---|---|---|
data |
&Mat<f64> |
Snapshot matrix (may be scalar time series as a 1-by-n matrix). |
config |
&HankelConfig |
Hankel-DMD configuration. |
Returns: Result<HankelDmdResult, DmdError>
-- decomposition result including the Hankel structure metadata.
hankel_reconstruct
Reconstruct the original (non-embedded) time series from a Hankel-DMD result.
pub fn hankel_reconstruct(
result: &HankelDmdResult,
n_time: usize,
) -> Result<Mat<f64>, DmdError>
hankel_predict
Predict future time steps from a Hankel-DMD result, projecting back to the original observation space.
pub fn hankel_predict(
result: &HankelDmdResult,
n_ahead: usize,
) -> Result<Mat<f64>, DmdError>
use koopman_dmd::{hankel_dmd, hankel_reconstruct, hankel_predict, HankelConfig};
let config = HankelConfig {
delays: Some(10),
rank: Some(6),
dt: 0.01,
};
let result = hankel_dmd(&signal, &config)?;
let fitted = hankel_reconstruct(&result, 200)?;
let future = hankel_predict(&result, 50)?;
GLA (Generalized Laplace Analysis)
Generalized Laplace Analysis extracts Koopman eigenvalues and eigenfunctions from trajectory data using spectral methods. Unlike standard DMD, GLA can resolve eigenvalues that are not well-separated and handles continuous spectra.
GlaConfig
pub struct GlaConfig {
pub eigenvalues: Option<Vec<C64>>,
pub n_eigenvalues: usize,
pub tol: f64,
pub max_iter: Option<usize>,
}
| Field | Type | Default | Description |
|---|---|---|---|
eigenvalues |
Option<Vec<C64>> |
None |
Known or initial-guess eigenvalues. If None, eigenvalues
are estimated from the data. |
n_eigenvalues |
usize |
10 |
Number of eigenvalues to extract (ignored when eigenvalues
is provided). |
tol |
f64 |
1e-10 |
Convergence tolerance for the iterative solver. |
max_iter |
Option<usize> |
None |
Maximum number of iterations. None uses a library default. |
gla
Run Generalized Laplace Analysis on trajectory data.
pub fn gla(
data: &Mat<f64>,
config: &GlaConfig,
) -> Result<GlaResult, DmdError>
| Parameter | Type | Description |
|---|---|---|
data |
&Mat<f64> |
Trajectory data matrix. |
config |
&GlaConfig |
GLA configuration. |
Returns: Result<GlaResult, DmdError>
-- extracted eigenvalues, eigenfunctions, and convergence information.
gla_predict
Predict future states using the GLA decomposition.
pub fn gla_predict(
result: &GlaResult,
n_ahead: usize,
) -> Result<Mat<f64>, DmdError>
gla_reconstruct
Reconstruct the training trajectory from the GLA decomposition.
pub fn gla_reconstruct(
result: &GlaResult,
n_time: usize,
) -> Result<Mat<f64>, DmdError>
use koopman_dmd::{gla, gla_predict, gla_reconstruct, GlaConfig, C64};
// Extract 8 eigenvalues with default tolerance
let config = GlaConfig {
eigenvalues: None,
n_eigenvalues: 8,
tol: 1e-10,
max_iter: Some(1000),
};
let result = gla(&trajectory, &config)?;
println!("Eigenvalues: {:?}", result.eigenvalues);
let fitted = gla_reconstruct(&result, 500)?;
let future = gla_predict(&result, 100)?;
Harmonic Analysis
Harmonic time averages isolate Koopman modes at specific frequencies.
Given a dynamical map and an observable, the harmonic time average at
frequency omega converges to the projection of the observable
onto the Koopman eigenfunction at that frequency.
Observable
pub enum Observable {
Identity,
SinPi,
CosPi,
SinPiXY,
Quadratic,
}
| Variant | Description |
|---|---|
Identity |
The identity observable g(x) = x. |
SinPi |
g(x) = sin(pi * x) applied to the first component. |
CosPi |
g(x) = cos(pi * x) applied to the first component. |
SinPiXY |
g(x, y) = sin(pi * x * y) for 2-D state vectors. |
Quadratic |
g(x) = x^2 applied component-wise. |
harmonic_time_average
Compute the harmonic time average of an observable along a trajectory generated by a dynamical map at a specified frequency.
pub fn harmonic_time_average(
ic: &[f64],
map: &dyn MapFn,
obs: &Observable,
omega: f64,
n_iter: usize,
) -> Result<HtaResult, DmdError>
| Parameter | Type | Description |
|---|---|---|
ic |
&[f64] |
Initial condition for the trajectory. |
map |
&dyn MapFn |
Dynamical map to iterate (see Maps). |
obs |
&Observable |
Observable function to evaluate along the trajectory. |
omega |
f64 |
Target frequency for the harmonic average. |
n_iter |
usize |
Number of map iterations to compute the average over. |
Returns: Result<HtaResult, DmdError>
-- the converged harmonic time average value and convergence diagnostics.
classify_phase_space
Classify regions of phase space based on harmonic time average behavior. Identifies periodic islands, chaotic seas, and cantori.
pub fn classify_phase_space(
map: &dyn MapFn,
obs: &Observable,
omega: f64,
n_iter: usize,
grid: &[(f64, f64)],
) -> Vec<PhaseClassification>
hta_convergence
Monitor convergence of the harmonic time average as a function of iteration count. Useful for determining sufficient averaging length.
pub fn hta_convergence(
ic: &[f64],
map: &dyn MapFn,
obs: &Observable,
omega: f64,
checkpoints: &[usize],
) -> Vec<HtaResult>
hta_from_values
Compute the harmonic time average from pre-computed observable values rather than generating a trajectory internally.
pub fn hta_from_values(
values: &[f64],
omega: f64,
) -> HtaResult
use koopman_dmd::{
harmonic_time_average, hta_convergence,
Observable, StandardMap,
};
let map = StandardMap { epsilon: 0.5 };
let ic = [0.1, 0.2];
// Single harmonic time average
let hta = harmonic_time_average(&ic, &map, &Observable::CosPi, 0.0, 10000)?;
println!("HTA value: {:?}", hta.value);
// Convergence study
let checkpoints = vec![100, 500, 1000, 5000, 10000];
let conv = hta_convergence(&ic, &map, &Observable::CosPi, 0.0, &checkpoints);
Maps
Built-in dynamical maps implement the MapFn
trait. These are used for testing, benchmarking, and as inputs to harmonic
analysis and mesochronic computations.
MapFn (Trait)
pub trait MapFn {
/// Advance the state by one step.
fn step(&self, state: &[f64]) -> Vec<f64>;
/// Dimension of the state space.
fn dim(&self) -> usize;
}
Built-in Maps
| Struct | Fields | Dimension | Description |
|---|---|---|---|
StandardMap |
epsilon: f64 |
2 | Chirikov standard map on the torus. Perturbation strength
controlled by epsilon. |
FroeschleMap |
epsilon: f64 |
4 | Four-dimensional symplectic map generalizing the standard map. |
ExtendedStandardMap |
epsilon: f64 |
4 | Coupled pair of standard maps with additional coupling parameter. |
HenonMap |
a: f64, b: f64 |
2 | Henon map with classical parameters a = 1.4,
b = 0.3 by default. |
LogisticMap |
r: f64 |
1 | Logistic map x -> r * x * (1 - x). |
generate_trajectory
Generate a trajectory by iterating a map from an initial condition.
pub fn generate_trajectory(
ic: &[f64],
map: &dyn MapFn,
n: usize,
) -> Mat<f64>
| Parameter | Type | Description |
|---|---|---|
ic |
&[f64] |
Initial condition (length must match map.dim()). |
map |
&dyn MapFn |
Dynamical map to iterate. |
n |
usize |
Number of steps (output has n + 1 columns including the
initial condition). |
Returns: Mat<f64>
-- trajectory matrix with shape (dim, n + 1).
use koopman_dmd::{generate_trajectory, StandardMap, HenonMap};
// Standard map trajectory
let smap = StandardMap { epsilon: 0.97 };
let traj = generate_trajectory(&[0.1, 0.2], &smap, 10000);
// Henon map trajectory
let henon = HenonMap { a: 1.4, b: 0.3 };
let traj = generate_trajectory(&[0.0, 0.0], &henon, 5000);
Mesochronic
Mesochronic analysis computes finite-time Koopman operator properties over a grid of initial conditions, producing phase-space portraits that reveal the structure of the dynamics.
mesochronic_compute
Compute a mesochronic harmonic portrait over a 2-D grid of initial conditions. For each grid point, a trajectory is generated and the harmonic time average is evaluated.
pub fn mesochronic_compute(
map: &dyn MapFn,
x_range: (f64, f64),
y_range: (f64, f64),
resolution: usize,
observable: &Observable,
omega: f64,
n_iter: usize,
) -> Result<MhpResult, DmdError>
| Parameter | Type | Description |
|---|---|---|
map |
&dyn MapFn |
Dynamical map to iterate at each grid point. |
x_range |
(f64, f64) |
Range of the first state variable (min, max). |
y_range |
(f64, f64) |
Range of the second state variable (min, max). |
resolution |
usize |
Number of grid points along each axis. |
observable |
&Observable |
Observable function to evaluate. |
omega |
f64 |
Frequency for the harmonic time average. |
n_iter |
usize |
Number of map iterations per grid point. |
Returns: Result<MhpResult, DmdError>
-- grid coordinates and harmonic time average values at each point.
mesochronic_scatter
Compute mesochronic values at a scattered set of initial conditions (not on a regular grid). Useful for adaptive refinement or sampling along specific structures.
pub fn mesochronic_scatter(
map: &dyn MapFn,
points: &[(f64, f64)],
observable: &Observable,
omega: f64,
n_iter: usize,
) -> Result<Vec<HtaResult>, DmdError>
mesochronic_section
Compute mesochronic values along a 1-D cross-section of phase space. Produces a line profile through the mesochronic portrait.
pub fn mesochronic_section(
map: &dyn MapFn,
start: (f64, f64),
end: (f64, f64),
n_points: usize,
observable: &Observable,
omega: f64,
n_iter: usize,
) -> Result<Vec<HtaResult>, DmdError>
use koopman_dmd::{
mesochronic_compute, mesochronic_section,
StandardMap, Observable,
};
let map = StandardMap { epsilon: 0.97 };
// Full 2-D portrait
let portrait = mesochronic_compute(
&map,
(0.0, 1.0), // x range
(0.0, 1.0), // y range
256, // resolution
&Observable::CosPi,
0.0, // omega
5000, // iterations
)?;
// 1-D cross-section
let section = mesochronic_section(
&map,
(0.0, 0.5), // start point
(1.0, 0.5), // end point
500, // number of sample points
&Observable::CosPi,
0.0,
5000,
)?;