Extending#
Base classes and mixins for new strategies, warmups and evaluators. See the guide.
- class TACTICS.thompson_sampling.strategies.base_strategy.SelectionStrategy(mode='maximize')[source]#
Abstract base class for reagent selection strategies
- abstractmethod select_reagent(reagent_list, disallow_mask=None, **kwargs)[source]#
Select one reagent index from a component’s reagent list.
The sampler calls this once per component per cycle with the keyword context
rng,component_idx,iteration,current_cycleandtotal_cycles; strategies read what they need fromkwargs.- Parameters:
- Returns:
The selected index into
reagent_list.- Return type:
- select_batch(reagent_list, batch_size, disallow_mask=None, **kwargs)[source]#
Select
batch_sizereagent indices (with replacement).Default implementation calls
select_reagent()batch_sizetimes. Not used byThompsonSampler, which builds batches itself; kept for strategies used standalone.- Parameters:
reagent_list (List) – Reagent objects with posterior distributions.
batch_size (int) – Number of indices to return.
disallow_mask (set) – Indices to exclude from selection.
**kwargs – Passed through to
select_reagent().
- Returns:
Array of selected indices, length
batch_size.- Return type:
- get_component_criticality(reagent_list)[source]#
Return criticality score for a component, or None if not supported.
Strategies with CATS (e.g., RouletteWheelSelection, BayesUCBSelection) override this to compute component criticality.
- Returns:
Criticality score >= 0, or None if the strategy doesn’t compute it.
- Return type:
float | None
- get_component_state(reagent_list, component_idx, current_cycle, total_cycles)[source]#
Return full intermediate state for a component, or None if not supported.
CATS-aware strategies (RouletteWheelSelection, BayesUCBSelection) override this to expose the complete criticality + temperature/percentile pipeline.
- class TACTICS.thompson_sampling.strategies._thermal.ThermalCyclingMixin[source]#
Heated-component bookkeeping and rotation.
Subclasses call
_init_thermal_cycling()from__init__and implement_rotation_flexibility().- rotate_component_weighted(n_components, reagent_lists, rng=None)[source]#
Rotate to the next heated component with flexibility-weighted probabilities.
Draws exactly one sample from
rngafter deterministic weight computation, so seeded runs are reproducible across strategies.- Parameters:
n_components (int) – Number of reaction components.
reagent_lists – One list of Reagent objects per component.
rng –
numpy.random.Generator; a fresh default generator if None.
- class TACTICS.thompson_sampling.strategies._thermal.GMICCriticalityMixin[source]#
Bases:
ThermalCyclingMixinGMIC criticality plus GMIC-weighted rotation.
GMIC = 0.5 * log(1 + var(posterior means) / mean(posterior variances)). High GMIC = critical component (clear winners among reagents); low GMIC = flexible component (reagents look alike). Flexible components are heated more often: weight = 1 / (1 + GMIC).
Subclasses call
_init_gmic_state()from__init__.- _calculate_gmic_details(reagent_list)[source]#
Return
(gmic, details)for one component.detailsholdssignal_var,mean_noise_varandn_active_reagents. GMIC is 0.0 when fewer than two reagents have been observed.There is deliberately no minimum-observation gate here. One used to exist in TopTwoSelection (2026-06): it zeroed a component’s GMIC whenever its least-observed active reagent had fewer than N samples. On large components (adenine’s 688 isocyanides) a single straggler pinned GMIC to zero every cycle — on 25/28 benchmark libraries — which over-weighted that component in rotation. Removing the gate lifted adenine TT-TS top-100 recovery 87.1 -> 93.2 and halved its replicate variance (sd 18.4 -> 10.6), with no change on the libraries where the gate never fired.
- Return type:
- class TACTICS.thompson_sampling.warmup.base.WarmupStrategy[source]#
Abstract base class for warmup strategies.
A warmup strategy determines how reagent combinations are generated during the warmup phase to initialize reagent posteriors.
- abstractmethod generate_warmup_combinations(reagent_lists, num_warmup_trials, disallow_tracker)[source]#
Generate reagent combinations for warmup evaluation.
Parameters:#
- reagent_listsList[List[Reagent]]
List of reagent lists, one for each component
- num_warmup_trialsint
Number of trials per reagent
- disallow_trackerDisallowTracker
Tracker to prevent duplicate combinations
Returns:#
- List[List[int]]
List of combinations, where each combination is [idx_comp1, idx_comp2, …]
- get_expected_evaluations(reagent_lists, num_warmup_trials)[source]#
Calculate expected number of evaluations for this strategy.
Default implementation: sum of reagents × trials Override for strategies with different evaluation counts.
Parameters:#
- reagent_listsList[List[Reagent]]
List of reagent lists
- num_warmup_trialsint
Number of trials per reagent
Returns:#
- int
Expected number of evaluations
- Return type:
Package layout#
PEP 562 lazy re-exports for package __init__ modules.
The package hubs (TACTICS, TACTICS.thompson_sampling, .core,
TACTICS.library_analysis) re-export names from their submodules for
convenience. Importing those submodules eagerly makes import TACTICS –
and any config-only import that passes through a hub – pay for RDKit,
scipy, sqlitedict and the plotting stack up front. Each hub instead declares
a {name: ".submodule"} map and calls install(), which resolves a
name on first attribute access and caches it in the module namespace.
Submodule paths (TACTICS.thompson_sampling.core.evaluators) are
unaffected: a lazy hub is still a regular package.