Quadratic system with a slow manifold and a finite Koopman embedding
The quadratic flow x1' = mu x1, x2' = lam (x2 - x1^2), with a slow manifold and a linear embedding.
- Name:
koopman_slow_manifold - Field:
mathematics/dynamical_systems - Formalism: ordinary differential equations
- References: Brunton, Budišić, Kaiser, and Kutz 2022; Tu et al. 2014; Brunton et al. 2016
Factory
@register_model(
field='mathematics/dynamical_systems',
tags=('Koopman operator', 'slow manifold', 'eigenfunctions', 'ode'),
references=('Brunton, Budišić, Kaiser, and Kutz 2022', 'Tu et al. 2014', 'Brunton et al. 2016'),
defaults={'until': 40.0, 'dt': 0.1},
)
def koopman_slow_manifold(
x1: float = 1.0,
x2: float = -1.0,
*,
mu: float = -0.05,
lam: float = -1.0,
) -> System:
"""Return the quadratic flow `x1' = mu x1`, `x2' = lam (x2 - x1^2)`, with a slow manifold and a linear embedding.
For `lam < mu < 0` the fast direction contracts onto the slow manifold `x2 = x1^2`, and the state then slides
along it to the origin. With the observable `x1^2`, the coordinates `(x1, x2, x1^2)` span a Koopman-invariant
subspace in which the flow is linear, with the eigenvalues `mu`, `lam`, and `2 mu`. The Koopman eigenfunctions
`phi_mu = x1` and `phi_lam = x2 - b x1^2` with `b = lam / (lam - 2 mu)` decay exactly as `exp(mu t)` and
`exp(lam t)`, so trajectories follow the parabolas `x2 = b x1^2 + C |x1|^(lam / mu)`.
Args:
x1:
The initial slow coordinate.
x2:
The initial fast coordinate.
mu:
The slow eigenvalue.
lam:
The fast eigenvalue.
Returns:
system:
The model, with the states `flow.x1` and `flow.x2`.
Examples:
>>> from skcomplex.models.mathematics.dynamical_systems import koopman_slow_manifold
>>> koopman_slow_manifold(lam=-2.0).elements[0].lam
-2.0
"""
return System(elements=[SlowManifoldElement('flow', x1=x1, x2=x2, mu=mu, lam=lam)])
Components
class SlowManifoldElement(Element):
"""Quadratic flow `x1' = mu x1`, `x2' = lam (x2 - x1^2)` with the slow manifold `x2 = x1^2`.
Args:
label:
The label of the element.
visual:
How the element is drawn, or `None` for `default_visual_`.
x1:
The initial slow coordinate.
x2:
The initial fast coordinate.
mu:
The slow eigenvalue.
lam:
The fast eigenvalue.
Examples:
>>> from skcomplex.models.mathematics.dynamical_systems import SlowManifoldElement
>>> SlowManifoldElement('flow', lam=-2.0).lam
-2.0
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
x1: Annotated[object, StateSpec()] = 1.0,
x2: Annotated[object, StateSpec()] = 1.0,
mu: Annotated[object, ParameterSpec()] = -0.05,
lam: Annotated[object, ParameterSpec()] = -1.0,
) -> None:
super().__init__(label, visual=visual)
self.x1 = x1
self.x2 = x2
self.mu = mu
self.lam = lam
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the rates of the slow and the fast coordinate.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The laws of the element.
"""
return [RateLaw(s.x1, s.mu * s.x1), RateLaw(s.x2, s.lam * (s.x2 - s.x1**2))]
Equations
flow.x1: diff(x1_flow(t), t) == mu_flow*x1_flow(t)
flow.x2: diff(x2_flow(t), t) == -(x1_flow(t)^2 - x2_flow(t))*lam_flow