Note
Go to the end to download the full example code.
A staged, sequential campaign#
Extend, reorder and subsample a base design as an experimental campaign grows in stages.
An experimental campaign that unfolds in stages: an initial design is run, results come back, and the design is then grown and reorganised for the next batch. This example walks through Mergen’s sequential toolkit end to end, printing the row count at each step so the staging is easy to follow.
Parameters#
x1, x2 (discrete grids): two inputs on explicit grids so every design point is an exact grid node throughout the staged workflow.
What to look at#
The printed row count after each step: the base design, the extended design, the reordered design, and the small subsampled pilot. These counts are how the staging is made legible.
The two saved pairplots (base and extended): the extended design keeps the original points and fills the remaining gaps, rather than starting over.
ordered_design.csv: the final design with an added run_order column, ready as an execution list for the next batch.
Mergen features used#
mergen.sequential.extend: augment an existing design with new, space-filling points without discarding the originals.
mergen.sequential.run_order: assign an execution order that is robust to drift, so early runs already cover the space.
mergen.sequential.subsample: pick a small representative subset (a pilot) from a larger design.
mergen.sequential.k_fold_split: partition the design into folds for cross-validation.
Estimated runtime: a minute or two.
from mergen import ParameterSpace, Sampler
from mergen import sequential
# 1. Build a base design for the first batch.
space = ParameterSpace({
'x1': range(0, 101, 5),
'x2': range(0, 101, 5),
})
sampler = Sampler(space)
sampler.set_design(n_samples=15)
base = sampler.run()
print(f"base design : {len(base.best_design)} points")
# 2. Results came back; grow the design with 10 more points. extend()
# keeps the original points and adds space-filling ones around them.
extended = sequential.extend(sampler, base.best_design, n_new=10)
print(f"after extend : {len(extended.best_design)} points")
# 3. Assign a drift-robust execution order to the combined design.
ordered = sequential.run_order(sampler, extended.best_design)
print(f"ordered design : {len(ordered)} rows (run_order column added)")
# 4. Pick a small representative pilot from the full design.
pilot = sequential.subsample(sampler, extended.best_design, n_select=6)
print(f"subsampled pilot : {len(pilot)} points")
# 5. Partition the design into folds for cross-validation.
folds = sequential.k_fold_split(sampler, extended.best_design, k=3)
print(f"k-fold split : {len(folds)} folds")
# 6. Save the two coverage views and the final ordered run list.
base.plot('pairplot', save=True)
extended.plot('pairplot', save=True)
ordered.to_csv('outputs/ordered_design.csv', index=False)
[WARNING] n_samples (15) < recommended 10*n_parameters (20, Loeppky et al. 2009). Design quality may be reduced.
════════════════════════════════════════════════════════════
MERGEN — Space-filling Design
════════════════════════════════════════════════════════════
Parameters : 2
Candidates : 441
n_samples : 15 (prescribed_in=0, focus_in=0, optimised_slots=15)
Total design : 15
Validation : 3
Criterion : umaxpro
Algorithm(s) : sa
────────────────────────────────────────────────────────────
[MERGEN] Optimising (criterion=umaxpro, algorithm=sa)...
[SA] Restart 1/5
[SA] Tuning temperature...
[SA] Start log(score)=12.508 T=1.4286e+17 iters=2000 swappable=15 hybrid=0.50
iter 500/2000 T=1.429e+16 best log(score)=12.508
iter 1000/2000 T=1.429e+15 best log(score)=12.508
iter 1500/2000 T=1.429e+14 best log(score)=12.508
iter 2000/2000 T=1.429e+13 best log(score)=12.508
[SA] Done log(score)=12.508 (accepted=1831/2000, rate=91.5%)
[SA] Restart 1: new best log(score)=12.508
[SA] Restart 2/5
[SA] Tuning temperature...
[SA] Start log(score)=29.220 T=2.8571e+17 iters=2000 swappable=15 hybrid=0.50
iter 500/2000 T=2.857e+16 best log(score)=26.720
iter 1000/2000 T=2.857e+15 best log(score)=26.563
iter 1500/2000 T=2.857e+14 best log(score)=26.364
iter 2000/2000 T=2.857e+13 best log(score)=26.364
[SA] Done log(score)=26.364 (accepted=1854/2000, rate=92.7%)
[SA] Restart 3/5
[SA] Tuning temperature...
[SA] Start log(score)=28.027 T=3.8666e+12 iters=2000 swappable=15 hybrid=0.50
iter 500/2000 T=3.867e+11 best log(score)=26.225
iter 1000/2000 T=3.867e+10 best log(score)=26.225
iter 1500/2000 T=3.867e+09 best log(score)=26.225
iter 2000/2000 T=3.867e+08 best log(score)=26.225
[SA] Done log(score)=26.225 (accepted=1860/2000, rate=93.0%)
[SA] Restart 4/5
[SA] Tuning temperature...
[SA] Start log(score)=26.425 T=4.1373e+12 iters=2000 swappable=15 hybrid=0.50
iter 500/2000 T=4.137e+11 best log(score)=26.038
iter 1000/2000 T=4.137e+10 best log(score)=26.038
iter 1500/2000 T=4.137e+09 best log(score)=26.038
iter 2000/2000 T=4.137e+08 best log(score)=26.038
[SA] Done log(score)=26.038 (accepted=1858/2000, rate=92.9%)
[SA] Restart 5/5
[SA] Tuning temperature...
[SA] Start log(score)=29.183 T=1.4286e+17 iters=2000 swappable=15 hybrid=0.50
iter 500/2000 T=1.429e+16 best log(score)=26.799
iter 1000/2000 T=1.429e+15 best log(score)=26.799
iter 1500/2000 T=1.429e+14 best log(score)=26.799
iter 2000/2000 T=1.429e+13 best log(score)=26.463
[SA] Done log(score)=26.463 (accepted=1859/2000, rate=93.0%)
[MERGEN] sa done -- score=2.705e+05 (elapsed 4.4s)
────────────────────────────────────────────────────────────
MERGEN — Final Design
────────────────────────────────────────────────────────────
Prescribed (in) : 0
Prescribed (out) : 0
Focus (in) : 0
Focus (out) : 0
Optimised : 15
Total design : 15
Validation : 3
════════════════════════════════════════════════════════════
base design : 15 points
════════════════════════════════════════════════════════════
MERGEN — Space-filling Design
════════════════════════════════════════════════════════════
Parameters : 2
Candidates : 441
n_samples : 25 (prescribed_in=15, focus_in=0, optimised_slots=10)
Total design : 25
Validation : 0
Criterion : cd2
Algorithm(s) : sa
────────────────────────────────────────────────────────────
[MERGEN] Preparing anchor points...
[MERGEN] Optimising (criterion=cd2, algorithm=sa)...
[SA] Restart 1/5
[SA] Tuning temperature...
[SA] Start log(score)=-2.762 T=3.0583e-02 iters=2500 swappable=10 hybrid=0.50
iter 500/2500 T=4.847e-03 best log(score)=-3.189
iter 1000/2500 T=7.682e-04 best log(score)=-3.297
iter 1500/2500 T=1.218e-04 best log(score)=-3.309
iter 2000/2500 T=1.930e-05 best log(score)=-3.325
iter 2500/2500 T=3.058e-06 best log(score)=-3.325
[SA] Done log(score)=-3.325 (accepted=157/2500, rate=6.3%)
[SA] Restart 1: new best log(score)=-3.325
[SA] Restart 2/5
[SA] Tuning temperature...
[SA] Start log(score)=-2.902 T=3.9357e-02 iters=2500 swappable=10 hybrid=0.50
iter 500/2500 T=6.238e-03 best log(score)=-3.191
iter 1000/2500 T=9.886e-04 best log(score)=-3.279
iter 1500/2500 T=1.567e-04 best log(score)=-3.281
iter 2000/2500 T=2.483e-05 best log(score)=-3.281
iter 2500/2500 T=3.936e-06 best log(score)=-3.281
[SA] Done log(score)=-3.281 (accepted=160/2500, rate=6.4%)
[SA] Restart 3/5
[SA] Tuning temperature...
[SA] Start log(score)=-2.748 T=4.4755e-02 iters=2500 swappable=10 hybrid=0.50
iter 500/2500 T=7.093e-03 best log(score)=-3.190
iter 1000/2500 T=1.124e-03 best log(score)=-3.267
iter 1500/2500 T=1.782e-04 best log(score)=-3.281
iter 2000/2500 T=2.824e-05 best log(score)=-3.316
iter 2500/2500 T=4.475e-06 best log(score)=-3.323
[SA] Done log(score)=-3.323 (accepted=188/2500, rate=7.5%)
[SA] Restart 4/5
[SA] Tuning temperature...
[SA] Start log(score)=-2.754 T=4.5236e-02 iters=2500 swappable=10 hybrid=0.50
iter 500/2500 T=7.169e-03 best log(score)=-3.138
iter 1000/2500 T=1.136e-03 best log(score)=-3.172
iter 1500/2500 T=1.801e-04 best log(score)=-3.246
iter 2000/2500 T=2.854e-05 best log(score)=-3.262
iter 2500/2500 T=4.524e-06 best log(score)=-3.262
[SA] Done log(score)=-3.262 (accepted=226/2500, rate=9.0%)
[SA] Restart 5/5
[SA] Tuning temperature...
[SA] Start log(score)=-2.683 T=4.6123e-02 iters=2500 swappable=10 hybrid=0.50
iter 500/2500 T=7.310e-03 best log(score)=-3.216
iter 1000/2500 T=1.159e-03 best log(score)=-3.228
iter 1500/2500 T=1.836e-04 best log(score)=-3.237
iter 2000/2500 T=2.910e-05 best log(score)=-3.237
iter 2500/2500 T=4.612e-06 best log(score)=-3.237
[SA] Done log(score)=-3.237 (accepted=167/2500, rate=6.7%)
[MERGEN] sa done -- score=0.03597 (elapsed 8.0s)
────────────────────────────────────────────────────────────
MERGEN — Final Design
────────────────────────────────────────────────────────────
Prescribed (in) : 15
Prescribed (out) : 0
Focus (in) : 0
Focus (out) : 0
Optimised : 10
Total design : 25
Validation : 0
════════════════════════════════════════════════════════════
after extend : 25 points
ordered design : 25 rows (run_order column added)
subsampled pilot : 6 points
k-fold split : 3 folds
Saved: outputs/pairplot_10.png
Saved: outputs/pairplot_11.png
Total running time of the script: (0 minutes 12.985 seconds)

