Subsystem: upde — phase-ODE integrator family¶
The numerical core: integrates coupled phase dynamics. 74 files, ~18.3k LOC.
Inputs¶
step(phases, omegas, knm, zeta, psi, alpha):
phases—NDArray[float64], shape(N,), radians.omegas—(N,), natural frequencies (rad/s).knm—(N, N), coupling matrix, zero diagonal (validated).alpha—(N, N), Sakaguchi phase-lag matrix.zeta— scalar external-drive strength;psi— drive reference phase.IntegrationConfig(dt, method ∈ {euler, rk4, rk45}, substeps, atol, rtol).
Outputs¶
- New
phases, wrapped to[0, 2π). UPDEState— frozen diagnostic record: per-layerLayerState,cross_layer_alignment,stability_proxy.- Order parameter
(R ∈ [0,1], ψ)viaorder_params.compute_order_parameter.
Processing model¶
Integration methods: forward Euler, classical RK4, and adaptive RK45
(Dormand–Prince 5/4 with PI step control). Geometric variants use an
exponential map on the unit circle; the stochastic layer uses Euler–Maruyama;
the Ott–Antonsen reduction is an O(1) mean-field predictor (Bessel I0, I1).
Engine variants (14–15 implemented)¶
UPDEEngine (standard Kuramoto), StuartLandauEngine (phase + amplitude, Hopf),
InertialKuramotoEngine (2nd-order swing), SwarmalatorEngine,
SimplicialEngine (3-body), TorusEngine (symplectic), DelayedEngine,
SplittingEngine (operator splitting), SheafUPDEEngine, SparseUPDEEngine
(CSR), HypergraphEngine, DopplerEngine, MovingFrameUPDEEngine, and JAX
JaxUPDEEngine / JaxStuartLandauEngine. Papers cited in code (unvouched):
Acebrón 2005, Filatrella–Nielsen–Mallick 2008, and others.
The two JAX engines validate array source types on the host before JAX device
conversion: boolean, complex, and numeric-string aliases fail closed while
finite real numeric-object arrays remain compatible.
Backends¶
Dispatched through upde/_run.py with the fastest-first chain
Rust → WebGPU → Mojo → Julia → Go → Python; the per-language forwarder
modules (_engine_go.py, _engine_mojo.py, …) point to
experimental/accelerators/upde/. Rust paths exist for the standard, sparse,
sheaf, geometric, inertial, and Ott–Antonsen engines.
The sparse Rust boundary accepts only a finite real phase vector with exact
oscillator cardinality and every phase inside [0, 2*pi). Its positive finite
adaptive timestep is replayed into the public last_dt diagnostic only after
the phase result passes validation.
The sheaf boundary validates phase, frequency, restriction-map, and drive-target
source types before conversion. Its Rust result is accepted only as a finite
real flattened N * D torus state, and the positive finite Rust adaptive
timestep is replayed into the public last_dt diagnostic.
Finite-difference and optional JAX adjoint paths share one pre-execution state
contract for phase, frequency, coupling, and phase-lag arrays. Counts and
perturbation/timestep scalars are validated before arithmetic or optional JAX
imports, so backend availability cannot mask malformed public input.
Bayesian UPDE uses one source-type-aware array boundary for direct inputs,
Gaussian distribution parameters, fitted posterior data, and custom
distribution samples. Boolean, complex, and numeric-string aliases are rejected
before float64 conversion, and finite real drive controls are validated before
Monte Carlo rollout.
The forward and variational prediction models apply the same source-type-aware
contract to phase, frequency, predicted-state, observed-state, and precision
vectors. Coercive aliases fail before prediction, free-energy arithmetic, or
online state updates, while finite real numeric object arrays remain compatible.
Public Strang-splitting phase, frequency, coupling, phase-lag, and optional-
backend phase arrays reject boolean, complex/object-complex, and numeric-string
aliases before conversion while preserving finite real numeric-object arrays.
Existing shape, zero-self-coupling, and torus-output checks remain authoritative.
Geometric direct Go, Julia, and Mojo bridges validate torus phase, frequency,
coupling, lag, scalar, count, and backend-output payloads before optional native
runtime loading; numeric-string aliases are rejected at the Python boundary.
Wiring¶
Constructed by api.Orchestrator, runtime/simulation.simulate, and the
server simulation state. Output (UPDEState, order parameter) feeds monitor/
and, through it, supervisor/. coupling/ supplies the knm each step.
Scope boundaries¶
- JAX engines are marked
# pragma: no cover(untested in standard CI). bayesian.pyraisesNotImplementedErrorfor non-NumPy uncertainty backends.- The splitting engine documents symplectic reversibility but has no test asserting it.