Robust evaluation
Robust evaluation of a policy over the distribution an environment samples from.
evaluate runs n independent episodes of env under a fixed policy and reports the
physical final performance (mean, lower-tail CVaR, minimum) with bootstrap confidence
intervals where they are validated. The evaluation distribution is whatever the
environment carries: wrap the task in a parameter randomiser, a control-error wrapper or an
observation model first; there is no separate distribution argument. Evaluate a policy on a
distribution other than its training distribution by building the evaluation environment
separately and passing a key that the training stream did not use.
What is reported
metric: the physical final performance, read from the exactenv.info(final_state):"fidelity"for gate and state-transfer tasks, the reward quantity ("energy"or"ergotropy") for battery tasks.episode_return(the training reward summed over the episode, a gainQ(final) - Q(initial)) is reported in separate fields; aggregation is always over the metric. The metric is higher is better, so the CVaR here is the mean of the lowestceil(0.1 n)episodes, the opposite tail of a loss-based CVaR.mean,cvar(lower 10 percent tail mean) andmin. The CVaR estimator has anO(1/n)bias (for U(0, 1) its expectation is exactly(k + 1) / (2 (n + 1)),k = ceil(0.1 n), against the population value 0.05). The minimum is a descriptive statistic that falls asngrows: never compare minima of differentn.- Intervals: non-parametric percentile bootstrap over episodes (
B = 2000, 2.5 and 97.5 percentiles). The mean interval is provided forn >= 256and the CVaR interval forn >= 1024; below that only point estimates are returned, with a warning. In a Monte Carlo check (1000 independent repetitions each) the empirical coverage atn = 1024was inside [0.92, 0.98] for U(0, 1) and for a gate-fidelity-like distribution, but the CVaR interval undercovers for U(0, 1) (0.932, about 2.6 Monte Carlo standard errors below the nominal 0.95), so it is approximate and somewhat narrow. That is the evidence for those two distributions, not a coverage guarantee for any distribution: heavy-tailed, discrete or boundary-heavy performance distributions (for example a fidelity piled up at its upper bound 1) are separate validation targets. - The intervals describe the sampling variation of the evaluation episodes for the given policy. Variation across independently trained policies (seeds) is a different source; report it separately and do not merge the two into one interval.
Random numbers: key is required. The episode keys are
keys.episode_key(fold_in(key, 0), i) for i = 0, ..., n - 1, the bootstrap key is
fold_in(key, 1) and a stochastic policy receives keys.policy_key(episode_key, t) at
decision t = 0, 1, .... Use a key that does not belong to the training stream.
The outcome of an episode does not depend on the batch it is simulated in, up to the last
bits of floating-point rounding (XLA changes the operation order between batch sizes).
CVAR_LEVEL = 0.1
module-attribute
Fraction of the episodes in the lower tail averaged by :func:cvar.
N_BOOT = 2000
module-attribute
Bootstrap replicates B of the percentile intervals.
Evaluation
dataclass
Result of :func:evaluate.
Attributes:
| Name | Type | Description |
|---|---|---|
metric |
str
|
name of the aggregated performance metric. |
n |
int
|
number of episodes. |
mean |
float
|
mean of the metric. |
cvar |
float
|
mean of the lowest |
min |
float
|
smallest metric value (descriptive; falls with |
mean_interval |
tuple[float, float] | None
|
95 percent bootstrap interval of the mean, |
cvar_interval |
tuple[float, float] | None
|
95 percent bootstrap interval of the CVaR, |
return_mean |
float
|
mean episode return (training reward), reported apart from the metric. |
return_min |
float
|
smallest episode return. |
nominal |
float | None
|
metric of the same policy on |
nominal_return |
float | None
|
its episode return. |
values |
ndarray
|
per-episode metric, shape |
returns |
ndarray
|
per-episode returns, shape |
as_dict()
Plain-dict summary (floats and lists, without the per-episode arrays).
Stability
dataclass
Result of :func:stability: the evaluation at several sample sizes.
Attributes:
| Name | Type | Description |
|---|---|---|
results |
dict[int, Evaluation]
|
|
mean_spread |
float
|
|
cvar_spread |
float
|
|
bootstrap_intervals(values, key, *, mean=True, tail=True, n_boot=N_BOOT, level=0.95)
Percentile bootstrap intervals of the mean and of the CVaR of values.
Resamples the n episode values with replacement n_boot times (both statistics
use the same resamples) and returns the (1 - level) / 2 and (1 + level) / 2
percentiles of each statistic, keyed "mean" and "cvar". The resampling indices
come from a NumPy generator seeded with the data of key, so the result is a
function of (values, key) only.
cvar(values, axis=-1)
Lower-tail CVaR: mean of the lowest ceil(0.1 n) entries along axis.
Higher is better, so this is the average of the worst 10 percent of the episodes.
Ties are handled exactly (the tail is a multiset of values). Biased by O(1/n).
evaluate(env, policy, key, n=1024, metric=None, nominal_env=None, *, batch_size=None)
Evaluate policy on n independent episodes of env (see the module docs).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
env
|
Environment
|
environment to evaluate in; carries the evaluation distribution (wrappers). |
required |
policy
|
Policy
|
an open-loop action array of shape |
required |
key
|
Array
|
explicit evaluation key (required); see the module docs for the derivation. |
required |
n
|
int
|
number of episodes (default 1024; |
1024
|
metric
|
Metric
|
an |
None
|
nominal_env
|
Environment | None
|
the same task without randomisation. The policy is also run on it for
2 episodes (it is assumed deterministic; a warning is issued if the two
episodes differ) and the result is reported as |
None
|
batch_size
|
int | None
|
simulate the episodes in chunks of this size to bound memory (default: all at once). |
None
|
Returns:
| Type | Description |
|---|---|
Evaluation
|
class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
no key, a non-positive |
performance_metric(env)
Name of the physical final performance of the task behind env.
Inferred from the unwrapped environment: GateControl (average gate fidelity, leakage
included) and StateTransfer (target-state fidelity) give "fidelity";
BatteryCharging gives its reward quantity, "energy" or "ergotropy". Any other
environment raises ValueError: pass metric= to :func:evaluate explicitly.
stability(env, policy, key, sizes=DEFAULT_SIZES, metric=None, *, batch_size=None)
Mean and CVaR at several sample sizes, to show whether they have settled.
One run of max(sizes) episodes is simulated; the result for a smaller size uses the
first n of those episodes (the same episode keys as evaluate(..., n=n)), so the
sizes are nested and share one bootstrap key. Intervals follow the rules of
:func:evaluate for each size (no interval below its minimum n); no warning is
issued because showing the small sizes is the purpose of this report.
tail_count(n, level=CVAR_LEVEL)
Number k = ceil(level * n) of episodes in the lower tail (exact for 0.1).
Key tree
The key tree of randomised environments.
Every random draw of an episode is derived from the episode key alone, through a fixed
tree of jax.random.fold_in calls, so that changing how one leaf is used (how many
draws, which distribution, on or off) never changes the samples of another leaf::
run_key
episode_key[i] = fold_in(run_key, i)
0 parameters fold_in(episode_key, 0)
one key per name fold_in(., crc32(name))
1 control errors fold_in(episode_key, 1)
0 calibration fold_in(., 0)
0 gain error fold_in(., 0)
1 offset fold_in(., 1)
1 step noise fold_in(., 1)
step k fold_in(., k)
2 measurement fold_in(episode_key, 2)
observation t fold_in(., t) (t = 0 after reset, t = k after step k)
observable j fold_in(., j)
3 policy (evaluation) fold_in(episode_key, 3)
decision t fold_in(., t)
Keys are a function of the episode key and the step index only, so restarts and parallel runs do not depend on call order. Statistical independence between leaves is not proved by this construction; the tests check sample distributions and correlations empirically.
calibration_key(ep_key, which)
Key of an episode-fixed control error: GAIN or OFFSET.
check_name_tags(names)
Raise ValueError if two different names share a tag.
episode_key(run_key, i)
Key of the i-th episode of a run (the rule used by vector envs and evaluation).
measurement_key(ep_key, t, j)
Key of the finite-shot estimate of observable j in observation t.
name_tag(name)
Stable 31-bit tag of a parameter name (CRC32, so it does not depend on the order).
parameter_key(ep_key, name)
Key of the model parameter name (fixed for the episode).
policy_key(ep_key, t)
Key handed to a stochastic policy at decision t (evaluation only).
step_noise_key(ep_key, k)
Key of the control noise of step k.