tauopt.engine.strategies.gp_ei#

GP + LogEI workhorse strategy (BoTorch behind the owned seam).

SingleTaskGP with current BoTorch defaults (dimension-scaled Hvarfner priors), LogEI acquisition, double precision, MODEL-view geometry (one-hot categoricals – SigOpt parity). Hyperparameters fit on real observations only; open suggestions enter as constant-liar fantasies by conditioning (pessimistic lie), so parallel asks spread without distorting the fit (see _gp_common).

Outcome-constraint metrics (strategy=”constraint”) each get their own GP component; acquisition becomes feasibility-weighted LogEI (analytic for n=1, MC for n>1). The incumbent is the best FEASIBLE observation – with none yet feasible, the worst observed value (pessimistic: EI then rewards any probably-feasible improvement). Constraint fantasies lie AT the threshold (neutral: pending points collapse local variance without inventing feasibility evidence); the objective lie stays pessimistic (y.min). Linear parameter constraints pass to the acquisition optimizer exactly (affine in the model view), so candidates are feasible by construction.

params: timebox_s float, default 10.0, ceiling 300 – cooperative wall-clock budget; overruns raise TimeboxExceeded and the robustness ladder takes over. Checked at phase boundaries and passed to BoTorch’s fit/optimize timeouts; a single long linear-algebra call inside a phase cannot be interrupted (the sync-suggest latency envelope accounts for this). NOTE: which ladder rung answers can therefore depend on machine load – the provenance receipt records the EXECUTED strategy + seed, so any served suggestion re-derives exactly even when the live fallback decision was load-dependent. timebox_mode “budget” (default) | “off” | “caps” – “off” (the benchmarking posture) removes the wall budget entirely: fits and acquisition run to convergence, no timeout machinery is installed, TimeboxExceeded is unreachable, and no clock read can influence the suggestion (wall-independence is pinned by test). Refuses when combined with an explicit timebox_s (ambiguous intent). An ask-level max_wait_s still governs BETWEEN ladder rungs and, when set, wins over “off” for the executed rung (ask.py injects a budget-mode pair as execution context – identity unaffected). “caps”: off’s clock structure with deterministic WORK ceilings – quality-under-budget. TOP-LEVEL ONLY (this params form refuses with a pointer: fallback rungs reset params, so a params-form caps would silently re-enter budget mode down the ladder). Under caps, an ask-level max_wait_s is enforced by the ask boundary alone (cooperative rung-boundary refusal + one post-completion delivery decision, AskDeadlineExceeded) – never by injection or timeouts. num_restarts int, default 8, in [1, 64] – acqf multi-start count raw_samples int, default 128, in [restarts, 4096] – acqf raw candidate pool fit_maxiter int, in [1, 10000] – caps-mode ONLY (set outside caps refuses): per-component GP-fit L-BFGS iteration cap via fit_options (each iteration’s line search is scipy-bounded, maxls=20). Unset => the version-pinned per-stratum default (the field ceiling on uncalibrated strata; the pinned constant 50 on mixed strata). Work exhaustion returns best-so-far – never ladders. acq_maxiter int, in [1, 10000] – caps-mode ONLY: the acqf inner optimizer’s iteration cap (optimize_acqf options.maxiter; on mixed spaces it binds the alternating optimizer’s continuous steps, whose round count is pinned at the capped-mode alternating constant). Unset => the ceiling default on continuous strata; on mixed strata the library’s own deps-pinned iteration bounds govern.

Experimental mode params – each default preserves shipped behavior exactly; the non-default value is an upgrade candidate under measurement, promoted (or parked) on benchmark results:

