tabench.estimation¶
The T2 OD-estimation track: the static estimators (entropy, GLS, Spiess, SPSA,
Yang 1992, DN-Kalman) and the within-day dynamic estimators (Cascetta 1993),
with their registries. The spsa-sumo guarded estimator registers only under
the sumo extra.
T2 estimation: recover OD demand from link counts (ADR-002).
A demand-free contract (ODEstimator over EstimationTask) parallel to the
T1 model contract, the shipped classical estimators, and the shared
MSA-averaged proportion extraction they score against. The harness certifies
every emitted OD matrix through a pinned reference assignment
(tabench.metrics.estimation).
- class tabench.estimation.CallableEstimator(fn, name='callable_estimator', paradigm='learned', deterministic=False, seedable=True, trained_on=())[source]¶
Bases:
ODEstimatorAdapter turning
fn(task, rng) -> od_matrixinto a benchmark estimator.capabilitiesare instance-level (they describe the wrapped artifact): passtrained_onlineage for learned inverse models so the fairness gate can act on it, exactly asCallableModeldoes for T1.- Parameters:
fn (ODFn)
name (ClassVar[str])
paradigm (str)
deterministic (bool)
seedable (bool)
trained_on (tuple[str, ...])
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- class tabench.estimation.EstimationTask(name, network, prior, dataset, identifiability, scenario_hash, certificate=<factory>, seed=0, heldout_digest='')[source]¶
Bases:
objectEverything a T2 estimator may see. Contains NO true demand, by design.
networkcarries its declared cost functions, so white-box estimators may run their own inner assignments (their inner solver and gap are declared factors, paid from their own budget);prioris the stale seed/target matrix;datasetis theLinkCountspayload; andidentifiabilityis the public per-task report (Decision 4). The truescenario.demandis simply absent from this object — there is nothing to peek at.- Parameters:
- content_hash()[source]¶
SHA-256 instance pin over scenario hash + prior bytes + sensor links + observed counts + dataset dials + certificate pin + held-out digest + seed.
The sensor-link and count bytes make this a true instance pin: two explicit sensor placements of equal coverage, or two macroreps of a
cv=0task, no longer collide.heldout_digest(a SHA-256 the runner computes over the sorted held-out links + held-out n_periods) folds the held-out design in without leaking held-out sensor identities to the estimator (P7).- Return type:
str
- class tabench.estimation.ODEstimator(**factor_overrides)[source]¶
Bases:
ABCBase class every T2 estimator or wrapper implements.
- Parameters:
factor_overrides (Any)
- abstractmethod estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- class tabench.estimation.ODResultBundle(estimator_name, final, trace, factors=<factory>, seed_info=<factory>)[source]¶
Bases:
objectEverything one
estimatecall produced, with provenance.
- class tabench.estimation.ODState(od_matrix, coords, self_report=<factory>)[source]¶
Bases:
objectOne emitted OD estimate, mirroring
FlowState.- Parameters:
od_matrix (ndarray)
coords (Any)
self_report (dict[str, float])
- class tabench.estimation.ODTrace[source]¶
Bases:
objectOrdered stream of OD checkpoints emitted during one
estimatecall.
- class tabench.estimation.PriorBaseline(**factor_overrides)[source]¶
Bases:
ODEstimatorDo-nothing anchor: emit the prior unchanged (BO4Mob Improvement%).
Every T2 leaderboard needs the baseline every improvement is measured against; a prior that is already the truth is unbeatable, one that is far off certifies a terrible (honest) count-fit.
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.register_estimator(cls)[source]¶
Class decorator adding an estimator to the name registry.
Mirrors
register_model: only self-contained estimators belong here (the CLI instantiates them with no arguments), so a registered class must declare class-levelnameandcapabilities. Adapter-style estimators with per-instance capabilities (CallableEstimator) are passed to the runner directly and must not be registered.- Parameters:
cls (type[ODEstimator])
- Return type:
type[ODEstimator]
- tabench.estimation.active_pairs(demand_matrix)[source]¶
Ordered 0-based
(origin, destination)pairs with positive off-diagonal demand.- Parameters:
demand_matrix (ndarray)
- Return type:
list[tuple[int, int]]
- tabench.estimation.od_from_pairs(prior_matrix, pairs, g)[source]¶
Scatter a per-pair demand vector into a full OD matrix.
Off-diagonal cells outside
pairsstay zero (support is fixed by the prior); the diagonal (intrazonal demand, which never enters the network) is carried over fromprior_matrixunchanged.- Parameters:
prior_matrix (ndarray)
pairs (list[tuple[int, int]])
g (ndarray)
- Return type:
ndarray
- tabench.estimation.proportion_matrix(network, demand, k_inner, pairs=None, engine=None)[source]¶
Extract
(P, pairs, msa_flows)at the equilibrium ofdemand.Phas shape(n_links, len(pairs));msa_flows = P @ gwheregis the per-pair demand vector, so the identityv = P gis exact.k_inner >= 1is the number of MSA/AON sweeps (one shortest-path call each). Pairs default to the positive off-diagonal support ofdemand.
- class tabench.estimation.VZWEntropyEstimator(**factor_overrides)[source]¶
Bases:
ODEstimatorMaximum-entropy OD estimation by cyclic count-balancing (Van Zuylen & Willumsen 1980).
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.vzw_balance(prior, p_obs, counts, n_passes, tol=1e-09)[source]¶
Cyclic multiplicative count-balancing of
priortowardcounts.p_obsis the(n_obs, n_pairs)proportion block on the observed sensors;countsthe per-period-mean count per sensor. Returns(g, trajectory, counts_consistent)wheregis the converged iterate aftern_passesdamped balancing passes andcounts_consistentflags whether its observed-count residual has settled belowtol(mutually inconsistent counts converge to a compromise that stays above tolerance).trajectoryrecordsgafter every single-link update.- Parameters:
prior (ndarray)
p_obs (ndarray)
counts (ndarray)
n_passes (int)
tol (float)
- Return type:
tuple[ndarray, list[ndarray], bool]
- class tabench.estimation.GLSEstimator(**factor_overrides)[source]¶
Bases:
ODEstimatorGeneralized-least-squares OD estimation (Cascetta 1984).
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.gls_solve(p_obs, counts, prior, w_var, v_var)[source]¶
Nonnegative GLS estimate on the whitened stacked system.
w_var/v_varare the prior and count variances (the diagonals ofWandV). Returns the minimizingg >= 0. For a single pair and a single sensor withW = V = 1this is the closed form(g_pr + p*cbar) / (1 + p^2)(Decision-6 anchor 4).- Parameters:
p_obs (ndarray)
counts (ndarray)
prior (ndarray)
w_var (ndarray)
v_var (ndarray)
- Return type:
ndarray
- class tabench.estimation.SpiessEstimator(**factor_overrides)[source]¶
Bases:
ODEstimatorGradient OD adjustment on the count misfit (Spiess 1990).
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.spiess_step(p_obs, g, counts, damp=1.0)[source]¶
One damped Spiess descent step at fixed proportions
p_obs.Returns
max(g * (1 - damp * lambda* * grad), 0)with the linearized optimumlambda*capped at1 / max gradfor feasibility. If no descent direction exists (degeneratew) or the optimal step is nonpositive,gis returned unchanged. The Armijo safeguard is applied retrospectively in the outer loop (SpiessEstimator), whereZis re-assessed under a fresh assignment — the frozen-proportionZthis step minimizes is convex inlambdaand would never trigger a halving (ADR-002 Decision 3.3).- Parameters:
p_obs (ndarray)
g (ndarray)
counts (ndarray)
damp (float)
- Return type:
ndarray
- class tabench.estimation.SPSAEstimator(**factor_overrides)[source]¶
Bases:
ODEstimatorBlack-box OD calibration by simultaneous perturbation (Spall 1992).
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- class tabench.estimation.Yang1992Estimator(**factor_overrides)[source]¶
Bases:
ODEstimatorBilevel OD estimation on congested networks (Yang et al. 1992).
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.yang_solve(p_obs, counts, prior, theta)[source]¶
Nonnegative minimizer of Yang’s theta-weighted upper-level QP at fixed
P.argmin_{g>=0} theta * ||g - g_pr||^2 + (1 - theta) * ||P_obs g - cbar||^2, solved as a whitened stacked nonnegative least squares with weightsqrt(theta)on the prior block andsqrt(1 - theta)on the count block (scipy.optimize.lsq_linear, bounded VLS). This is the scalar-thetacase of theglswhitened system: the single deterministic trade-off in place of the statistical covariancesW,V. Strictly convex for anythetain(0, 1)(the prior block alone has full column rank), so the minimizer is unique for any sensor set. For a single pair and single sensor with proportionpthis is the closed form(theta*g_pr + (1-theta)*p*cbar) / (theta + (1-theta)*p^2).- Parameters:
p_obs (ndarray)
counts (ndarray)
prior (ndarray)
theta (float)
- Return type:
ndarray
- class tabench.estimation.DavisNihanKalmanEstimator(**factor_overrides)[source]¶
Bases:
ODEstimatorDavis & Nihan (1993) linear-Gaussian OD estimation from a count series.
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate an OD matrix, emitting checkpoints to
trace.Implementations must respect
budget(expressed in assignment-equivalentsp_calls) and record at least one checkpoint. Certification runs a full pinned assignment per checkpoint, so emit O(10-20) checkpoints – sparsely spaced (e.g. everymax(1, iters // 15)iterations) plus always the final iterate – not one per iteration (ADR-002 Decision 2). Self-reported metrics go into checkpointself_reportentries; they are provenance, never scores.- Parameters:
task (EstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.ar1_tau(counts)[source]¶
AR(1) integrated-autocorrelation time of a count series (
TxS).Estimates the pooled lag-1 autocorrelation as the trace ratio
sum_{t,s} z_{t,s} z_{t+1,s} / sum_{t,s} z_{t,s}^2of the demeaned series (z = counts - counts.mean(0)) and returns(tau, rho_hat)withtau = (1 + rho_hat) / (1 - rho_hat)– the variance-inflation factor of the time-mean of an AR(1). Summing each sensor’s OWN autocovariance (rather than pooling sensors into a scalar mean) is robust to cross-link anti-correlation: for a VAR(1) withPhi = rho Iand innovation covarianceQthe numerator isrho * tr(Q)and the denominatortr(Q), sorho_hat -> rhoeven when the monitored links are on competing routes whose fluctuations cancel in the mean (a mean-pooled estimate collapses totau ~ 1there, silently discarding the temporal correction).rho_hatis clipped to[0, 0.98](negative / anti-persistent -> no inflation,tau = 1; the ceiling keepstaufinite);tau = 1for an IID series.- Parameters:
counts (ndarray)
- Return type:
tuple[float, float]
- tabench.estimation.dn_gls_solve(p_obs, counts_mean, prior, sigma_mean, w_var)[source]¶
Nonnegative GLS whitened by the FULL Davis-Nihan count-mean covariance.
Solves:
argmin_{g>=0} (P g - cbar)^T Sigma_mean^{-1} (P g - cbar) + (g - g_pr)^T W^{-1} (g - g_pr)
as a bounded least squares on the whitened stacked system
[W^-1/2 ; Sigma_mean^-1/2 P] g ~ [W^-1/2 g_pr ; Sigma_mean^-1/2 cbar].sigma_meanis the(S, S)covariance of the count time-mean (Sigma_stat * tau / T); its off-diagonals (cross-link DN structure) and thetauinflation are what distinguish this fromgls(diagonalV,tau = 1). BecauseW^-1is strictly positive definite the problem is strictly convex for any sensor set. For a single pair and single sensor with scalarSigma_mean = s^2andW = w^2this is the closed form(g_pr / w^2 + p * cbar / s^2) / (1 / w^2 + p^2 / s^2).- Parameters:
p_obs (ndarray)
counts_mean (ndarray)
prior (ndarray)
sigma_mean (ndarray)
w_var (ndarray)
- Return type:
ndarray
- class tabench.estimation.DynamicEstimationTask(name, network, prior_profile, dataset, identifiability, scenario_hash, certificate=<factory>, seed=0, heldout_digest='')[source]¶
Bases:
objectEverything a dynamic estimator may see. Contains NO true profile, by design.
prior_profileis the stale(H, Z, Z)seed (one prior OD matrix per departure slice).datasetis theDynamicLinkCountspayload:counts(n_days, T, S), thesensor_links, the sensor-restricted exogenouslag_tensor(L+1, S, P), and the activepairs(the profile column order). The map is exogenous and hashed; the certifier regenerates the full-network map from the same recipe and never trusts this payload’s tensor.- Parameters:
name (str)
network (Network)
prior_profile (ndarray)
dataset (Dataset)
identifiability (Mapping[str, Any])
scenario_hash (str)
certificate (Mapping[str, Any])
seed (int)
heldout_digest (str)
- content_hash()[source]¶
SHA-256 instance pin (domain-prefixed
tabench-t2d-task-v2;).Covers the scenario hash, the slicing dials (
H,T, slice length, map recipe id) fromdataset.meta, the prior-profile bytes, the activepairs(the estimand’s cell layout — two tasks whose estimands live in different OD cells must never hash equal, even hand-built ones; adr-023 review), the sensor links, the observed-count bytes, the exogenous lag-tensor bytes, the certificate pin, the held-out digest, and the seed. The lag-tensor and per-slice count bytes make two macroreps of acv=0/noise='none'task, or two slicings of one scenario, distinct instances.- Return type:
str
- class tabench.estimation.DynamicODEstimator(**factor_overrides)[source]¶
Bases:
ABCBase class every within-day dynamic OD estimator implements.
Mirrors
ODEstimatorpiece for piece over aDynamicEstimationTask; the emitted artifact is a full(H, Z, Z)profile at every checkpoint, recorded through the sharedODTrace.- Parameters:
factor_overrides (Any)
- abstractmethod estimate(task, budget, rng, trace)[source]¶
Estimate the
(H, Z, Z)profile, recording it totrace.The exogenous map is given, so there is no inner assignment: both shipped estimators are single-shot solves with
sp_calls = 0. Emit the full profile at every checkpoint so certification is always well-defined.- Parameters:
task (DynamicEstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- class tabench.estimation.DynamicPriorBaseline(**factor_overrides)[source]¶
Bases:
DynamicODEstimatorDo-nothing anchor: emit the prior profile unchanged (BO4Mob Improvement%).
Every dynamic leaderboard needs the baseline every improvement is measured against; a prior profile that is already the truth is unbeatable, one that is far off certifies a terrible (honest) per-interval count-fit.
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate the
(H, Z, Z)profile, recording it totrace.The exogenous map is given, so there is no inner assignment: both shipped estimators are single-shot solves with
sp_calls = 0. Emit the full profile at every checkpoint so certification is always well-defined.- Parameters:
task (DynamicEstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.register_dynamic_estimator(cls)[source]¶
Class decorator adding a dynamic estimator to its own name registry.
Deliberately separate from
ESTIMATOR_REGISTRY: a static estimator would mis-read the(H, Z, Z)task and a dynamic one would mis-read a static(Z, Z)task, so the registries are the type gate (ADR-002 Decision 1 rationale, ADR-023).- Parameters:
cls (type[DynamicODEstimator])
- Return type:
type[DynamicODEstimator]
- class tabench.estimation.Bo4MobEstimationTask(name, instance_key, pairs, prior_vector, dataset, identifiability, engine, certificate=<factory>, seed=0, heldout_digest='')[source]¶
Bases:
objectEverything a BO4Mob T2 estimator may see. Contains NO held-out data, by design.
pairsis the fixed, ordered active(fromTaz, toTaz)OD-cell layout (from the instance’sod.xmltemplate); the estimand is a 1-D OD vector over it.prior_vectoris the stale seed (BO4Mob’sod_for_single_runexample OD).datasetis the TRAIN-only sensor payload: the anchor(date, hour)PeMS counts the estimator may fit —payload['link_ids']andpayload['counts'](P7: only the TRAIN anchor; the held-out panel lives solely inside the certifier and is folded in throughheldout_digest, never constructed into this object).identifiabilityis a light, provenance-only diagnostic (sensor-vs-active-pair coverage — BO4Mob has no declared assignment for Hazelton’s rank test, so it never gates; adr-041).enginepins the exacteclipse-sumoversion the certificate re-runs.- Parameters:
name (str)
instance_key (str)
pairs (tuple[tuple[str, str], ...])
prior_vector (ndarray)
dataset (Dataset)
identifiability (Mapping[str, Any])
engine (Mapping[str, Any])
certificate (Mapping[str, Any])
seed (int)
heldout_digest (str)
- content_hash()[source]¶
SHA-256 instance pin (domain-prefixed
tabench-t2-bo4mob-task-v1;).Covers the instance key, the active pair LAYOUT (two tasks whose estimands live in different OD cells must never hash equal — the adr-023 lesson carried to BO4Mob’s string-keyed pairs), the prior-vector bytes, the TRAIN link ids + count bytes, the TRAIN metadata dials, the exact engine pin, the certificate (engine flags + sim/OD window), the held-out digest (the ONLY held-out design that enters task identity, P7), and the seed.
- Return type:
str
- class tabench.estimation.Bo4MobODEstimator(**factor_overrides)[source]¶
Bases:
ABCBase class every BO4Mob OD estimator implements.
Mirrors
ODEstimatorpiece for piece over aBo4MobEstimationTask; the emitted artifact is a 1-D OD vector overtask.pairsat every checkpoint, recorded through the sharedODTrace.- Parameters:
factor_overrides (Any)
- abstractmethod estimate(task, budget, rng, trace)[source]¶
Estimate the OD vector over
task.pairs, recording it totrace.A black-box estimator (a future SPSA over the pipeline) runs the engine as its own inner oracle, paid from its own budget; the do-nothing prior baseline is a single-shot emit. Record at least one checkpoint (the final emitted vector) so certification is always well-defined.
- Parameters:
task (Bo4MobEstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- class tabench.estimation.Bo4MobPriorBaseline(**factor_overrides)[source]¶
Bases:
Bo4MobODEstimatorDo-nothing anchor: emit the prior OD vector unchanged (BO4Mob Improvement%).
Every BO4Mob leaderboard needs the baseline every improvement is measured against; a prior already fitting the held-out days is unbeatable, one far off certifies a terrible (honest) held-out count-fit. Registers unconditionally and imports no
sumo— the engine is the certifier’s job, not the estimator’s (unlike the simulator-in-the-loop spsa-sumo guard; adr-041).- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate the OD vector over
task.pairs, recording it totrace.A black-box estimator (a future SPSA over the pipeline) runs the engine as its own inner oracle, paid from its own budget; the do-nothing prior baseline is a single-shot emit. Record at least one checkpoint (the final emitted vector) so certification is always well-defined.
- Parameters:
task (Bo4MobEstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.register_bo4mob_estimator(cls)[source]¶
Class decorator adding a BO4Mob estimator to its own name registry.
Deliberately separate from
ESTIMATOR_REGISTRY/DYNAMIC_ESTIMATOR_REGISTRY: a static or dynamic estimator would mis-read a BO4Mob task (1-D vector over string pairs, no(Z, Z)matrix) and vice versa, so the registries are the type gate (ADR-002 Decision 1 rationale, ADR-023, adr-041).- Parameters:
cls (type[Bo4MobODEstimator])
- Return type:
type[Bo4MobODEstimator]
- class tabench.estimation.SimultaneousDynamicGLSEstimator(**factor_overrides)[source]¶
Bases:
DynamicODEstimatorSimultaneous dynamic GLS (Cascetta et al. 1993): all slices jointly.
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate the
(H, Z, Z)profile, recording it totrace.The exogenous map is given, so there is no inner assignment: both shipped estimators are single-shot solves with
sp_calls = 0. Emit the full profile at every checkpoint so certification is always well-defined.- Parameters:
task (DynamicEstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- class tabench.estimation.SequentialDynamicGLSEstimator(**factor_overrides)[source]¶
Bases:
DynamicODEstimatorSequential dynamic GLS (Cascetta et al. 1993): slice by slice, frozen carryover.
- Parameters:
factor_overrides (Any)
- estimate(task, budget, rng, trace)[source]¶
Estimate the
(H, Z, Z)profile, recording it totrace.The exogenous map is given, so there is no inner assignment: both shipped estimators are single-shot solves with
sp_calls = 0. Emit the full profile at every checkpoint so certification is always well-defined.- Parameters:
task (DynamicEstimationTask)
budget (Budget)
rng (RngBundle)
trace (ODTrace)
- Return type:
- tabench.estimation.dynamic_gls_simultaneous(a_stacked, counts, prior, w_prior, v_count)[source]¶
One whitened nonnegative GLS on the full stacked system (all slices jointly).
argmin_{x>=0} (x - z)^T W^-1 (x - z) + (A x - c)^T V^-1 (A x - c)on the stacked unknownx(H*P), solved as bounded least squares on the whitened system[W^-1/2 ; V^-1/2 A] x ~ [W^-1/2 z ; V^-1/2 c].a_stackedis(T*S, H*P);counts/v_countare(T*S,)(per interval-sensor count and its variance);prior/w_priorare(H*P,)(per slice-pair prior and its variance). BecauseW^-1is positive definite the problem is strictly convex for any sensor set. Returns the flat(H*P,)estimate.- Parameters:
a_stacked (ndarray)
counts (ndarray)
prior (ndarray)
w_prior (ndarray)
v_count (ndarray)
- Return type:
ndarray
- tabench.estimation.dynamic_gls_sequential(blocks, counts_mean, prior_profile, w_prior, v_count, n_intervals)[source]¶
Slice-by-slice GLS: each slice from its earliest observed interval, frozen.
For
h = 0..H-1in order, find the earliest intervalt_h >= hwith a nonzero block for sliceh(the slice’s first crossing of a monitored link); subtract the frozen contributions of already-estimated earlier slices fromc_{t_h}; solve the slice-local nonnegative GLS ford_hagainst that block. The two information losses that make the sequential estimator provably less efficient than the simultaneous one: (i) the slice’s own LATER crossings (intervals> t_h) are discarded, and (ii) earlier-slice estimates are frozen with no covariance propagation. (Later-slice contamination att_hcannot occur on a time-invariant tensor — a later slice’s earliest nonzero lag is the same, so its first crossing is strictly aftert_h; on a general time-varying block map any such contribution is treated as zero, a documented bias of the plug-in scheme.) A slice never observed within the horizon keeps its prior.blocks[t] = {h: (S,P)};counts_mean/v_countare(T, S);prior_profile/w_priorare(H, P). Returns the(H, P)estimate.- Parameters:
blocks (list[dict[int, ndarray]])
counts_mean (ndarray)
prior_profile (ndarray)
w_prior (ndarray)
v_count (ndarray)
n_intervals (int)
- Return type:
ndarray
- tabench.estimation.lagged_assignment_tensor(network, pairs, slice_length, n_lags=None, engine=None)[source]¶
Frozen free-flow two-interval-split lag tensor
M((L+1, n_links, P)).M[l, a, k]is the fraction of pair-pairs[k]demand crossing linkaexactlylslices after departure, under free-flow path choice and uniform within-slice departures.slice_lengthisDelta(native time units).Lis the largest lag any path induces; passn_lagsto fix a larger horizon (padded with zeros) — a smaller one raises, since dropping a contribution would break the column-mass identity. Deterministic and RNG-free.- Parameters:
network (Network)
pairs (list[tuple[int, int]])
slice_length (float)
n_lags (int | None)
engine (PathEngine | None)
- Return type:
ndarray
- tabench.estimation.predict_interval_counts(m, profile, n_intervals)[source]¶
Expected crossing counts
c_t = sum_l M[l] @ d_{t-l}(shape(T, R)).mis(L+1, R, P)(R= n_links or a sensor subset);profileis the(H, P)per-slice per-pair demand. Slices outside0..H-1contribute nothing (causality and horizon truncation), so counts are exact linear algebra.- Parameters:
m (ndarray)
profile (ndarray)
n_intervals (int)
- Return type:
ndarray
- tabench.estimation.stacked_tensor_map(m, n_slices, n_intervals)[source]¶
Stacked observation map
A((T*R, H*P)) from a time-invariant tensor.Block
(t, h)isM[t-h]on the causal band0 <= t-h <= Land zero elsewhere, soAis block-lower-banded. Row-major over(t, sensor)and(h, pair)— the layout the whitened simultaneous GLS and the identifiability rank test both use.- Parameters:
m (ndarray)
n_slices (int)
n_intervals (int)
- Return type:
ndarray
- tabench.estimation.tensor_blocks(m, n_slices, n_intervals)[source]¶
Time-invariant tensor -> per-interval block map
blocks[t] = {h: M[t-h]}.The general (possibly time-varying) representation the GLS solvers consume:
blocks[t][h]is the(R, P)block mapping slicehdemand to intervaltcounts. For the frozen tensor it is simplyM[t-h]on the causal band.- Parameters:
m (ndarray)
n_slices (int)
n_intervals (int)
- Return type:
list[dict[int, ndarray]]