Search#
Block 3 — configure and run. See the guide.
Configuration#
- class TACTICS.thompson_sampling.config.ThompsonSamplingConfig(*, synthesis_pipeline, num_ts_iterations, num_warmup_trials=3, strategy_config, evaluator_config, warmup_config=None, batch_size=1, log_filename=None, hide_progress=False, processes=1, min_cpds_per_core=10, track_diagnostics=False, product_library_file=None, use_boltzmann_weighting=False, seed=None, auto_detect_smarts_compatibility=True, deprotect_for_compatibility=False, desalt_for_compatibility=False)[source]#
Configuration for Thompson Sampling optimization.
The SynthesisPipeline is the single source of truth for: - Reaction SMARTS patterns - Reagent file paths - Multi-step synthesis configuration
Example
>>> from TACTICS.library_enumeration import ( ... SynthesisPipeline, ReactionDef, ReactionConfig ... ) >>> from TACTICS.thompson_sampling import ThompsonSamplingConfig >>> from TACTICS.thompson_sampling.strategies.config import GreedyConfig >>> from TACTICS.thompson_sampling.core.evaluator_config import LookupEvaluatorConfig >>> >>> # Create reaction config >>> config = ReactionConfig( ... reactions=[ReactionDef(reaction_smarts="...", step_index=0)], ... reagent_file_list=["acids.smi", "amines.smi"] ... ) >>> >>> # Create pipeline >>> pipeline = SynthesisPipeline(config) >>> >>> # Create Thompson Sampling config >>> ts_config = ThompsonSamplingConfig( ... synthesis_pipeline=pipeline, ... num_ts_iterations=1000, ... strategy_config=GreedyConfig(mode="maximize"), ... evaluator_config=LookupEvaluatorConfig(ref_filename="scores.csv"), ... )
Fields
- Parameters:
synthesis_pipeline (Any) – SynthesisPipeline instance containing reaction config and reagent files. Default: required.
num_ts_iterations (int) – Number of Thompson Sampling iterations. Default: required.
num_warmup_trials (int) – Number of warmup trials per reagent. Default:
3.strategy_config (GreedyConfig | RouletteWheelConfig | UCBConfig | EpsilonGreedyConfig | BayesUCBConfig | TopTwoConfig) – Selection strategy configuration. Default: required.
evaluator_config (LookupEvaluatorConfig | DBEvaluatorConfig | FPEvaluatorConfig | MWEvaluatorConfig | ROCSEvaluatorConfig | FredEvaluatorConfig | MLClassifierEvaluatorConfig | CustomEvaluatorConfig) – Evaluator configuration. Default: required.
warmup_config (BalancedWarmupConfig | EnhancedWarmupConfig | None) – Warmup strategy configuration. Default:
None.batch_size (int) – Compounds to sample per iteration. Default:
1.log_filename (str | None) – Log file path. Default:
None.hide_progress (bool) – Hide progress bars. Default:
False.processes (int) – Number of worker processes used for batch evaluation. Leave at 1 for fast evaluators (Lookup, DB, FP, MW), where process overhead exceeds the cost of scoring and parallelism makes runs slower. Set it to the number of allocated cores for slow evaluators (Fred docking, ROCS, ML models), where evaluation dominates runtime. Compound generation itself is fast; this parameter exists for the evaluation step. Default:
1.min_cpds_per_core (int) – Minimum compounds per worker before a batch is evaluated in parallel. Batches smaller than processes * min_cpds_per_core are evaluated sequentially to avoid process overhead on small batches. Default:
10.track_diagnostics (bool) – Track per-cycle criticality diagnostics during search. Access via sampler.get_diagnostics() after search completes. Default:
False.product_library_file (str | None) – Path to CSV with pre-enumerated products (Product_Code, SMILES). Default:
None.use_boltzmann_weighting (bool) – Boltzmann-weighted posterior update (better observations weigh more), the update rule of the recommended presets. False selects the uniform Bayesian update. Default:
False.seed (int | None) – Random seed for reproducibility. Controls all RNG sources (warmup partner selection, search sampling, component ordering). None = non-deterministic. Default:
None.auto_detect_smarts_compatibility (bool) – Auto-detect reagent-pattern compatibility. Default:
True.deprotect_for_compatibility (bool) – Apply deprotection during compatibility detection. Default:
False.desalt_for_compatibility (bool) – Apply desalting during compatibility detection. Default:
False.
Presets#
- TACTICS.thompson_sampling.presets.get_preset(preset_name='recommended', synthesis_pipeline=None, evaluator_config=None, **kwargs)[source]#
Get a configuration preset by name.
- Parameters:
preset_name (str) –
Name of preset (default:
"recommended"). Available:"recommended": Enhanced + TT-TS + Boltzmann (best overall, 86.1%)"recommended_rws": Enhanced + RWS/CATS + Boltzmann (85.5%)"baseline": Balanced + Greedy (isolates warmup contribution)
synthesis_pipeline (SynthesisPipeline) – SynthesisPipeline with reaction config and reagent files
evaluator_config – Evaluator configuration
**kwargs – Additional arguments passed to preset function, including: - mode: “maximize” or “minimize” - num_iterations: Number of iterations - batch_size: Compounds per cycle (recommended/recommended_rws, default 100) - output_dir: Directory for the run log (optional)
- Returns:
Configured preset
- Return type:
Example
>>> from TACTICS.library_enumeration import SynthesisPipeline >>> from TACTICS.library_enumeration.smarts_toolkit import ReactionConfig, ReactionDef >>> from TACTICS.thompson_sampling.core.evaluator_config import LookupEvaluatorConfig >>> >>> pipeline = SynthesisPipeline(ReactionConfig( ... reactions=[ReactionDef(reaction_smarts="...", step_index=0)], ... reagent_file_list=["acids.smi", "amines.smi"] ... )) >>> evaluator = LookupEvaluatorConfig(ref_filename="scores.csv") >>> ts_config = get_preset( ... synthesis_pipeline=pipeline, ... evaluator_config=evaluator ... )
- class TACTICS.thompson_sampling.presets.ConfigPresets[source]#
Pre-configured Thompson Sampling configurations validated by benchmarking.
Each preset corresponds to a method configuration tested across 21 combinatorial libraries (114,450+ trials). All presets support both
"maximize"and"minimize"modes.- Recommended (use for new work):
recommended: Enhanced + TT-TS + Boltzmann (best overall)recommended_rws: Enhanced + RWS/CATS + Boltzmann (close second)
- Baseline:
baseline: Balanced + Greedy (isolates warmup contribution)
- static recommended(synthesis_pipeline, evaluator_config, num_iterations=1000, batch_size=100, mode='maximize', output_dir=None)[source]#
Best-performing method from large-scale benchmarking.
Uses Top-Two Thompson Sampling with Enhanced warmup, Boltzmann weighting, and GMIC-weighted component rotation. Adaptive per-component thermal cycling auto-tunes exploration on both balanced and imbalanced libraries.
Performance: 86.1% mean top-100 recovery (114,450 trials, 21 libraries).
- Parameters:
synthesis_pipeline (SynthesisPipeline) – SynthesisPipeline with reaction config and reagent files
evaluator_config – Evaluator configuration
num_iterations (int) – Number of Thompson sampling iterations
batch_size (int) – Number of compounds to sample per cycle (default: 100)
mode (Literal['maximize', 'minimize']) – “maximize” for highest scores, “minimize” for lowest (e.g., docking)
output_dir (str | None) – Directory for the run log (created if needed). Results are returned as a DataFrame; write them yourself, e.g.
results.write_parquet(...).
- Return type:
- static recommended_rws(synthesis_pipeline, evaluator_config, num_iterations=1000, batch_size=100, mode='maximize', output_dir=None)[source]#
Roulette Wheel Selection with Enhanced warmup and Boltzmann weighting.
The original TACTICS method (CATS + GMIC-weighted rotation). Close second to TT-TS (85.5% vs 86.1% mean recovery). Preferred when thermal cycling behavior is well-understood for the target library.
Performance: 85.5% mean top-100 recovery (114,450 trials, 21 libraries).
- Parameters:
synthesis_pipeline (SynthesisPipeline) – SynthesisPipeline with reaction config and reagent files
evaluator_config – Evaluator configuration
num_iterations (int) – Number of Thompson sampling iterations
batch_size (int) – Number of compounds to sample per cycle (default: 100)
mode (Literal['maximize', 'minimize']) – “maximize” for highest scores, “minimize” for lowest (e.g., docking)
output_dir (str | None) – Directory for the run log (created if needed). Results are returned as a DataFrame; write them yourself, e.g.
results.write_parquet(...).
- Return type:
- static baseline(synthesis_pipeline, evaluator_config, num_iterations=1000, mode='maximize', output_dir=None)[source]#
Baseline method: Balanced warmup + Greedy selection.
Isolates the contribution of TACTICS’ stratified warmup without any advanced selection strategy. Useful as a reference point — the gap between this baseline and
recommendedmeasures the value added by TT-TS and GMIC-weighted rotation.Performance: Balanced warmup + Greedy gives +1.5 pts over random warmup + Greedy (the 1.x baseline) on 2-component libraries via warmup alone (significant on 10/11).
- Parameters:
synthesis_pipeline (SynthesisPipeline) – SynthesisPipeline with reaction config and reagent files
evaluator_config – Evaluator configuration
num_iterations (int) – Number of Thompson sampling iterations
mode (Literal['maximize', 'minimize']) – “maximize” for highest scores, “minimize” for lowest (e.g., docking)
output_dir (str | None) – Directory for the run log (created if needed). Results are returned as a DataFrame; write them yourself, e.g.
results.write_parquet(...).
- Return type:
Sampler#
- class TACTICS.thompson_sampling.core.sampler.ThompsonSampler(synthesis_pipeline, selection_strategy, warmup_strategy=None, log_filename=None, batch_size=1, processes=1, min_cpds_per_core=10, product_library_file=None, use_boltzmann_weighting=False, seed=None, track_diagnostics=False)[source]#
Run a Thompson Sampling search over a combinatorial library.
The usual way to build one is
from_config(), which wires the strategy, warmup, evaluator and reagents from aThompsonSamplingConfig. Direct construction is for tests and custom pipelines: after__init__callread_reagents()andset_evaluator(), thenwarm_up(),search(), andclose().- Parameters:
synthesis_pipeline (SynthesisPipeline) – Reaction definition(s) and reagent files. The single source of truth for how a product is made from a reagent tuple.
selection_strategy (SelectionStrategy) – How reagents are chosen each cycle (e.g.
TopTwoSelection,RouletteWheelSelection).warmup_strategy (WarmupStrategy, optional) – How initial observations are collected before the posteriors exist. Default
EnhancedWarmup().log_filename (str, optional) – Write the run log to this file as well as the console.
batch_size (int, default 1) – Compounds sampled per cycle (independent of parallel evaluation).
processes (int, default 1) – Worker processes for evaluation. Worth it only for slow evaluators (docking, ROCS, ML); for lookup evaluators the overhead exceeds the lookup. With
processes > 1the evaluator must be set with its config (seeset_evaluator()) so each worker can rebuild it.min_cpds_per_core (int, default 10) – Evaluation is triggered once
processes * min_cpds_per_corecompounds have accumulated (or at the last cycle).product_library_file (str, optional) – CSV with
Product_CodeandSMILEScolumns of pre-enumerated products. Looked up before synthesis; misses fall back to synthesis.use_boltzmann_weighting (bool, default False) – Boltzmann-weighted posterior update (the update rule the recommended presets use) instead of the uniform Bayesian update.
seed (int, optional) – Seeds the sampler’s random generator, which drives reagent selection and component rotation. (Warmup pairing uses the
seedon the warmup strategy, where one exists.)track_diagnostics (bool, default False) – Record per-cycle component state so
get_diagnostics()returns a trajectory. Small cost per cycle.
- classmethod from_config(config)[source]#
Create a ThompsonSampler from a Pydantic configuration.
- Parameters:
config (ThompsonSamplingConfig) – ThompsonSamplingConfig with synthesis_pipeline, strategy_config, warmup_config, and evaluator_config
- Returns:
Configured sampler instance
- Return type:
Example
>>> from TACTICS.library_enumeration import SynthesisPipeline >>> from TACTICS.library_enumeration.smarts_toolkit import ReactionDef, ReactionConfig >>> from TACTICS.thompson_sampling import ThompsonSamplingConfig >>> from TACTICS.thompson_sampling.strategies.config import GreedyConfig >>> from TACTICS.thompson_sampling.core.evaluator_config import LookupEvaluatorConfig >>> >>> # Create pipeline >>> rxn_config = ReactionConfig( ... reactions=[ReactionDef(reaction_smarts="...", step_index=0)], ... reagent_file_list=["acids.smi", "amines.smi"] ... ) >>> pipeline = SynthesisPipeline(rxn_config) >>> >>> # Create Thompson Sampling config >>> ts_config = ThompsonSamplingConfig( ... synthesis_pipeline=pipeline, ... num_ts_iterations=1000, ... strategy_config=GreedyConfig(mode="maximize"), ... evaluator_config=LookupEvaluatorConfig(ref_filename="scores.csv") ... ) >>> sampler = ThompsonSampler.from_config(ts_config)
- close()[source]#
Close the parallel evaluator and clean up resources.
Call this when done with the sampler to properly shut down the multiprocessing pool.
- load_product_library(library_file)[source]#
Load pre-enumerated product library for testing mode.
When a product library is provided, the sampler will skip reaction synthesis and directly lookup product SMILES from the library using product codes. This is useful for testing on pre-enumerated libraries where synthesis is redundant.
- Parameters:
library_file (str) – Path to CSV file with ‘Product_Code’ and ‘SMILES’ columns
- Raises:
FileNotFoundError – If library file doesn’t exist
ValueError – If required columns are missing
- read_reagents(reagent_file_list, num_to_select=None)[source]#
Read reagents from file list with optional Boltzmann weighting and mode
- set_evaluator(evaluator, evaluator_config=None)[source]#
Define the evaluator.
Automatically disables multiprocessing for fast evaluators (LookupEvaluator, DBEvaluator) where pickle overhead exceeds evaluation time.
- Parameters:
evaluator – The evaluator instance used to score compounds.
evaluator_config – Optional picklable config (Pydantic model) that can recreate
evaluator. Required forprocesses > 1with OpenEye-backed evaluators, whose SWIG objects cannot be pickled: each worker builds its own evaluator from this config instead of receiving one over the pipe.from_configsupplies it automatically.
- evaluate(choice_list)[source]#
Evaluate a single set of reagents.
NOTE: This method does NOT update reagent scores. Score updates must be done by the caller after evaluation to ensure compatibility with multiprocessing.
- warm_up(num_warmup_trials=3)[source]#
Warm-up phase using configured warmup strategy.
The warmup strategy determines how reagent combinations are generated to initialize reagent posteriors before the main search begins.
- Parameters:
num_warmup_trials – Number of trials per reagent
- Returns:
Warmup results with columns [“score”, “SMILES”, “Name”]
- Return type:
pl.DataFrame
- search(num_cycles=100, max_evaluations=None)[source]#
Unified search loop that works with any batch_size.
Supports batch_size=1 (single compound per cycle) or batch_size>1 (multiple compounds per cycle).
- Parameters:
num_cycles – Maximum number of sampling cycles to run
max_evaluations – Maximum number of unique compounds to evaluate (optional) If specified, search stops after evaluating this many unique compounds
- Returns:
Search results with columns [“score”, “SMILES”, “Name”]
- Return type:
pl.DataFrame
Selection strategies#
Configs#
Pydantic configuration models for selection strategies.
- class TACTICS.thompson_sampling.strategies.config.GreedyConfig(*, strategy_type='greedy', mode='maximize')[source]#
Configuration for Greedy selection strategy.
Pure argmax Thompson Sampling: sample posteriors, pick the best.
Fields
- Parameters:
mode (Literal['maximize', 'minimize']) – Default:
'maximize'.
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.strategies.config.RouletteWheelConfig(*, strategy_type='roulette_wheel', mode='maximize', alpha=0.1, beta=0.05, cats_range=None, cats_ema_decay=None, divergence_threshold=0.1, adaptive_temperature=False, alpha_increment=0.01, beta_increment=0.001, efficiency_threshold=0.1, alpha_max=2.0)[source]#
Configuration for Roulette Wheel selection with Component-Aware Thompson Sampling (CATS).
Combines thermal cycling with component criticality analysis for efficient exploration of ultra-large combinatorial libraries. CATS automatically adjusts exploration based on Shannon entropy-based criticality.
References
Zhao, H., Nittinger, E. & Tyrchan, C. Enhanced Thompson Sampling by Roulette Wheel Selection for Screening Ultra-Large Combinatorial Libraries. bioRxiv 2024.05.16.594622 (2024)
Fields
- Parameters:
mode (Literal['maximize', 'minimize', 'maximize_boltzmann', 'minimize_boltzmann']) – Default:
'maximize'.alpha (float) – Base temperature for heated component. Default:
0.1.beta (float) – Base temperature for cooled components. Default:
0.05.cats_range (float | None) – Override alpha/beta-derived CATS multiplier range. If set, cats_max = cats_range, cats_min = 1/cats_range. When None, range is derived from alpha/beta ratio. Default:
None.cats_ema_decay (float | None) – EMA decay factor for smoothing relative GMIC in the CATS multiplier. When set, relative_gmic is replaced by an EMA that accumulates directional signal across cycles. Smaller values = smoother. None disables smoothing (default, backward compatible). Must be in (0, 1) when set. Typical range: 0.05-0.15. Default:
None.divergence_threshold (float) – KL divergence threshold for switching from diversity to GMIC criticality mode. Default:
0.1.adaptive_temperature (bool) – Enable adaptive temperature control (increase alpha/beta when sampling efficiency drops). Default:
False.alpha_increment (float) – Amount to increase alpha when efficiency drops below threshold. Default:
0.01.beta_increment (float) – Amount to increase beta when zero unique compounds found. Default:
0.001.efficiency_threshold (float) – Efficiency below which alpha is incremented. Default:
0.1.alpha_max (float) – Maximum alpha value. Default:
2.0.
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.strategies.config.UCBConfig(*, strategy_type='ucb', mode='maximize', c=2.0)[source]#
Configuration for Upper Confidence Bound selection.
Fields
- Parameters:
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.strategies.config.EpsilonGreedyConfig(*, strategy_type='epsilon_greedy', mode='maximize', epsilon=0.1, decay=0.995)[source]#
Configuration for Epsilon-Greedy selection with decaying epsilon.
Fields
- Parameters:
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.strategies.config.TopTwoConfig(*, strategy_type='top_two', mode='maximize', beta=0.5, heated_scale=1.5, cooled_scale=0.75, adaptive_temperature=False, scale_increment=0.01, cooled_scale_increment=0.001, efficiency_threshold=0.1, heated_scale_max=5.0, adaptive_disagreement=True, disagreement_high_threshold=0.8, disagreement_low_threshold=0.3, disagreement_decay_rate=0.95, ema_alpha=0.02, heated_scale_min=1.0, gmic_convergence_gate=None, max_growth_per_step=None, disagreement_window=200)[source]#
Configuration for Top-Two Thompson Sampling (TT-TS).
TT-TS targets best-arm identification rather than regret minimization. It draws two independent posterior samples and explores challengers when there is genuine uncertainty about which reagent is best.
Supports asymmetric thermal cycling via posterior std scaling. Criticality is used strictly for weighted component rotation — it does NOT produce a temperature multiplier.
- Reference:
Russo, D. (2020). Simple Bayesian Algorithms for Best-Arm Identification. Operations Research, 68(6), 1625-1647.
Fields
- Parameters:
mode (Literal['maximize', 'minimize']) – Default:
'maximize'.beta (float) – Probability of selecting the challenger when two posterior samples disagree on the best reagent. β=0.5 gives equal weight to exploration and exploitation. Higher β → more exploration of uncertain reagents. Default:
0.5.heated_scale (float) – Multiplier on posterior std for the heated component. >1 inflates uncertainty → more TT-TS disagreement → exploration. Set to 1.0 to disable thermal cycling. Default:
1.5.cooled_scale (float) – Multiplier on posterior std for cooled components. <1 deflates uncertainty → more TT-TS agreement → exploitation. Set to 1.0 to disable thermal cycling. Default:
0.75.adaptive_temperature (bool) – Enable adaptive thermal cycling. Progressively increases heated_scale and decreases cooled_scale when sampling efficiency drops, counteracting posterior tightening over long searches. Default:
False.scale_increment (float) – Amount to increase heated_scale when efficiency drops below threshold. Default:
0.01.cooled_scale_increment (float) – Amount to decrease cooled_scale when zero unique compounds found. Default:
0.001.efficiency_threshold (float) – Efficiency below which heated_scale is incremented. Default:
0.1.heated_scale_max (float) – Maximum heated_scale value. Default:
5.0.adaptive_disagreement (bool) – Enable bidirectional disagreement-rate adaptation. Tracks per-component TT-TS disagreement rate via exponential moving average. Reduces heated_scale when disagreement is saturated (>high_threshold) and increases it when too low (<low_threshold). Ensures TT-TS works optimally on both balanced and imbalanced libraries. Default:
True.disagreement_high_threshold (float) – Disagreement rate above which heated_scale is reduced toward 1.0. Default:
0.8.disagreement_low_threshold (float) – Disagreement rate below which heated_scale is increased. Default:
0.3.disagreement_decay_rate (float) – Multiplicative decay factor for heated_scale adaptation. Applied to the excess (heated_scale - 1.0) each adaptation step. Default:
0.95.ema_alpha (float) – Exponential moving average smoothing factor for per-component disagreement tracking. Smaller = smoother (longer memory). Default:
0.02.heated_scale_min (float) – Minimum heated_scale value (floor). Default 1.0 = raw posteriors. Default:
1.0.gmic_convergence_gate (float | None) – GMIC threshold above which heated_scale inflation is suppressed. When a component’s GMIC exceeds this value, the adaptive rule will not inflate its heated_scale even if disagreement is low — the component is already converged and low disagreement is correct. Set to None to disable (default). Typical values: 0.5–1.0. Default:
None.max_growth_per_step (float | None) – Maximum heated_scale increase per adaptation step. Caps the per-step growth when a component converges rapidly (disagreement drops below low_threshold). Set to None for uncapped growth (default). Disabled after diagnostic analysis showed the ‘runaway’ on balanced 3-comp libraries has no measurable recovery impact — the smaller TACTICS advantage on those libraries is due to easier SAR (higher min_GMIC), not mechanism malfunction. Default:
None.disagreement_window (int) – Rolling window size for global disagreement rate (diagnostics). Default:
200.
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.strategies.config.BayesUCBConfig(*, strategy_type='bayes_ucb', mode='maximize', initial_p_high=0.9, initial_p_low=0.6, min_observations=5, cats_exploration_fraction=0.3, criticality_metric='ipr', n_adaptive_sharpening=True)[source]#
Configuration for Bayes-UCB selection with Component-Aware Thompson Sampling (CATS).
Uses Bayesian Upper Confidence Bounds with Student-t quantiles and combines percentile-based thermal cycling with component criticality analysis for efficient exploration of ultra-large combinatorial libraries.
The percentile parameters serve as an analog to temperature in thermal cycling: - Higher percentile → wider confidence bounds → more exploration - Lower percentile → tighter bounds → more exploitation
CATS automatically adjusts exploration based on Shannon entropy-based criticality.
References
Kaufmann, E., Cappé, O., & Garivier, A. (2012). On Bayesian upper confidence bounds for bandit problems. In AISTATS.
Fields
- Parameters:
mode (Literal['maximize', 'minimize']) – Default:
'maximize'.initial_p_high (float) – Base percentile for heated component (more exploration). Default:
0.9.initial_p_low (float) – Base percentile for cooled components (more exploitation). Default:
0.6.min_observations (int) – Minimum observations per reagent before trusting criticality. Default:
5.cats_exploration_fraction (float | None) – Fraction of total cycles during which CATS explores at full strength. After this point, CATS influence decays linearly if criticality remains low. Set to None to disable decay. (default: 0.3 = first 30% of cycles). Default:
0.3.criticality_metric (Literal['ipr', 'shannon']) – Metric for computing component criticality. ‘ipr’ uses Inverse Participation Ratio (sensitive to probability concentration). ‘shannon’ uses Shannon entropy (the earlier metric; insensitive at large N). Default:
'ipr'.n_adaptive_sharpening (bool) – Enable N-adaptive sharpening of z-scores before softmax. Counteracts softmax flattening for components with many reagents (large N). Only applies when criticality_metric=’ipr’. Default:
True.
Unknown keyword arguments raise
pydantic.ValidationError.
Classes#
- class TACTICS.thompson_sampling.strategies.top_two_selection.TopTwoSelection(mode='maximize', beta=0.5, heated_scale=1.5, cooled_scale=0.75, adaptive_temperature=False, scale_increment=0.01, cooled_scale_increment=0.001, efficiency_threshold=0.1, heated_scale_max=5.0, adaptive_disagreement=True, disagreement_window=200, disagreement_high_threshold=0.8, disagreement_low_threshold=0.3, disagreement_decay_rate=0.95, ema_alpha=0.02, heated_scale_min=1.0, gmic_convergence_gate=None, max_growth_per_step=None)[source]#
Top-Two Thompson Sampling with asymmetric thermal cycling.
- Two orthogonal mechanisms:
TT-TS selection — draws two posterior samples; when they disagree on the best reagent, explores the challenger with probability β.
Thermal cycling — scales posterior std asymmetrically across components. The heated component gets inflated uncertainty (more disagreement → more exploration), cooled components get deflated uncertainty (more agreement → more exploitation).
Component criticality is computed via GMIC (Gaussian Mutual Information Criticality) and used ONLY for weighted rotation — deciding which component gets heated. It does not produce a temperature multiplier.
- Parameters:
mode (str) – “maximize” or “minimize” optimization direction.
beta (float) – Probability of selecting the challenger when samples disagree. β=0.5 gives equal exploration/exploitation balance.
heated_scale (float) – Multiplier on posterior std for the heated component. >1 inflates uncertainty → more TT-TS disagreement → exploration.
cooled_scale (float) – Multiplier on posterior std for cooled components. <1 deflates uncertainty → more TT-TS agreement → exploitation.
- select_reagent(reagent_list, disallow_mask=None, **kwargs)[source]#
Select a reagent using Top-Two Thompson Sampling.
Scale posterior std by thermal cycling (heated/cooled).
Draw two independent posterior samples with scaled std.
Find the best reagent under each sample.
If they disagree, select the challenger with probability β.
If they agree, exploit the believed-best.
- Return type:
- adapt_heated_scale()[source]#
Adapt per-component heated_scale based on disagreement rate.
Called once per iteration (after rotation). Checks the EMA disagreement rate for the currently-heated component and adjusts its per-component heated_scale:
If disagreement > high_threshold: decay toward 1.0
If disagreement < low_threshold: grow away from 1.0
Otherwise: stable, no change
- Returns:
True if heated_scale was adjusted, False otherwise.
- Return type:
- adapt_temperatures(n_unique, n_attempted)[source]#
Adapt thermal cycling scales based on sampling efficiency.
Mirrors RouletteWheelSelection.adapt_temperatures but operates on posterior std scales instead of Boltzmann temperatures, and its zero-unique branch cools cooled_scale downward (with a floor) where RWS heats beta upward – kept separate for that reason. When posteriors tighten, TT-TS samples agree more often (less challenger exploration), causing recovery to stall. Increasing heated_scale counteracts this by inflating uncertainty on the heated component, generating more disagreement and thus more exploration.
- Parameters:
n_unique – Number of unique compounds generated in this batch.
n_attempted – Number of compounds attempted in this batch.
- Returns:
True if scales were adjusted, False otherwise.
- class TACTICS.thompson_sampling.strategies.roulette_wheel.RouletteWheelSelection(mode='maximize', alpha=0.1, beta=0.1, adaptive_temperature=False, alpha_increment=0.01, beta_increment=0.001, efficiency_threshold=0.1, alpha_max=2.0, cats_range=None, divergence_threshold=0.1, cats_ema_decay=None)[source]#
Roulette wheel selection with Component-Aware Thompson Sampling (CATS).
Combines thermal cycling with component criticality analysis for efficient exploration of ultra-large combinatorial libraries.
References
Zhao, H., Nittinger, E. & Tyrchan, C. Enhanced Thompson Sampling by Roulette Wheel Selection for Screening Ultra-Large Combinatorial Libraries. bioRxiv 2024.05.16.594622 (2024)
- get_component_state(reagent_list, component_idx, current_cycle, total_cycles)[source]#
Return full intermediate state for a component.
Computes GMIC criticality with divergence-gated temperature adjustment. Caches the result on
self._last_component_states[component_idx].
- select_reagent(reagent_list, disallow_mask=None, **kwargs)[source]#
Select a reagent using roulette wheel selection with CATS.
- Parameters:
reagent_list – List of Reagent objects with posterior distributions
disallow_mask – Optional set of indices to exclude from selection
**kwargs – Additional context: - rng: Random number generator - component_idx: Which reaction component - current_cycle: Current search cycle (for CATS) - total_cycles: Total number of cycles (for CATS)
- Returns:
Index of selected reagent
- adapt_temperatures(n_unique, n_attempted)[source]#
Adapt temperatures based on sampling efficiency (after Zhao et al. 2025).
When posteriors tighten, selection concentrates on a few reagents, leading to more duplicate combinations. Increasing temperatures counteracts this by broadening the selection distribution.
Mirrors the adaptive mechanism from the ETS paper’s RWSSampler: - alpha += alpha_increment when efficiency < threshold - beta += beta_increment when zero unique compounds found
Kept separate from TopTwoSelection.adapt_temperatures on purpose: the zero-unique branches differ in direction (this heats beta upward; TT-TS cools cooled_scale downward with a floor).
- Parameters:
n_unique – Number of unique compounds generated in this batch
n_attempted – Number of compounds attempted in this batch
- Returns:
True if temperatures were adjusted, False otherwise
- class TACTICS.thompson_sampling.strategies.greedy_selection.GreedySelection(mode='maximize')[source]#
Standard greedy selection: sample posteriors, pick argmax (or argmin).
- class TACTICS.thompson_sampling.strategies.ucb_selection.UCBSelection(mode='maximize', c=2.0)[source]#
Upper Confidence Bound selection.
Note
Baseline strategy. Benchmarking (114,450+ trials, 21 libraries) shows
TopTwoSelectionandRouletteWheelSelectionconsistently outperform UCB. Useget_preset()for recommended defaults.- 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:
reagent_list – Reagent objects with posterior
mean/std/n_samples.disallow_mask – Indices that must not be selected (already sampled in combination with the other components’ current picks).
**kwargs – Per-cycle context from the sampler (see above).
- Returns:
The selected index into
reagent_list.
- class TACTICS.thompson_sampling.strategies.epsilon_greedy.EpsilonGreedySelection(mode='maximize', epsilon=0.1, decay=0.995)[source]#
Epsilon-greedy selection with decaying epsilon.
Note
Baseline strategy. Benchmarking (114,450+ trials, 21 libraries) shows
TopTwoSelectionandRouletteWheelSelectionconsistently outperform epsilon-greedy. Useget_preset()for recommended defaults.- 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:
reagent_list – Reagent objects with posterior
mean/std/n_samples.disallow_mask – Indices that must not be selected (already sampled in combination with the other components’ current picks).
**kwargs – Per-cycle context from the sampler (see above).
- Returns:
The selected index into
reagent_list.
- class TACTICS.thompson_sampling.strategies.bayes_ucb_selection.BayesUCBSelection(mode='maximize', initial_p_high=0.9, initial_p_low=0.6, min_observations=5, cats_exploration_fraction=0.3, criticality_metric='ipr', n_adaptive_sharpening=True, **kwargs)[source]#
Bayesian Upper Confidence Bound selection with Component-Aware Thompson Sampling (CATS).
Combines percentile-based thermal cycling with component criticality analysis for efficient exploration of ultra-large combinatorial libraries.
Note
Baseline strategy. Benchmarking (114,450+ trials, 21 libraries) shows
TopTwoSelectionandRouletteWheelSelectionconsistently outperform BayesUCB. Useget_preset()for recommended defaults.Uses Student-t quantiles for proper Bayesian treatment of uncertainty. Percentile levels serve as analog to temperature in RWS: - Higher percentile → wider confidence bounds → more exploration - Lower percentile → tighter bounds → more exploitation
- get_component_criticality(reagent_list)[source]#
Return CATS criticality score for a component.
- Return type:
- get_component_state(reagent_list, component_idx, current_cycle, total_cycles)[source]#
Return full intermediate state for a component.
Same schema as RouletteWheelSelection for DataFrame consistency. Now includes SNR dampening (aligned with RWS) and IPR details.
final_temperaturemaps to the CATS-adjusted percentile value.
- select_reagent(reagent_list, disallow_mask=None, **kwargs)[source]#
Select a single reagent using Bayes-UCB indices with CATS.
Computes UCB index for each reagent based on posterior distribution (mean, std, n_samples) and CATS-adjusted percentile, then selects via argmax.
- Parameters:
reagent_list – List of Reagent objects with posterior distributions
disallow_mask – Optional set of indices to exclude from selection
**kwargs – Additional context: - component_idx: Which reaction component - current_cycle: Current search cycle (for CATS) - total_cycles: Total number of cycles (for CATS) - rng: Random number generator (not used but kept for API compatibility)
- Returns:
Index of selected reagent
Warmup strategies#
Pydantic configuration models for warmup strategies.
- class TACTICS.thompson_sampling.warmup.config.EnhancedWarmupConfig(*, warmup_type='enhanced')[source]#
Configuration for Enhanced warmup strategy (recommended).
Uses stochastic parallel pairing where all reagents are shuffled and paired exhaustively in each trial. Universally optimal across both balanced and imbalanced libraries. On imbalanced libraries, its natural over-sampling of the small component pre-solves that component’s ranking during warmup, which GMIC-weighted rotation then exploits during search.
Fields
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.warmup.config.BalancedWarmupConfig(*, warmup_type='balanced', observations_per_reagent=5, seed=None, use_per_reagent_variance=True, shrinkage_strength=3.0)[source]#
Configuration for Balanced warmup strategy.
Guarantees exactly K observations per reagent using stratified partner selection. Useful for isolating framework gains (e.g., Balanced-Greedy provides +1.5 pts on 2-component libraries via warmup alone). For best overall results, prefer
EnhancedWarmupConfig.This ensures: 1. Every reagent gets exactly observations_per_reagent observations 2. Partners are selected from K different strata (no duplicates) 3. Optional seeded RNG for reproducibility
Total evaluations: sum(component_sizes) x observations_per_reagent
Example
For 130 acids x 3844 amines with K=5: Total = (130 + 3844) x 5 = 19,870 evaluations Every reagent gets exactly 5 observations.
Fields
- Parameters:
observations_per_reagent (int) – Number of observations guaranteed per reagent (K). Must be >= 3 for reliable variance estimation. Default:
5.seed (int | None) – Random seed for reproducibility. None = random each run. Default:
None.use_per_reagent_variance (bool) – If True, estimate variance per-reagent using warmup observations with James-Stein shrinkage. If False, use global variance. Default:
True.shrinkage_strength (float) – Shrinkage parameter for per-reagent variance estimation. Higher = more regularization toward global variance. With n observations: weight = n / (n + shrinkage_strength). Default:
3.0.
Unknown keyword arguments raise
pydantic.ValidationError.
- class TACTICS.thompson_sampling.warmup.enhanced.EnhancedWarmup[source]#
Enhanced warmup strategy using stochastic parallel pairing.
The default warmup and the one both recommended presets use. Each trial shuffles every component and pairs reagents exhaustively, repeating for num_warmup_trials times.
Key Characteristic: IMBALANCED sampling#
Small components get over-sampled relative to large components because they are repeated to match the size of the largest component.
Example: 130 acids × 3844 amines - Each acid appears ~30 times per trial (repeated to match 3844) - Each amine appears 1 time per trial - Result: acids get 300 samples, amines get 10 samples (30x imbalance!)
Characteristics:#
Balance: ❌ Small component gets N×(rmax/rmin) samples, large gets N samples
Diversity: ✅ Guaranteed (shuffled pairing each trial)
Coverage: Excellent for small component (~7.8% of all partners)
Evaluations: max(component_sizes) × num_warmup_trials
Use case: When you WANT comprehensive small-component coverage
Example:#
For 130 acids and 3844 amines with 10 trials: - Generates 3844 pairs per trial - Acids are repeated: [a1,a2,…a130] × 30 = 3844 slots - Amines used once: [m1,m2,…m3844] - Shuffle both, pair up: [(a_i, m_j) for all j in 1..3844] - Repeat 10 times with different shuffles - Total: 38,440 evaluations - Each acid tested with ~300 different amines - Each amine tested with 10 different acids
Trade-off:#
Provides comprehensive coverage of small component but creates imbalanced posteriors. Use this if you specifically want to thoroughly explore the small component’s interactions with the large component.
- get_name()[source]#
Return strategy name for logging.
Returns:#
- str
Human-readable strategy name
- Return type:
- get_expected_evaluations(reagent_lists, num_warmup_trials)[source]#
Calculate expected evaluations for parallel pairing.
Returns: max(component_sizes) × num_warmup_trials
- Return type:
- generate_warmup_combinations(reagent_lists, num_warmup_trials, disallow_tracker)[source]#
Generate warmup combinations using stochastic parallel pairing.
Algorithm:#
For each trial: a. Shuffle all reagent indices in each component b. Repeat small components to match largest component size c. Transpose to create pairs d. Add all pairs to combinations list
This creates balanced trials (all reagents paired once per trial) but imbalanced sampling (small components over-sampled).
- class TACTICS.thompson_sampling.warmup.balanced.BalancedWarmup(observations_per_reagent=5, seed=None, use_per_reagent_variance=True, shrinkage_strength=3.0)[source]#
Balanced warmup strategy guaranteeing exactly K observations per reagent.
This strategy ensures: 1. Every reagent gets exactly observations_per_reagent observations 2. Partners are selected using stratified sampling (no duplicates within a reagent’s trials) 3. Optional seeded RNG for reproducibility
Characteristics:#
Balance: Each reagent gets exactly K observations (no imbalance)
Diversity: Partners sampled from K different strata (no duplicates)
Evaluations: sum(component_sizes) x observations_per_reagent
Reproducibility: Optional seed for deterministic results
Example:#
For 130 acids and 3844 amines with K=5: - Each acid tested with 5 amines from different strata - Each amine tested with 5 acids from different strata - Total: (130 + 3844) x 5 = 19,870 evaluations - Every reagent guaranteed exactly 5 observations
Parameters:#
- observations_per_reagentint, default=5
Number of observations guaranteed per reagent (K)
- seedint or None, default=None
Random seed for reproducibility. None = random each run.
- get_name()[source]#
Return strategy name for logging.
Returns:#
- str
Human-readable strategy name
- Return type:
- generate_warmup_combinations(reagent_lists, num_warmup_trials, disallow_tracker)[source]#
Generate warmup combinations with exactly K observations per reagent.
Uses stratified partner selection: divides partner space into K strata and samples one partner from each stratum, guaranteeing diversity.
Note: The num_warmup_trials parameter is ignored - we use observations_per_reagent instead. This ensures the caller’s expectation of “trials per reagent” is honored.
- Parameters:
- Returns:
List of combinations [idx_comp1, idx_comp2, …]
- Return type:
Reagent#
- class TACTICS.thompson_sampling.core.reagent.Reagent(reagent_name, smiles, use_boltzmann_weighting=False, mode='maximize')[source]#
Unified reagent class for Thompson Sampling.
Handles both warmup and search phases with Bayesian updating of posterior distributions.
- Variables:
reagent_name (str) – Name/ID of the reagent
smiles (str) – SMILES string representation
mol (Mol) – RDKit molecule object
mean (float) – Current posterior mean
std (float) – Current posterior standard deviation
n_samples (int) – Number of times this reagent has been sampled
known_var (float) – Known variance (set during initialization)
initial_scores (list) – Scores collected during warmup
current_phase (str) – Either “warmup” or “search”
_compatible_smarts (Set[str]) – Set of SMARTS pattern IDs this reagent is compatible with
- add_score(score)[source]#
Add an observed score for this reagent.
During warmup, scores are collected. During search, Bayesian updating is performed on the posterior distribution.
- Parameters:
score (float) – Observed score value
- init_prior(prior_mean, prior_std)[source]#
Initialize the prior distribution from warmup statistics.
This is called after warmup to set the prior mean and std, then replays all warmup scores as Bayesian updates.
If Boltzmann weighting is enabled, uses batch Boltzmann-weighted update. Otherwise, uses sequential standard Bayesian updates.
Factories#
Factory functions for creating Thompson Sampling components from configs.
- TACTICS.thompson_sampling.factories.create_strategy(config)[source]#
Create a selection strategy from a Pydantic config.
- Parameters:
config (GreedyConfig | RouletteWheelConfig | UCBConfig | EpsilonGreedyConfig | BayesUCBConfig | TopTwoConfig) – Strategy configuration (GreedyConfig, RouletteWheelConfig, etc.)
- Returns:
Instantiated strategy object
- Return type:
Example
>>> config = RouletteWheelConfig(mode="maximize", alpha=0.1, beta=0.1) >>> strategy = create_strategy(config) >>> isinstance(strategy, RouletteWheelSelection) True
- TACTICS.thompson_sampling.factories.create_warmup(config)[source]#
Create a warmup strategy from a Pydantic config.
- Parameters:
config (EnhancedWarmupConfig | BalancedWarmupConfig) – Warmup configuration (EnhancedWarmupConfig or BalancedWarmupConfig)
- Returns:
Instantiated warmup strategy object
- Return type:
Example
>>> config = BalancedWarmupConfig(observations_per_reagent=5) >>> warmup = create_warmup(config) >>> isinstance(warmup, BalancedWarmup) True
- TACTICS.thompson_sampling.factories.create_evaluator(config)[source]#
Create an evaluator from a Pydantic config.
- Parameters:
config (LookupEvaluatorConfig | DBEvaluatorConfig | FPEvaluatorConfig | MWEvaluatorConfig | ROCSEvaluatorConfig | FredEvaluatorConfig | MLClassifierEvaluatorConfig | CustomEvaluatorConfig) – Evaluator configuration (LookupEvaluatorConfig, DBEvaluatorConfig, etc.)
- Returns:
Instantiated evaluator object
- Return type:
Example
>>> config = LookupEvaluatorConfig( ... ref_filename="scores.csv", ... ref_colname="Score" ... ) >>> evaluator = create_evaluator(config) >>> isinstance(evaluator, LookupEvaluator) True