5. Inspect#
What this block is. The results DataFrame tells you which products scored well. The posteriors and the per-cycle trajectory tell you why — which component the search decided was solved, when, and which reagents carry the signal. That is the SAR the search has learned, and it is available from the same sampler object once the search ends.
Core#
Turn on track_diagnostics before building the sampler, then ask for
three things after search():
config.track_diagnostics = True # record per-cycle component state
config.seed = 1
sampler = ThompsonSampler.from_config(config)
sampler.warm_up(num_warmup_trials=config.num_warmup_trials)
results = sampler.search(num_cycles=config.num_ts_iterations)
diagnostics = sampler.get_diagnostics() # one row per (cycle, component)
landscape = sampler.get_posterior_landscape() # one row per reagent: mean, std, n_samples
summary = sampler.get_sar_summary() # dict: per-component structure + prose
sampler.close()
print(diagnostics.columns)
print(summary["landscape_type"])
|
One row per (cycle, component): what the strategy knew and did at
that moment. Columns depend on the strategy (below); every schema
shares |
|
One row per reagent — |
|
A dict: per-component entropy, concentration, Gini, top-1/top-5
share, SNR, the dominant reagent and a convergence verdict;
|
What it produces: two Polars DataFrames and a dict. Write the frames to Parquet — everything in Build on it and in 6. Visualise runs on the saved files without a sampler.
Build on it#
Reading the trajectory#
Each recommended strategy records what drives its decisions. The columns worth watching:
- Top-Two TS (12 columns)
gmicandcriticality(the component’s GMIC),is_heated,heated_scale/cooled_scale/effective_scale(what the posterior std was multiplied by),disagreement_ema(how often the two draws disagreed — the signal the adaptive scale follows),n_active_reagents.- Roulette wheel / CATS (18 columns)
gmicwith its partssignal_var/mean_noise_var;divergenceagainstdivergence_thresholdand the resultingis_stable/cats_mode("diversity"until posteriors settle, then GMIC-driven);base_temp→cats_multiplier→final_temperature;ema_relative_gmic.- Bayes-UCB (18 columns)
criticalityfrom the z-score softmax withsnr,participation_ratio/effective_n,sharpening_factor, the observation-gatedcriticality_weightand itsdecay, and the percentile pipelinebase_temp→cats_multiplier→final_temperature.
A component whose gmic climbs and stays high early is one the search
considered solved; one that stays flat is where the budget went.
Analysis functions#
TACTICS.thompson_sampling.diagnostics is Polars in, Polars out, no
sampler needed:
from TACTICS.thompson_sampling.diagnostics import (
compute_posterior_entropy, compute_convergence_point, format_sar_report,
)
print(format_sar_report(summary))
entropy = compute_posterior_entropy(landscape, mode="minimize")
converged = compute_convergence_point(diagnostics, threshold=0.3)
print(entropy.join(converged, on="component_idx"))
diagnostics.write_parquet("diagnostics.parquet") # for post-hoc analysis and plots
landscape.write_parquet("landscape.parquet")
compute_posterior_entropy()— from the landscape: per-component entropy, concentration and SNR. Pass the samemodeas the search.compute_convergence_point()— from the diagnostics: the first cycle each component’s criticality crossedthresholdand the cycle it stayed there.compare_trajectory_vs_snapshot()— joins the two: does the trajectory add information the final snapshot does not?compute_disagreement_convergence()andcompute_scale_adaptation()— Top-Two-specific: when disagreement settled, how far the heated scale moved.format_sar_report()— the summary dict as text.
Many runs#
To compare methods or replicates, save each run’s diagnostics with a
replicate (and method) column added, concatenate, and hand the
result to the plots in 6. Visualise — they average across
replicates and draw confidence bands.
Gotchas
track_diagnosticsmust be set beforefrom_config/ construction. Setting it afterwards records nothing.The diagnostics schema is strategy-specific; code that reads
disagreement_emawill fail on an RWS run. Branch on"disagreement_ema" in df.columnsor on the strategy you ran.get_sar_summary()needs observations: with very few cycles the verdict isinsufficient_dataand the per-component numbers areNaN.compute_posterior_entropyis direction-aware — passmodeor a minimize run reads as inverted.
Reference#
Inspect — the three accessors, the six analysis functions, and the full column lists.
Search Performance Metrics for TACTICS — the metrics behind these numbers.
Next: 6. Visualise — pictures of all of this.