Swarmalator Engine — Coupled Spatial-Phase Dynamics¶
The SwarmalatorEngine models agents that are simultaneously swarming
(moving in space) and oscillating (advancing in phase). Phase similarity
modulates spatial attraction, and spatial proximity modulates phase coupling.
This creates a rich zoo of collective states: static sync, static async,
splintered phase waves, and active phase waves.
Swarmalators are a relatively new concept in nonlinear dynamics (O'Keeffe, Hong & Strogatz 2017), bridging swarm dynamics with Kuramoto synchronisation.
1. Mathematical Formalism¶
1.1 The Swarmalator Equations¶
Each agent \(i\) has position \(\mathbf{x}_i \in \mathbb{R}^d\) and phase \(\theta_i \in [0, 2\pi)\). The dynamics are:
Position: $$ \dot{\mathbf{x}}i = \frac{1}{N} \sum \frac{(A + J\cos(\theta_j - \theta_i))\,(\mathbf{x}_j - \mathbf{x}_i)}{|\mathbf{x}_j - \mathbf{x}_i|} - \frac{B\,(\mathbf{x}_j - \mathbf{x}_i)}{|\mathbf{x}_j - \mathbf{x}_i|^2} $$
Phase: $$ \dot{\theta}i = \omega_i + \frac{K}{N} \sum \frac{\sin(\theta_j - \theta_i)}{|\mathbf{x}_j - \mathbf{x}_i|} $$
where:
| Symbol | Description | Default |
|---|---|---|
| \(\mathbf{x}_i\) | Position in \(\mathbb{R}^d\) | — |
| \(\theta_i\) | Phase | \([0, 2\pi)\) |
| \(\omega_i\) | Natural frequency | rad/s |
| \(A\) | Attraction strength | 1.0 |
| \(B\) | Repulsion strength | 1.0 |
| \(J\) | Phase→space coupling | 1.0 |
| \(K\) | Space→phase coupling | 1.0 |
| \(d\) | Spatial dimension | 2 or 3 |
1.2 Coupling Mechanisms¶
The swarmalator model has two reciprocal couplings:
J: Phase modulates space. The attraction between agents depends on their phase difference. When \(J > 0\): phase-similar agents attract more strongly (clustering by phase). When \(J < 0\): phase-different agents attract (spatial mixing by phase).
K: Space modulates phase. Phase coupling is inversely weighted by distance. Nearby agents synchronise more strongly. This is the natural assumption for local interactions (neural, chemical, etc.).
1.3 Collective States¶
O'Keeffe et al. (2017) identified five macroscopic states:
| State | J | K | Spatial pattern | Phase pattern |
|---|---|---|---|---|
| Static sync | \(J > 0\) | \(K > 0\) | Compact cluster | All locked |
| Static async | \(J < 0\) | \(K > 0\) | Ring/shell | Spatially ordered phases |
| Static phase wave | \(J > 0\) | \(K = 0\) | Disc | Phase varies with radius |
| Splintered phase wave | \(J < 0\) | \(K < 0\) | Fragmented | Partial locking |
| Active phase wave | \(J > 0\) | \(K < 0\) | Rotating | Travelling wave |
1.4 Regularisation¶
The \(1/|\mathbf{x}_j - \mathbf{x}_i|\) terms diverge when agents coincide. The implementation adds a small \(\epsilon = 10^{-6}\) to distances:
This prevents division-by-zero without significantly affecting dynamics when agents are separated.
1.5 Order Parameter¶
The order_parameter(phases) method computes the standard Kuramoto \(R\):
For swarmalators, \(R\) alone doesn't capture the full state — the spatial distribution matters too. A "static async" state has \(R \approx 0\) but is highly ordered spatially. Use both \(R\) and mean inter-agent distance for full characterisation.
1.6 Dimensionality¶
The engine supports arbitrary spatial dimension \(d\). Default \(d = 2\) (planar swarming). \(d = 3\) models three-dimensional swarming (e.g., fish schools, bird flocks, drone formations). Higher \(d\) is mathematically valid but has no obvious physical interpretation.
1.7 Energy Functional¶
The swarmalator system has no known energy functional in general. However, for specific parameter regimes (e.g., \(J = 0\)), the spatial and phase dynamics decouple and each has its own Lyapunov function. The coupled system is non-gradient — trajectories can exhibit limit cycles and chaotic attractors.
2. Theoretical Context¶
2.1 Historical Background¶
The swarmalator model was introduced by O'Keeffe, Hong & Strogatz (2017) in Nature Communications. It was inspired by biological systems where spatial aggregation and internal dynamics are coupled:
- Sperm cells: Flagellar beating (oscillation) coupled to chemotaxis (spatial movement)
- Fireflies: Flash timing (phase) coupled to spatial positioning
- Vinegar eels: Body oscillation coupled to collective swimming
- Myxococcus bacteria: Reversal period (phase) coupled to swarming
The model was extended to 3D by O'Keeffe et al. (2022) and to networks with heterogeneous coupling by Lizárraga & de Aguiar (2020).
2.2 Role in SCPN¶
The swarmalator engine has no direct SCPN layer assignment. It is used for:
- Research — studying coupled spatial-phase dynamics in neural populations where neurons have both physical location and oscillatory phase
- Notebook 19 — interactive exploration of swarmalator collective states
- Potential Layer 12 extension — distributed nodes with both geographic position and oscillation state
2.3 Comparison with Other Engines¶
| Engine | Has position? | Has amplitude? | Coupling |
|---|---|---|---|
UPDEEngine |
No | No | All-to-all or graph |
StuartLandauEngine |
No | Yes | All-to-all or graph |
InertialKuramotoEngine |
No | No (has velocity) | All-to-all or graph |
SwarmalatorEngine |
Yes (\(\mathbb{R}^d\)) | No | Distance-weighted |
Swarmalator is the only engine with spatial degrees of freedom.
2.4 Phase Diagram¶
The \((J, K)\) parameter space divides into five regions:
K ↑
| Active Static
| phase wave sync
| (J>0, K>0)
|
--+--+--+--+--+--+--→ J
|
| Splintered Static
| phase wave async
| (J<0, K>0)
|
Phase transitions: As \(J\) crosses 0 at fixed \(K > 0\), the system transitions from static async (ring) to static sync (cluster). As \(K\) crosses 0, active states (with persistent motion) emerge.
The transitions are discontinuous (first-order) in some regions —
hysteresis exists. The run() trajectory reveals whether the system
reached steady state or is still evolving.
2.5 Biological Relevance¶
| System | Position | Phase | J coupling | K coupling |
|---|---|---|---|---|
| Fireflies | Tree position | Flash timing | Light attraction | Visual sync |
| Sperm cells | Swim position | Flagellar beat | Hydrodynamic | Mechanical |
| Myxococcus | Colony position | Reversal period | Signalling | Physical contact |
| Neurons (Layer 2) | Cortical position | Firing phase | Synaptic strength | Spatial proximity |
| Drone swarm | 3D coordinates | Communication phase | Formation control | Local consensus |
2.6 Analytical Results¶
For identical oscillators (\(\omega_i = 0\), \(A = B = 1\)) in 2D: - Static sync: all agents at same position and phase. \(R = 1\), cluster radius \(\to 0\). - Static async: agents on a ring of radius \(\sim \sqrt{B/A}\), phases ordered by angle. \(R = 0\) but spatially ordered. - Phase wave: agents fill a disc, phase varies linearly with radius. \(R \approx 0\).
No closed-form \(K_c\) exists for the general swarmalator model — numerical continuation (not yet implemented in SPO) would be needed.
2.7 Limitations¶
- \(O(N^2)\) per step: All-to-all distance computation. No neighbour lists or spatial indexing (future optimisation).
- Euler integration only (Python fallback). Rust backend available but no RK4/RK45.
- No boundaries: Agents can drift to infinity in some parameter regimes. No periodic boundaries or confinement implemented.
- Fixed coupling parameters: \(A, B, J, K\) are passed per-step, not per-pair. Heterogeneous pairwise coupling not supported.
3. Pipeline Position¶
┌──────────────┐ ┌──────────────────────┐ ┌──────────────┐
│ Initial │────→│ SwarmalatorEngine │────→│ positions │
│ positions │ │ │ │ phases │
│ phases │ │ step(pos, phases, │ └──────┬───────┘
│ omegas │ │ omegas, a,b,j,k) │ │
└──────────────┘ │ │ ┌──────▼───────┐
│ run() → trajectories │ │ order_params │
└──────────────────────┘ │ (R, ψ) │
└──────────────┘
Inputs:
- pos (N, d) — agent positions
- phases (N,) — agent phases
- omegas (N,) — natural frequencies
- a, b, j, k (floats) — coupling parameters (per-step)
Outputs:
- (new_pos, new_phases) — updated state
Direct Mojo swarmalator adapters preserve raw stdout cardinality at the
position-phase boundary: STEP must emit exactly N*d + N scalar lines,
ordered as flattened positions followed by torus phases. Blank, truncated,
overlong, non-numeric, non-finite, or out-of-domain phase lines are rejected
before public arrays are returned.
The public SwarmalatorEngine.step() dispatcher and the Rust wrapper replay
the same output contract before publication: optional backend positions must
have (N, d) shape or exactly N*d flattened values, phases must have length
N, all values must be finite real numbers, phases must stay in [0, 2*pi),
and object-dtype boolean aliases are rejected instead of being widened to
0.0 or 1.0. Public constructor controls, position arrays, phase arrays,
frequency arrays, scalar controls, run-step counts, order_parameter() phase
inputs, direct Go/Julia/Mojo validator inputs, optional backend outputs, and
direct Julia raw returns also reject numeric-string aliases before Python,
NumPy, or accelerator coercion. Loader and runtime unavailability still fall
back to Python; malformed backend physics payloads raise ValueError.
4. Features¶
4.1 Flexible API¶
Coupling parameters \((a, b, j, k)\) are passed to step() and run(),
not the constructor. This allows time-varying coupling (e.g., ramping
\(J\) over a simulation).
4.2 Arbitrary Dimension¶
Constructor parameter dim supports any positive integer. Tested with
\(d = 1, 2, 3\).
4.3 Trajectory Recording¶
run() returns full position and phase trajectories:
(final_pos, final_phases, pos_trajectory, phase_trajectory).
4.4 Rust Acceleration¶
PySwarmalatorStepper provides Rust-accelerated step(). Speedup ~12x.
5. Usage Examples¶
5.1 Static Sync (\(J > 0\), \(K > 0\))¶
import numpy as np
from scpn_phase_orchestrator.upde.swarmalator import SwarmalatorEngine
N = 30
rng = np.random.default_rng(42)
pos = rng.uniform(-2, 2, (N, 2))
phases = rng.uniform(0, 2 * np.pi, N)
omegas = np.zeros(N)
engine = SwarmalatorEngine(N, dim=2, dt=0.01)
fp, fph, pos_traj, ph_traj = engine.run(
pos, phases, omegas, a=1.0, b=1.0, j=1.0, k=1.0, n_steps=2000,
)
R = engine.order_parameter(fph)
print(f"Static sync: R = {R:.4f}") # R ≈ 1.0
5.2 Static Async (\(J < 0\), \(K > 0\))¶
fp, fph, _, _ = engine.run(
pos.copy(), phases.copy(), omegas,
a=1.0, b=1.0, j=-0.5, k=1.0, n_steps=2000,
)
R = engine.order_parameter(fph)
print(f"Static async: R = {R:.4f}") # R ≈ 0 but spatially ordered
5.3 Decoupled (\(J = 0\))¶
fp, fph, _, _ = engine.run(
pos.copy(), phases.copy(), omegas,
a=1.0, b=1.0, j=0.0, k=1.0, n_steps=2000,
)
# Phase doesn't affect space → standard swarm + standard Kuramoto
5.4 3D Swarming¶
pos3d = rng.uniform(-2, 2, (N, 3))
engine3d = SwarmalatorEngine(N, dim=3, dt=0.01)
fp3d, fph3d, _, _ = engine3d.run(
pos3d, phases.copy(), omegas,
a=1.0, b=1.0, j=0.5, k=1.0, n_steps=1000,
)
print(f"3D: R = {engine3d.order_parameter(fph3d):.4f}")
5.5 Parameter Sweep¶
J_values = np.linspace(-1, 1, 20)
R_values = []
for J_val in J_values:
_, fph, _, _ = engine.run(
pos.copy(), phases.copy(), omegas,
a=1.0, b=1.0, j=J_val, k=1.0, n_steps=1000,
)
R_values.append(engine.order_parameter(fph))
# R_values traces the J-dependent synchronisation landscape
5.6 Time-Varying Coupling¶
# Ramp J from 0 to 1 over 2000 steps
pos_curr, ph_curr = pos.copy(), phases.copy()
for step in range(2000):
J_t = step / 2000.0
pos_curr, ph_curr = engine.step(
pos_curr, ph_curr, omegas,
a=1.0, b=1.0, j=J_t, k=1.0,
)
R_final = engine.order_parameter(ph_curr)
print(f"After J ramp: R = {R_final:.4f}")
5.7 Spatial Compactness Metric¶
# Measure how compact the swarm is (mean distance from centroid)
centroid = fp.mean(axis=0)
distances = np.linalg.norm(fp - centroid, axis=1)
compactness = distances.mean()
print(f"Mean distance from centroid: {compactness:.4f}")
# Static sync: very compact. Static async: ring radius.
5.8 Phase-Space Correlation¶
# In static async: phase correlates with angular position
angles = np.arctan2(fp[:, 1] - centroid[1], fp[:, 0] - centroid[0])
angles_mod = angles % (2 * np.pi)
from scpn_phase_orchestrator.upde.order_params import compute_plv
# PLV between spatial angle and oscillator phase
plv = float(np.abs(np.mean(np.exp(1j * (fph - angles_mod)))))
print(f"Phase-space PLV: {plv:.4f}")
# High PLV → strong spatial-phase ordering (static async state)
5.9 Multi-State Exploration¶
# Systematically explore (J, K) phase diagram
states = {}
for J_val in [-1, -0.5, 0, 0.5, 1.0]:
for K_val in [-1, 0, 0.5, 1.0]:
_, fph, _, _ = engine.run(
pos.copy(), phases.copy(), omegas,
a=1.0, b=1.0, j=J_val, k=K_val, n_steps=3000,
)
R = engine.order_parameter(fph)
states[(J_val, K_val)] = R
print(f"J={J_val:+.1f}, K={K_val:+.1f}: R={R:.3f}")
5.10 Visualisation (2D scatter)¶
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))
sc = ax.scatter(fp[:, 0], fp[:, 1], c=fph, cmap="hsv",
vmin=0, vmax=2*np.pi, s=50, edgecolors="k", linewidths=0.5)
plt.colorbar(sc, label="Phase (rad)")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title(f"Swarmalator state (R={engine.order_parameter(fph):.2f})")
ax.set_aspect("equal")
plt.savefig("swarmalator_state.png", dpi=150)
6. Technical Reference¶
6.1 Module API¶
swarmalator ¶
Swarmalator step (position + phase) with a 5-backend fallback chain.
Swarmalators combine spatial attraction / repulsion with phase
oscillator dynamics (O'Keeffe, Hong & Strogatz, Nat. Commun. 8:1504,
2017). Each agent has a position x_i ∈ ℝ^d and a phase θ_i;
they co-evolve through attract/repulse + phase-coupling terms:
ẋ_i = (1/N) Σ_j (x_j − x_i) [(a + j·cos(θ_j − θ_i)) / |x_j − x_i|
− b / |x_j − x_i|²]
θ̇_i = ω_i + (k / N) Σ_j sin(θ_j − θ_i) / |x_j − x_i|
The repulsion b·(x_j − x_i) / |x_j − x_i|² is the canonical
inverse-distance hard core of O'Keeffe-Hong-Strogatz (magnitude
b / |x_j − x_i|), with a = A = 1, b = B = 1, j = J,
k = K recovering the original model. A single regularisation
constant ε = 1e-6 is added to |x_j − x_i|² (and inside the
sqrt for the attraction/phase |x_j − x_i|) so the kernel is
finite at coincident agents; it vanishes in the ε → 0 limit.
Classes¶
SwarmalatorEngine ¶
Swarmalator stepper with 5-backend dispatch.
The engine is stateful in its (n_agents, dim, dt) geometry
but the step contract is stateless: (pos, phases, omegas) →
(new_pos, new_phases).
Initialise the stateless swarmalator stepper geometry.
Source code in src/scpn_phase_orchestrator/upde/swarmalator.py
Methods:¶
step ¶
step(
pos: FloatArray,
phases: FloatArray,
omegas: FloatArray,
a: float = 1.0,
b: float = 1.0,
j: float = 1.0,
k: float = 1.0,
) -> tuple[FloatArray, FloatArray]
Advance coupled swarmalator positions and phases by one step.
Parameters¶
pos
Agent positions with shape (n_agents, dim).
phases
Agent phases in radians, shape (n_agents,).
omegas
Natural angular frequencies, shape (n_agents,).
a
Baseline spatial attraction coefficient.
b
Spatial repulsion coefficient.
j
Phase-dependent attraction modulation.
k
Phase-coupling coefficient.
Returns¶
tuple[FloatArray, FloatArray]
Updated positions with shape (n_agents, dim) and updated
phases wrapped into [0, 2*pi).
Notes¶
The dispatcher selects the first available accelerated backend and falls back to the NumPy reference path with the same state contract.
Source code in src/scpn_phase_orchestrator/upde/swarmalator.py
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | |
run ¶
run(
pos: FloatArray,
phases: FloatArray,
omegas: FloatArray,
a: float = 1.0,
b: float = 1.0,
j: float = 1.0,
k: float = 1.0,
n_steps: int = 100,
) -> tuple[FloatArray, FloatArray, FloatArray, FloatArray]
Integrate swarmalator positions and phases with trajectory capture.
Parameters¶
pos : FloatArray
Swarmalator positions, shape (N, 2).
phases : FloatArray
Oscillator phases in radians, shape (N,).
omegas : FloatArray
Natural frequencies in rad/s, shape (N,).
a : float
Spatial attraction strength.
b : float
Spatial repulsion strength.
j : float
Phase-to-space coupling strength.
k : float
Space-to-phase coupling strength.
n_steps : int
Number of integration steps to run.
Returns¶
tuple[FloatArray, FloatArray, FloatArray, FloatArray] The final positions and phases plus their trajectory traces.
Source code in src/scpn_phase_orchestrator/upde/swarmalator.py
order_parameter ¶
Return the Kuramoto order parameter for swarmalator phases.
Parameters¶
phases : FloatArray
Oscillator phases in radians, shape (N,).
Returns¶
float
The Kuramoto order parameter R.
Source code in src/scpn_phase_orchestrator/upde/swarmalator.py
Functions:¶
6.2 Constructor¶
| Parameter | Type | Default | Description |
|---|---|---|---|
n_agents |
int |
— | Number of swarmalator agents |
dim |
int |
2 |
Spatial dimension |
dt |
float |
0.01 |
Timestep |
6.3 step() Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
pos |
(N, d) |
— | Agent positions |
phases |
(N,) |
— | Agent phases |
omegas |
(N,) |
— | Natural frequencies |
a |
float |
1.0 |
Attraction strength |
b |
float |
1.0 |
Repulsion strength |
j |
float |
1.0 |
Phase→space coupling |
k |
float |
1.0 |
Space→phase coupling |
Returns: (new_pos, new_phases).
6.4 run() Parameters¶
Same as step() plus n_steps: int = 100.
Returns: (final_pos, final_phases, pos_trajectory, phase_trajectory).
6.5 order_parameter(phases) → float¶
Standard Kuramoto R. Does not account for spatial structure.
7. Performance Benchmarks¶
7.1 Rust Speedup¶
| N | dim | Python (ms/step) | Rust (ms/step) | Speedup |
|---|---|---|---|---|
| 30 | 2 | 0.8 | 0.07 | 11.4x |
| 100 | 2 | 8.5 | 0.7 | 12.1x |
| 500 | 2 | 210 | 17 | 12.4x |
| 100 | 3 | 9.2 | 0.8 | 11.5x |
7.2 Complexity¶
| Operation | Time | Space |
|---|---|---|
step() |
\(O(N^2 \cdot d)\) | \(O(N^2)\) distances + \(O(Nd)\) |
run(n) |
\(O(n \cdot N^2 \cdot d)\) | \(O(n \cdot N \cdot d)\) trajectory |
The \(N^2\) pairwise distance computation dominates. For large \(N\), spatial indexing (k-d tree, not yet implemented) could reduce to \(O(N \log N)\) for short-range interactions.
7.3 Memory¶
| N | dim | n_steps | Trajectory memory |
|---|---|---|---|
| 30 | 2 | 2000 | 940 KB |
| 100 | 2 | 2000 | 3.2 MB |
| 500 | 3 | 1000 | 12 MB |
7.4 Convergence Time by State¶
Different collective states converge at different rates:
| State | Typical convergence | Sensitivity |
|---|---|---|
| Static sync | Fast (500–1000 steps) | Low — robust |
| Static async | Medium (1000–3000 steps) | Medium |
| Phase wave | Slow (3000–5000 steps) | High — initial conditions matter |
| Active phase wave | Very slow (5000+ steps) | Very high — transients persist |
| Splintered | Slow (3000+ steps) | High — metastable states |
For reliable state identification, run ≥ 3000 steps and verify that \(R\) has plateaued (check \(|R(t) - R(t-100)| < 0.01\)).
7.5 Timestep Stability¶
Euler integration is conditionally stable. For \(dt = 0.01\): - Stable for \(A, B, J, K \leq 5\) and \(N \leq 500\) - Unstable for \(A, B > 10\) or \(N > 1000\) with \(dt = 0.01\) - Reduce \(dt\) proportionally: \(dt \leq 0.1 / \max(A, B, |J|, |K|)\)
7.6 Recommended Settings¶
| Scenario | N | dim | dt | n_steps |
|---|---|---|---|---|
| Quick exploration | 30 | 2 | 0.01 | 2000 |
| Publication quality | 100 | 2 | 0.005 | 5000 |
| 3D visualisation | 100 | 3 | 0.01 | 1000 |
| Large-scale research | 500 | 2 | 0.01 | 10000 |
7.7 Future Optimisations¶
- Spatial indexing: k-d tree for short-range interactions → \(O(N \log N)\)
- RK4 integration: higher accuracy without reducing \(dt\)
- GPU acceleration: swarmalator N-body is trivially parallelisable
- Periodic boundaries: wrap positions on torus for infinite-lattice-like behaviour
8. Citations¶
-
O'Keeffe K.P., Hong H., Strogatz S.H. (2017). Oscillators that sync and swarm. Nature Communications 8:1504. doi:10.1038/s41467-017-01190-3
-
O'Keeffe K.P., Evers J.H.M., Kolokolnikov T. (2022). Ring states in swarmalator systems. Physical Review E 105(3):034307. doi:10.1103/PhysRevE.105.034307
-
Lizárraga J.U.F., de Aguiar M.A.M. (2020). Synchronization and spatial patterns in forced swarmalators. Chaos 30(5):053112. doi:10.1063/1.5141343
-
Tanaka H. (2007). General chemotactic model of oscillators. Physical Review Letters 99(13):134103. doi:10.1103/PhysRevLett.99.134103
-
Kuramoto Y. (1984). Chemical Oscillations, Waves, and Turbulence. Springer-Verlag. doi:10.1007/978-3-642-69689-3
-
Yoon S., O'Keeffe K.P., Mendes J.F.F., Goltsev A.V. (2022). Sync and swarm: swarmalators on random graphs. New Journal of Physics 24:023037. doi:10.1088/1367-2630/ac4808
-
Sar G.K., Ghosh D., O'Keeffe K. (2023). Swarmalators under competitive time-varying phase interactions. New Journal of Physics 25:032001. doi:10.1088/1367-2630/acc127
Test Coverage¶
tests/test_swarmalator.py— covers step shapes, phase range, J=0 decoupling, run trajectory shapes, 3D, order parameter bounds, behaviour (J>0 clustering, K>0 phase sync), pipeline wiringtests/test_prop_swarmalator_inertial.py— property tests (Hypothesis): output finite, shapes correct, J=0 phase-position independencetests/test_degenerate_edges.py— swarmalator edge cases: N=2, dimensions 1/2/3, J=0 decouplingtests/test_swarmalator_backends.py— direct and public optional-backend input/output validation, fallback, loader, and typed-array contracts
These span direct, property-based, and degenerate-edge tests across the files above.
Source¶
- Python:
src/scpn_phase_orchestrator/upde/swarmalator.py - Rust:
spo-kernel/crates/spo-engine/src/swarmalator.rs - FFI:
spo-kernel/crates/spo-ffi/src/lib.rs(PySwarmalatorStepper)