2026-07-30 18:52:01 +02:00

40 lines
1.4 KiB
Python

"""Multi-epoch trajectory driver for a single config."""
from __future__ import annotations
from typing import Any
import numpy as np
from . import tsi
from .config import SimConfig
from .epoch import simulate_epoch
from .metrics import metric_row
from .rng import seedseq_for
from .stake import make_stake
def run_trajectory(config: SimConfig) -> list[dict[str, Any]]:
"""Run ``config.epochs`` epochs of TSI, returning one metric row per epoch.
Stake is drawn once (it is fixed; only ``D_est`` evolves). ``D_est`` starts at the
hardcoded genesis value ``genesis_d_factor * D_true`` and is updated each epoch from
the measured density. The RNG is a spawn hierarchy off the config's root SeedSequence:
child 0 draws the stake, child ``e+1`` drives epoch ``e`` — so every draw is a
deterministic, order-independent function of the config identity.
"""
root = seedseq_for(config)
children = root.spawn(config.epochs + 1)
stake = make_stake(config, np.random.default_rng(children[0]))
d_true = float(stake.sum())
d_est = config.genesis_d_factor * d_true
T = config.period_T
rows: list[dict[str, Any]] = []
for epoch in range(config.epochs):
er = simulate_epoch(config, stake, d_est, children[epoch + 1])
d_next = tsi.update_D(d_est, er.m, T, config.f, config.beta, config.fixed_point)
rows.append(metric_row(config, epoch, d_est, d_next, d_true, er))
d_est = d_next
return rows