tauopt.engine.strategies.sobol#

Scrambled-Sobol space-filling strategy (the bootstrap workhorse).

The scramble seed stays FIXED for an experiment (resolve_seed derives it from the space, not the full state) and the engine fast-forwards past the points already drawn – so successive asks genuinely continue one low-discrepancy sequence.

Linear constraints are honored by rejection with FEASIBLE-index accounting: the history count skips the first skip feasible sequence points (raw fast-forward would let previously-issued points re-emerge as duplicates, since rejected draws consume sequence indexes that history never records). Unconstrained spaces keep the v0 fast-forward path verbatim.

Center-in-bootstrap (cfg.center_in_bootstrap): the domain center (0.5 per canonical normalized coordinate, decoded normally) rides the stream per the following three-branch decision table:

  1. Center ill-defined (mixed space – categorical/grid/conditional axes; plain double/integer boxes have centers) OR design-infeasible -> deterministic recorded SKIP; the stream and cursor are byte-identical to the unflagged path.

  2. Unconstrained space -> ONE fixed toroidal shift s = (0.5 - x_0) mod 1 computed from sequence index zero (a throwaway same-seed generator reads x_0, so the real cursor advances exactly as today), applied to the entire indexed stream – values only, index-independent. Shifted index 0 IS the center by construction.

  3. Linearly-constrained space (the rejection loop – shifting interacts with acceptance, so the generator cannot carry the shift) -> the center is emitted directly as slot 0 on the experiment’s first ask (skip == 0); raw index 0 is consumed-and-discarded in the center’s favor on EVERY flagged ask, and the feasible walk runs from raw index 1 with (skip - 1) feasible slots behind it – cursor mechanics identical to today from index 1 on.

“Already observed/pending” centers are emission-skips handled by the cursor law itself (any history entry => skip >= 1 => index/slot 0 already consumed) – the stream law never flips mid-experiment (the only P4-coherent reading). The branch decision is recorded in provenance via record_center (never hashed, never seeded – the flag is a top-level config field excluded from resolve_seed’s derivation, so branch-1 and flag-off streams are bit-identical).

Module Contents#

Classes#

SobolStrategy

Scrambled-Sobol space-filling strategy (the module docstring carries the stream and cursor laws). The default policy’s bootstrap rung until max(4, 2*dim) successful observations, and the rung below the GP strategies on both never-fail ladders (pin P6). Requires tauopt[local] (numpy/scipy).

API#

class tauopt.engine.strategies.sobol.SobolStrategy#

Scrambled-Sobol space-filling strategy (the module docstring carries the stream and cursor laws). The default policy’s bootstrap rung until max(4, 2*dim) successful observations, and the rung below the GP strategies on both never-fail ladders (pin P6). Requires tauopt[local] (numpy/scipy).

name#

‘sobol’

requires: tuple[str, ...]#

(‘local’,)

accepted_params: frozenset[str]#

‘frozenset(…)’

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

Return the next n decoded, linearly-feasible points of the experiment’s one indexed stream (fixed space-derived scramble seed, history skip applied), so successive asks continue a single low-discrepancy sequence (pins P4/P7). Raises ValueError when linear constraints reject 100,000 consecutive points (feasible region too small to sample).

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]#

Dedup repair path: advance the stream past collisions (exclusion-aware), at most SEQUENCE_REPAIR_FACTOR * n examined candidates.