categorical_mode  "one_hot" (default) | "mixed" | "mixed_capped"
              "mixed": MixedSingleTaskGP over the mixed-model view (one column
              per parameter, CategoricalKernel on category-index columns) +
              optimize_acqf_mixed_alternating. No-op on spaces without
              categoricals; conditional spaces are refused (ladders with
              provenance). The alternating optimizer takes no timeout: the
              timebox is checked at phase boundaries only.
              "mixed_capped" (cost-engineered candidate): "mixed" with the
              LOCKED cap bundle (module constants) -- an L-BFGS maxiter cap on
              every MLL fit this mode performs plus alternating-acqf caps
              (maxiter_alternating / num_restarts / raw_samples). The plain
              "mixed" mode's ~90% fit-cost blowup engineered down; efficacy
              still under benchmark measurement. User
              num_restarts/raw_samples params are
              VALIDATED-THEN-OVERRIDDEN on the mixed path (out-of-range
              values still reject as bad config; in-range values are
              ignored -- the mode IS the bundle; use "mixed" for tunable
              knobs); timebox_s applies unchanged. Same
              no-op on categorical-free spaces (byte-identical to the default
              path, caps inert), same conditional-space and
              feasibility_gp_fixed refusals as "mixed".
              The same enum also exists as the TOP-LEVEL config field
              ``categorical_mode`` (the composable surface that rides auto +
              the ladder); resolution = ``effective_categorical_mode``
              (both-set refused, params form unchanged for explicit
              strategy configs).
noise_mode    "median_impute" (default) | "mll_impute"
              "mll_impute": stddev-less observations impute at the stage-1
              inferred-noise level (marginal-likelihood-optimal on the same
              data) instead of the median reported stddev. Identical to the
              default at full or zero stddev coverage.
failure_mode  "exclude" (default) | "feasibility_gp" | "feasibility_gp_fixed"
              "feasibility_gp": a label GP (1=scored, 0=failed, ALL reported
              observations) joins the constrained-acquisition path at
              threshold 0.5 -- EI is weighted by the probability the point
              succeeds. Identical to the default while no failure is recorded.
              "feasibility_gp_fixed" (cost-engineered candidate): the same
              label component with FIXED hyperparameters and no MLL fit
              (see _gp_common.make_fixed_label_gp) -- feasibility_gp's 8-20x
              label-fit blowup removed; the component costs one Cholesky.
              Same inertness contract (identical to the default while no
              failure is recorded); one-hot model view only -- composing
              with categorical_mode="mixed" is refused on spaces WITH
              categoricals (ladders with provenance) and stays mixed's
              documented no-op on categorical-free spaces.

Module Contents#

Classes#

GpEiParams

gp_ei’s resolved params for one (state, cfg): what read_params returns and suggest executes.

GpEiStrategy

Single-objective GP + LogEI strategy (the module docstring carries the full model and params contract). The default policy’s post-bootstrap rung for single-metric experiments, atop the never-fail ladder gp_ei -> ucb_cl -> sobol -> random (pin P6). Requires tauopt[botorch] (torch/botorch/gpytorch).

Functions#

effective_categorical_mode

Composed-flag resolution: the top-level field (the composable surface that rides auto + the ladder) and the params form are ONE fact with two possible writers – BOTH set is refused as ambiguous, even when equal (agreement would still be two homes for one fact). The top-level value is Literal-validated at config parse; the params form keeps its str_param enum check. Absent everywhere => “one_hot”, the default.

Data#

API#

tauopt.engine.strategies.gp_ei.MIXED_CAPPED_FIT_OPTIONS: dict#

None

tauopt.engine.strategies.gp_ei.MIXED_CAPPED_ALT_OPTIONS: dict#

None

tauopt.engine.strategies.gp_ei.MIXED_CAPPED_RESTARTS#

4

tauopt.engine.strategies.gp_ei.MIXED_CAPPED_RAW_SAMPLES#

64

tauopt.engine.strategies.gp_ei.DEFAULT_NUM_RESTARTS#

8

tauopt.engine.strategies.gp_ei.DEFAULT_RAW_SAMPLES#

128

tauopt.engine.strategies.gp_ei.effective_categorical_mode(cfg: tauopt.engine.config.OptimizerConfig) → str#

Composed-flag resolution: the top-level field (the composable surface that rides auto + the ladder) and the params form are ONE fact with two possible writers – BOTH set is refused as ambiguous, even when equal (agreement would still be two homes for one fact). The top-level value is Literal-validated at config parse; the params form keeps its str_param enum check. Absent everywhere => “one_hot”, the default.

class tauopt.engine.strategies.gp_ei.GpEiParams#

