Everything on this site is generated by the clocks repository . To run it yourself:
Prerequisites
Python 3.12+
uv — handles the virtual environment and every dependency.
Install
git clone https://github.com/jbwhit/clocks.git
cd clocks
uv sync
Run the demos
Five animated demos plus the density figure. Rough runtimes on a laptop:
uv run demo-1d # → output/demo_1d.gif (~2 min)
uv run demo-2d # → output/demo_2d.gif (~3 min)
uv run demo-multi-mass # → output/demo_multi_mass.gif (~3 min)
uv run demo-multi-mass-2d # → output/demo_multi_mass_2d.gif (~5 min)
uv run demo-model-comparison # → output/demo_model_comparison.gif (~5 min)
uv run demo-density # → output/demo_density.png (~2 min)
Use the library
The same example as the repository README, executed live on this page — if you can read the output below, the install instructions above work:
import numpy as np
from clocks import (
ClockArray,
InferenceConfig,
MassConfig,
NoiseConfig,
PriorConfig,
SimulationConfig,
infer,
simulate,
)
clock_array = ClockArray(
positions= np.array([[- 6.0 ], [- 3.0 ], [0.0 ], [3.0 ], [6.0 ]]),
track_offset= 1.0 ,
)
ground_truth = MassConfig(
positions= np.array([[- 2.0 ], [3.0 ]]),
masses= np.array([0.6 , 0.4 ]),
)
simulation = simulate(
SimulationConfig(
clock_array= clock_array,
ground_truth= ground_truth,
noise= NoiseConfig(observation_std= 0.005 ),
n_observations= 40 ,
seed= 42 ,
)
)
result = infer(
simulation.observations,
InferenceConfig(
clock_array= clock_array,
noise= NoiseConfig(observation_std= 0.005 ),
prior= PriorConfig(position_range= (- 8.0 , 8.0 ), mass_range= (0.1 , 2.0 )),
n_particles= 1500 ,
n_masses= (1 , 2 , 3 ),
seed= 42 ,
),
)
print (result.best_model)
print (result.posterior_by_model)
2
{1: 0.0, 2: 1.0, 3: 0.0}
For fixed-K inference, pass an integer to n_masses; to drive the filter observation-by-observation (e.g. for animation), use build_particle_filter — both are documented in the README .
Next: Reproducibility — seeds, tests, and CI.