High-performance simulation engine for the GDS ecosystem.
gds-sim is the standalone discrete-time runtime for GDS models. It has no
dependency on gds-framework: it executes plain Python policy functions and
state update functions over a dictionary state, then stores trajectories in a
compact columnar Results object.
uv add gds-sim
# or: pip install gds-simFor DataFrame output:
uv add "gds-sim[pandas]"from gds_sim import Model, Simulation, StateUpdateBlock
def growth_policy(state, params, **kw):
return {"delta": state["population"] * params["growth_rate"]}
def update_population(state, params, *, signal=None, **kw):
signal = signal or {}
return "population", state["population"] + signal["delta"]
model = Model(
initial_state={"population": 100.0},
state_update_blocks=[
StateUpdateBlock(
policies={"growth": growth_policy},
variables={"population": update_population},
)
],
params={"growth_rate": [0.01, 0.05]},
)
results = Simulation(model=model, timesteps=10, runs=2).run()
rows = results.to_list()
print(rows[-1])Each result row includes metadata columns:
timestep: outer simulation stepsubstep: state update block index within the timesteprun: Monte Carlo run indexsubset: parameter subset index
gds-sim runs a cadCAD-like loop:
- Start from
initial_state - For each parameter subset and run, copy the initial state
- At each timestep, execute each
StateUpdateBlock - Policies produce a signal dictionary
- State update functions return
(state_key, new_value) - Append each substep state snapshot to
Results
Parameter sweeps are built into Model.params as a cartesian product:
model = Model(
initial_state={"x": 0},
state_update_blocks=[StateUpdateBlock(variables={"x": update_x})],
params={"rate": [1, 2], "delay": [0, 5]},
)
# subset 0..3 covers all 2 x 2 combinationsfrom gds_sim import Hooks
def stop_when_large(state, timestep):
return False if state["population"] > 500 else None
sim = Simulation(
model=model,
timesteps=100,
hooks=Hooks(after_step=stop_when_large),
)Hooks are available before a run, after each step, and after a run. Returning
False from after_step stops that run early.
Results stores columns internally and converts on demand:
rows = results.to_list()
df = results.to_dataframe() # requires gds-sim[pandas]Experiment can merge multiple simulations and run independent (subset, run)
pairs across processes:
from gds_sim import Experiment
experiment = Experiment(simulations=[Simulation(model=model)], processes=2)
merged = experiment.run()gds-frameworkdefines structural specifications and verification.gds-analysisconverts selectedGDSSpecstructures intogds_sim.Model.gds_analysis.psuuusesgds-simas its runtime for parameter sweeps, KPI scoring, optimization, and sensitivity analysis.
Apache-2.0 -- Dynamical Systems Group