Note
Go to the end to download the full example code.
Mixed parameter types and a constraint#
Mix discrete, continuous, integer, nominal and ordinal factors under one constraint.
A catalysis group is scoping a new packed-column reaction and needs a first screening design. The chemistry involves a continuous flow rate, a discrete temperature ladder set by the heater controller, an integer number of stages, a choice of catalyst material, and a process grade tier. The whole factor palette lives in a single space, and a physical column limits the total loading, so a feasibility constraint is applied before optimisation.
Parameters#
flow_rate (0.1-10.0 mL/min, continuous, 25-level grid, rounded to 2 decimals): span the operating envelope of the pump; a tighter grid gives more resolution along this rate-controlling factor, and the rounding keeps the node values at a precision the pump can actually be set to.
temperature (20-100 degC, 5-degree steps): the heater exposes only a discrete ladder, so it is entered as an explicit list.
n_stages (1-20, integer): column length options offered by the hardware.
catalyst (‘A’, ‘B’, ‘C’, nominal): materials with no intrinsic ordering; the criterion treats them as unordered labels.
grade (‘low’, ‘med’, ‘high’, ordinal): quality tiers with a meaningful order, so distance along this axis carries information.
Constraint: flow_rate + n_stages <= 20 discards operating points the column cannot support.
What to look at#
summary(): the “Candidates” count reflects the constraint (fewer than the unconstrained Cartesian product); the design size and any automatic validation split are also reported here.quality_report(): min_distance and max_absolute_correlation percentiles against the Monte Carlo baseline show that the mixed factor space is well covered despite the categorical columns.plot('pairplot'): panels involving the nominal catalyst factor should show all three levels visited; panels between numeric factors should look evenly spread.
Mergen features used#
ParameterSpaceaccepting all five factor types simultaneously.Per-parameter resolution override via the options dictionary on the specification tuple.
add_constraint to filter the candidate pool by a feasibility predicate.
criteria='maxproqq', the default-safe choice when the space contains any nominal factor.
Estimated runtime: a few seconds.
from mergen import ParameterSpace, Sampler
# 1. Define a mixed-type parameter space.
# A per-parameter resolution override is passed as an options dict
# on the specification tuple (see 'flow_rate' below).
space = ParameterSpace({
'flow_rate': ('continuous', 0.1, 10.0, {'resolution': 25, 'round': 2}), # continuous, 25-level grid
'temperature': range(20, 101, 5), # discrete list
'n_stages': ('integer', 1, 20), # integer interval
'catalyst': ('nominal', ['A', 'B', 'C']), # unordered labels
'grade': ('ordinal', ['low', 'med', 'high']), # ordered labels
})
# 2. Feasibility constraint: only keep candidates below the diagonal
# of the flow-rate / stage-count plane.
space.add_constraint(lambda p: p['flow_rate'] + p['n_stages'] <= 20)
# 3. Run the sampler. maxproqq is the default-safe choice when the
# space contains any nominal factor.
sampler = Sampler(space)
sampler.set_design(n_samples=25)
result = sampler.run(criteria='maxproqq', seed=44)
# 4. Inspect and export.
result.summary()
result.quality_report()
result.plot('pairplot', save=True)
result.to_csv('parameter_types.csv')
[WARNING] n_samples (25) < recommended 10*n_parameters (50, Loeppky et al. 2009). Design quality may be reduced.
════════════════════════════════════════════════════════════
MERGEN — Space-filling Design
════════════════════════════════════════════════════════════
Parameters : 5
Candidates : 55,386
n_samples : 25 (prescribed_in=0, focus_in=0, optimised_slots=25)
Total design : 25
Validation : 5
Criterion : maxproqq
Algorithm(s) : sa
────────────────────────────────────────────────────────────
[MERGEN] Optimising (criterion=maxproqq, algorithm=sa)...
[SA] Restart 1/5
[SA] Tuning temperature...
[SA] Start log(score)=30.992 T=8.3007e+13 iters=2500 swappable=25 hybrid=0.50
iter 500/2500 T=1.316e+13 best log(score)=30.385
iter 1000/2500 T=2.085e+12 best log(score)=30.385
iter 1500/2500 T=3.305e+11 best log(score)=30.385
iter 2000/2500 T=5.237e+10 best log(score)=29.825
iter 2500/2500 T=8.301e+09 best log(score)=29.825
[SA] Done log(score)=29.825 (accepted=2165/2500, rate=86.6%)
[SA] Restart 1: new best log(score)=29.825
[SA] Restart 2/5
[SA] Tuning temperature...
[SA] Start log(score)=32.060 T=4.0613e+14 iters=2500 swappable=25 hybrid=0.50
iter 500/2500 T=6.437e+13 best log(score)=30.855
iter 1000/2500 T=1.020e+13 best log(score)=30.468
iter 1500/2500 T=1.617e+12 best log(score)=30.013
iter 2000/2500 T=2.563e+11 best log(score)=30.013
iter 2500/2500 T=4.061e+10 best log(score)=30.013
[SA] Done log(score)=30.013 (accepted=2188/2500, rate=87.5%)
[SA] Restart 3/5
[SA] Tuning temperature...
[SA] Start log(score)=31.836 T=4.9497e+14 iters=2500 swappable=25 hybrid=0.50
iter 500/2500 T=7.845e+13 best log(score)=30.564
iter 1000/2500 T=1.243e+13 best log(score)=30.564
iter 1500/2500 T=1.970e+12 best log(score)=30.016
iter 2000/2500 T=3.123e+11 best log(score)=30.016
iter 2500/2500 T=4.950e+10 best log(score)=29.252
[SA] Done log(score)=29.252 (accepted=2182/2500, rate=87.3%)
[SA] Restart 3: new best log(score)=29.252
[SA] Restart 4/5
[SA] Tuning temperature...
[SA] Start log(score)=30.939 T=2.8084e+14 iters=2500 swappable=25 hybrid=0.50
iter 500/2500 T=4.451e+13 best log(score)=30.361
iter 1000/2500 T=7.054e+12 best log(score)=30.227
iter 1500/2500 T=1.118e+12 best log(score)=30.227
iter 2000/2500 T=1.772e+11 best log(score)=30.155
iter 2500/2500 T=2.808e+10 best log(score)=30.155
[SA] Done log(score)=30.155 (accepted=2188/2500, rate=87.5%)
[SA] Restart 5/5
[SA] Tuning temperature...
[SA] Start log(score)=34.704 T=1.4332e+14 iters=2500 swappable=25 hybrid=0.50
iter 500/2500 T=2.271e+13 best log(score)=31.744
iter 1000/2500 T=3.600e+12 best log(score)=31.127
iter 1500/2500 T=5.706e+11 best log(score)=30.601
iter 2000/2500 T=9.043e+10 best log(score)=30.601
iter 2500/2500 T=1.433e+10 best log(score)=30.601
[SA] Done log(score)=30.601 (accepted=2148/2500, rate=85.9%)
[MERGEN] sa done -- score=5.059e+12 (elapsed 33.0s)
────────────────────────────────────────────────────────────
MERGEN — Final Design
────────────────────────────────────────────────────────────
Prescribed (in) : 0
Prescribed (out) : 0
Focus (in) : 0
Focus (out) : 0
Optimised : 25
Total design : 25
Validation : 5
════════════════════════════════════════════════════════════
────────────────────────────────────────────────────
MERGEN Design Summary
────────────────────────────────────────────────────
Optimised : 25
Total design : 25
Validation : 5
────────────────────────────────────────────────────
Parameters : 5
Candidates : 55386
Criterion : maxproqq
Seed : 44
Algorithm : sa
────────────────────────────────────────────────────
[METRICS] Computing MC baseline (300 designs)...
[METRICS] MC baseline complete (300 designs).
════════════════════════════════════════════════════════════════════════
MERGEN Design Metrics (n=25, d=5)
════════════════════════════════════════════════════════════════════════
Metric Value Baseline Better when Rank
────────────────────────────────────────────────────────────────────────
Min distance 0.0838 0.2026 higher 6th pct
Minimax distance 1.2818 1.2714 lower 41th pct
Max |correlation| 0.1917 0.3267 lower 94th pct
2D projection CD2 0.2169 0.1749 lower 6th pct
CV distances 0.2643 0.2612 lower 38th pct
Mean distance 1.1882 1.2109 higher 25th pct
────────────────────────────────────────────────────────────────────────
Criterion scores
────────────────────────────────────────────────────────────────────────
MAXPROQQ 5.0593e+12 3.7560e+14 100th pct lower
────────────────────────────────────────────────────────────────────────
Baseline: 300 MC designs from feasible space | Rank = percentile among baseline designs
════════════════════════════════════════════════════════════════════════
Saved: outputs/pairplot_2.png
Saved: outputs/parameter_types.csv (30 rows)

Total running time of the script: (0 minutes 38.864 seconds)