pytyche.experiment.simulate

Sim-mode generator adapter — pytyche DGP templates as a Generator.

simulated_experiment_generator() wraps a registered pytyche.generators scenario template as a callable conforming to the Generator contract: the loop calls generator(round_idx, plan) and receives (observed, truth) with non-None truth. Visitors are allocated to the plan’s cells by weight and each visitor’s treatment is drawn from the cell’s policy.assignTreePolicy routing happens at data-generation time, driving the template’s assign_and_observe through its external treatment_assignment hook (never the fixed treatment_probabilities path).

Functions

simulated_experiment_generator(*, template, ...)

Wrap a registered DGP template as a sim-mode Generator callable.

pytyche.experiment.simulate.simulated_experiment_generator(*, template, metric, effect_scale, K, seed=0, treatment_names=None, **template_kwargs)[source]

Wrap a registered DGP template as a sim-mode Generator callable.

The returned callable conforms to the single data-source contract (Generator): invoked as generator(round_idx, plan), it synthesizes one round of observed data from the plan’s cell structure and returns (ObservedExperimentData, CalibrationTruth) — truth is always non-None (sim mode). Generation is deterministic per (seed, round_idx): replaying a round with the same plan reproduces it exactly, while distinct rounds draw fresh visitors.

Variant naming defaults to the generator core’s: index 0 is "control" and indices 1..K-1 are "treatment_1" .. "treatment_{K-1}". treatment_names= renames the variants for the experiment’s narrative (position 0 is the baseline; positions follow the template’s arm order) — presentation-only, the positional truth arrays are untouched. A pt.sequential_experiment(...) driven by this adapter must pass the effective names as its treatments= universe, baseline first.

Each returned visitors frame carries the reserved recording columns:

  • cell — the id of the plan cell that allocated the visitor (recorded at generation time; not derivable from the treatment received).

  • propensity_1 .. propensity_{K-1} — the realized assignment propensities, i.e. the cell-weight blend P(Z = k | x, plan) = sum_c w_c * P_policy_c(k | x).

Real-data generators carry the same recording obligations: the loop requires the cell column, and the reserved propensity columns are the documented channel for adaptively-assigned designs (propensity at K = 2).

The adapter is K >= 3 only: the generator core’s external treatment_assignment hook exists only for multi-arm truth, and the K = 2 paired sampling path is pinned out of bounds. For a K = 2 sequential experiment, write a custom generator instead.

Parameters:
  • template (str) – Name of a registered scenario template — a key of pytyche.generators.scenarios.TEMPLATES.

  • metric (str) – Canonical metric identifier passed to the template (e.g. "revenue_per_visitor").

  • effect_scale (float) – Treatment-effect amplitude passed to the template.

  • K (int) – Number of treatment levels (control + K-1 treatments). Must be >= 3.

  • seed (int) – Master seed. Round r draws from np.random.default_rng(np.random.SeedSequence((seed, r))).

  • treatment_names (Sequence[str] | None) – Optional K unique variant names replacing the template’s, in template arm order (position 0 = baseline).

  • **template_kwargs (object) – Extra keyword arguments forwarded to the template (e.g. n_nuisance=, baseline_rate=).

Return type:

Callable[[int, NextRoundPlan], tuple[ObservedExperimentData, CalibrationTruth | None]]

Returns:

A Generator-conforming callable.

Raises:

ValueError – When template is not a registered template name, when K < 3, or when treatment_names is not exactly K unique names.