Protocols¶
Core types and interfaces for trade-study workflows.
trade_study.Direction
¶
Bases: Enum
Optimization direction for an observable.
trade_study.Observable(name, direction, weight=1.0)
dataclass
¶
A structured observable evaluated against known truth.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Identifier (e.g. "coverage_95", "relWIS", "wall_seconds"). |
direction |
Direction
|
Whether lower or higher values are better. |
weight |
float
|
Objective scaling used by weighted analysis. Strictly positive
scaling preserves Pareto membership. Default is |
trade_study.Annotation(name, lookup, key)
dataclass
¶
External information attached to configurations.
Used for costs, constraints, or metadata not computed by the simulator (e.g. dollar costs from a surveillance costing sheet).
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Column name in the results table. |
lookup |
dict[str, float] | Any
|
Dictionary mapping config key → value, or a callable. |
key |
str
|
Which config field to use for lookup. |
resolve(config)
¶
Resolve the annotation value for a given config.
Returns:
| Type | Description |
|---|---|
float
|
The resolved annotation value as a float. |
Source code in src/trade_study/protocols.py
trade_study.Scorer
¶
Bases: Protocol
Protocol for scoring model output against truth.
score(truth, observations, config)
¶
Score a single trial, returning values for each observable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
truth
|
Any
|
Known latent state from the simulator. |
required |
observations
|
Any
|
Observed data from the simulator. |
required |
config
|
dict[str, Any]
|
The configuration that produced this trial. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
Dictionary mapping observable names to scalar scores. |
Source code in src/trade_study/protocols.py
trade_study.Simulator
¶
Bases: Protocol
Protocol for generating ground truth and observations.
A simulator produces (truth, observations) pairs where truth is the known latent state and observations are what a real system would see.
generate(config)
¶
Generate a (truth, observations) pair for a given configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Dictionary of factor values defining this trial. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
A tuple of (truth, observations) where truth is the known latent |
Any
|
state and observations are the (possibly noisy/masked) data. |
Note
Implementations that want independent draws per replicate under
run_grid(..., n_reps>1) may additionally accept an
optional keyword-only rep: int parameter (e.g.
def generate(self, config, *, rep=0)) and vary their own
randomness by it (a seed derived from rep, a per-rep RNG,
etc.). :func:~trade_study.runner.run_grid detects this via
introspection and passes the current 0-indexed replicate;
simulators without a rep parameter are called unchanged and
produce identical replicates when their own random state is unchanged.
Source code in src/trade_study/protocols.py
trade_study.PartialEvaluator
¶
Bases: Protocol
Protocol for incrementally-evaluable trials.
Used by successive-halving / Hyperband to discard unpromising
configurations after a small fraction of their full budget. The budget
is opaque to the runner — it may be epochs, MCMC iterations, dataset
fractions, mesh resolutions, or seconds. Implementations should
interpret budget as "run from scratch up to this much work" so a
trial promoted from rung r to rung r+1 is re-trained at the larger
budget rather than continuing from the smaller one (this matches the
canonical Hyperband formulation; implementations are free to cache
intermediate state internally as an optimization).
evaluate(config, budget)
¶
Evaluate config at the given budget and return observables.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Dictionary of factor values defining this trial. |
required |
budget
|
float
|
Resource budget (epochs, iterations, dataset fraction, wall seconds, ...). Larger means a higher-fidelity evaluation. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
Mapping from observable name to scalar value, including the |
dict[str, float]
|
metric used for early-stopping. |
Source code in src/trade_study/protocols.py
trade_study.TrialResult(config, scores, wall_seconds=0.0, metadata=dict())
dataclass
¶
Result of a single simulation trial.
trade_study.ResultsTable(configs, scores, observable_names, annotations=None, annotation_names=list(), metadata=list())
dataclass
¶
Scored results from a study phase.
Stores configs, observable scores, annotations, and metadata as parallel arrays backed by numpy.
to_dataframe(*, include_metadata=True)
¶
Export one row per trial to a pandas DataFrame.
Factor columns appear in config insertion order, followed by
observables and annotations. Missing config keys become missing
values; categorical values retain their original values. Metadata
is flattened under meta. (for example meta.rep and
meta.standard_error.loss), retaining raw adaptive means and
replicate uncertainty. This method does not aggregate replicates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
include_metadata
|
bool
|
Include trial metadata, default True. |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A new DataFrame independent of the score and annotation arrays. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If pandas is unavailable; install the dataframe extra. |
ValueError
|
If column names collide or metadata row counts differ. |
Source code in src/trade_study/protocols.py
feasible(constraints)
¶
Return a boolean mask indicating which rows satisfy all constraints.
Each constraint references an observable or annotation column by
name. Adaptive results retain weighted scores for compatibility;
their raw means in metadata["scores"] are used here so thresholds
and standard errors remain in the observable's original units.
A row is feasible only when every constraint evaluates to True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
constraints
|
list[Constraint]
|
Constraint objects to evaluate. |
required |
Returns:
| Type | Description |
|---|---|
NDArray[bool_]
|
Boolean array of shape |
Raises:
| Type | Description |
|---|---|
KeyError
|
If a constraint references a column not found in
either |
A constraint with confidence needs per-row standard errors (see
:meth:_standard_errors), which raise ValueError when absent.
Source code in src/trade_study/protocols.py
aggregate_replicates(*, proportion_observables=None, confidence=0.95, proportion_method='wilson')
¶
Collapse replicate rows into one row per design point.
Groups rows by their metadata["design_point"] key (set by
:func:~trade_study.runner.run_grid when called with
n_reps>1) and averages scores within each group. Each
aggregated row's metadata records design_point, n_reps
(replicate count for that point), and score_std (per-observable
standard deviation across replicates, keyed by observable name).
Annotations, if present, are taken from the first replicate of each
group (annotations are resolved from the config, which is identical
across replicates of the same design point).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
proportion_observables
|
list[str] | None
|
Explicit raw 0/1 observable names for optional
fixed-sample marginal intervals. Each row must have a unique
non-negative integer |
None
|
confidence
|
float
|
Two-sided nominal level for requested intervals. |
0.95
|
proportion_method
|
str
|
"wilson" (default) or "clopper-pearson" (raises ImportError without the optional stats extra). |
'wilson'
|
Returns:
| Type | Description |
|---|---|
ResultsTable
|
A new ResultsTable with one row per unique design point. Requested |
ResultsTable
|
intervals appear under |
ResultsTable
|
DataFrame export flattens their counts, bounds and method. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If any row's metadata lacks a |
ValueError
|
If requested indicator intervals have invalid inputs. |
Examples:
>>> import numpy as np
>>> table = ResultsTable(
... [{"size": 10}, {"size": 10}],
... np.array([[1.0], [3.0]]),
... ["loss"],
... metadata=[
... {"design_point": 0, "rep": 0},
... {"design_point": 0, "rep": 1},
... ],
... )
>>> summary = table.aggregate_replicates()
>>> summary.scores.tolist()
[[2.0]]
Source code in src/trade_study/protocols.py
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | |
DataFrame export¶
Install trade-study[dataframe] and call results.to_dataframe() to get one
row per trial with factor, observable, annotation, and metadata columns.
Metadata is flattened under meta. so replicate counts and uncertainty remain
available, including meta.standard_error.<observable> and raw adaptive means
in meta.scores.<observable>. Use include_metadata=False for only factors,
scores, and annotations. Conflicting column names raise an error instead of
silently overwriting values. Use pandas frame.to_csv(path, index=False) to
export CSV. Call aggregate_replicates() explicitly first if you want grid
results collapsed to design points.
For raw 0/1 outcomes, opt in to fixed-sample interval records with
aggregate_replicates(proportion_observables=["recovered"]). DataFrame
export includes meta.proportion_intervals.recovered.low, .high, .k,
.n, .method, .confidence and .scope. See the
proportion interval guide for sampling
assumptions and the distinction from sequential or paired inference.