Bases: typing.NamedTuple

gp_ei’s resolved params for one (state, cfg): what read_params returns and suggest executes.

box_mode: str#

None

timebox_s: float#

None

categorical_mode: str#

None

use_mixed: bool#

None

capped: bool#

None

num_restarts: int#

None

raw_samples: int#

None

noise_mode: str#

None

failure_mode: str#

None

fit_cap: int | None#

None

acq_cap: int | None#

None

class tauopt.engine.strategies.gp_ei.GpEiStrategy#

Single-objective GP + LogEI strategy (the module docstring carries the full model and params contract). The default policy’s post-bootstrap rung for single-metric experiments, atop the never-fail ladder gp_ei -> ucb_cl -> sobol -> random (pin P6). Requires tauopt[botorch] (torch/botorch/gpytorch).

name#

‘gp_ei’

requires: tuple[str, ...]#

(‘botorch’,)

accepted_params: frozenset[str]#

‘frozenset(…)’

read_params(state: tauopt.engine.state.ExperimentState, cfg: tauopt.engine.config.OptimizerConfig) → tauopt.engine.strategies.gp_ei.GpEiParams#

The ONE reading of cfg.params for this strategy – the strict typed readers, their ranges, the two-writer refusals (categorical_mode and timebox_mode set both top-level and in params), the caps posture rules, and the compositions of valid values this space cannot run (the mixed mode on a conditional space; the fixed feasibility GP with the mixed mode on a space with categoricals) – resolved against the space (the mixed strata’s defaults). suggest executes exactly what this returns; the ask boundary runs it for the intended strategy BEFORE any rung and answers a ValueError raised here as the caller’s 400 (AskValidationError naming the strategy and the key: the value and the expected domain for a typed, range or enumerated refusal, the keys and the rule for a conflict), so a mistyped value never reaches a served suggestion. Pure in (state, cfg); no math imports.

suggest(state: tauopt.engine.state.ExperimentState, cfg: tauopt.engine.config.OptimizerConfig, n: int = 1) → list[tauopt.engine.strategies.base.SuggestionDraft]#

Fit the objective GP (plus constraint/label components when configured) on aggregated scored observations, condition constant-liar fantasies for open suggestions, optimize LogEI (analytic at n=1, MC qLogEI at n>1, feasibility-weighted when constraint components exist), and return the n decoded drafts. Pure in (state, cfg) (pin P4): explicit derived seeds under torch fork_rng, single-thread compute. Raises ValueError on a multimetric state or zero scored observations, and TimeboxExceeded on wall overrun; the ask boundary catches both and descends the ladder (pin P6). Bad config never reaches here on any path: read_params refused it at the boundary first, for an explicit gp_ei and for the gp_ei the policy routes under auto (the routed config carries the caller’s top-level flags).

suggest_unique(state: tauopt.engine.state.ExperimentState, cfg: tauopt.engine.config.OptimizerConfig, n: int = 1, exclude: frozenset[str] = frozenset()) → list[tauopt.engine.strategies.base.SuggestionDraft]#

Uniqueness repair path: next eligible queue entry from the SAME acqf optimization’s restart pool (zero extra optimizer work), then <= PER_SLOT_REOPT_ALLOWANCE bounded re-optimize attempts per slot – same acqf, fresh derived IC seed; models are never re-conditioned (the acquisition function is reused unchanged).

suggest_selected(state: tauopt.engine.state.ExperimentState, cfg: tauopt.engine.config.OptimizerConfig, n: int = 1, exclude: frozenset[str] = frozenset(), select=None) → list[tauopt.engine.strategies.base.SuggestionDraft]#

Per-slot selection handshake: the SAME acqf optimization’s restart-endpoint pool becomes each slot’s capped ranked queue (zero extra optimizer work; a joint-q restart’s slot-s row is scored by the restart’s joint acquisition value); the boundary’s selector picks. No eligible entry => the owner-repair path fills the slot (recorded, no draw). Mixed-alternating mode exposes no restart pool (best-only API) – refused BEFORE any compute so the boundary falls back to the rung’s repair path, recorded pass-through.