In silico optimization of multiplex PCR primers is the foundation of multiplex wormhole. The basic optimization algorithm relies on an iterative process where an initial set is designed, then at each iteration, a primer pair is randomly swapped with an alternative. If the dimer load of the multiplex improves based on this swap, the change is kept for the next iteration, otherwise the change is discarded. The process is repeated until either 1) a dimer load of 0 is achieved, 2) all alternative changes are tested and shown to provide no further improvement, or 3) the maximum number of iterations (set by the user) is reached.
multiplex_wormhole can describe “dimer load” using two distinct cost functions:
With the standard approach (deltaG=False), cost of the multiplex is calculated as the total count of dimers between primer pairs within the set. The cost table for this approach can be either the count of dimers per pairwise interaction (i.e., to minimize for total dimer load) or a binary pairwise table indicating which primer pairs interact (i.e., to minimize the number of interacting pairs). By default with this approach, multiplex wormhole minimizes total dimer load.
Alternatively, with the deltaG approach (deltaG=True), cost of the multiplex reflects the “badness” or strength of dimers within the multiplex. For each combination of primer pairs, the minimum deltaG (i.e., worst or strongest) is identified. Then, this is averaged across pairwise combinations within the multiplex. The maximum “mean deltaG” (i.e., closest to zero - reflecting weakest dimers) is then optimized for.
For simple problems, both approaches will return a final predicted dimer load of zero. However, for complex problems where dimerization is inevitable, the deltaG option allows strength of dimers to be considered rather than treating all dimers equally. This may be particularly valuable when building large multiplexes.
An initial set of primer pairs is selected by using a pseudo-greedy algorithm that considers one template at a time:
N_LOCI primer pairs is selected by choosing the “best” from the above sorted list of “best” per-template primer pairs. If a keeplist is provided, the keeplist primer pairs are included in the initial set and N_LOCI-N_KEEPLIST_PAIRS “bests” are chosen.The initial set is then used as input for a simple iterative improvement algorithm. At each iteration, the total and per-pair costs (i.e., dimer load) are calculated for the current multiplex. Then, the following steps are taken:
SIMPLE have been run.This step is where the bulk of reduction in dimer load will occur.
Simulated annealing is an optimization procedure that allows the algorithm to make “mistakes” as it proceeds. Short-term “mistakes” (i.e., changes that result in higher cost) enable the algorithm to overcome local minima in the optimization space using “hill-climbing” behavior. Simulated annealing proceeds along a schedule where riskier decisions (i.e., those resulting in increased cost) are allowed with higher probability in early iterations in order to explore the search space, and with decreasing probability as the algorithm proceeds. Simulated annealing takes the following steps:
p = e^(-_PROB_ADJ_ * delta_cost / T)
where T is the simulated annealing temperature at the current iteration, delta_cost is the new cost minus the previous cost, and PROB_ADJ is a scaling parameter set by the user (Default=2).(T_INIT-T_FINAL)*_DECAY_RATE_**(i_scaled)+T_FINAL
where T_INIT is the initial temperature, T_FINAL is the final temperature, i_scaled is the percent of iterations run (i.e., i / (ITERATIONS/100)), and _DECAY_RATE_ is the user-defined temperature decay rate (Default=0.95). See below for details on calculating T_INIT & T_FINAL for each cycle.ITERATIONS is reached.CYCLES is reached (Default=10).The default temperature schedule and acceptance probabilities are plotted on the Exploring Optimization Parameters page.
In multiplex_wormhole, an adaptive simulated annealing approach is used to set the temperature schedule, where the initial temperature is set based on the cost space of the problem at hand. The initial temperature is recalculated for each simulated annealing cycle (i.e., to account for the change in cost space from the previous cycle) using the following steps:
BURNIN iterations (default=200), and the change in cost delta_cost recorded.MEAN_DIMERS (i.e., mean delta_costs) and MAX_DIMERS (i.e., max delta_costs) are recorded.The initial temperature is calculated based on the ratio of these two values:
For deltaG=False : T_INIT = -2*log10( MEAN_DIMER / MAX_DIMER ) + 2, T_INIT<0.3 --> T_INIT=0.3
For deltaG=True : T_INIT = [-2*log10(MEAN_DIMER / MAX_DIMER) + 1] / 10, T_INIT<0.03 --> T_INIT=0.03
Values are given these lower limits to allow some hill-climbing.
T_FINAL = 0.001Here’s a plot showing the functional form of T_INIT based on common MEAN_DIMER & MAX_DIMER values:

This plot shows the following key characteristics:
Users may also choose to set a fixed temperature schedule using the T_INIT and T_FINAL arguments; these will be carried into all simulated annealing cycles. T_INIT between 2-3 (or 0.2-0.3 for deltaG=True) seems to work well for most problems.
Each multiplex wormhole run will output a dimer trace plot, with the number of iterations based on the total iterations passed (SIMPLE + ITERATIONS), which allows visualization of the contributions of each algorithm. This can also be plotted in R using the _costTrace.csv output. The trace plot can help troubleshoot simulated annealing parameterization:
T_INIT to allow higher hills to be climbed at the start of each cycle. To extend the hill-climbing period of each cycle, increase the DECAY_RATE (e.g., 0.98).T_INIT or PROB_ADJ to reduce the probability of accepting large cost increases, or reducing the DECAY_RATE (e.g., 0.90) to make the hill-climbing period of each cycle shorter.SEED argument in both the multipleOptimizations and optimizeMultiplex functions._costsTrace.csv into R and plot with (x=Iterations, y=TotalDimers, color=ASA_Temp), you can check which temperatures contributed to changes (good or bad). Example below (truncated to highlight simulated annealing portion):
plot_SA_temps script to test the effects of DECAY_RATE, T_INIT, T_FINAL, and PROB_ADJ on the probability of accepting a range of dimer values as the simulated annealing algorithm proceeds.multiple_run_optimization provides an easy wrapper for running and summarizing across multiple runs with standard inputs. Variability in results will increase with problem complexity, and more runs are recommended for very complex problems.SIMPLE high and ITERATIONS=0 to bypass simulated annealing.N_LOCI), you may consider successive optimization runs. The SEED argument in the optimizeMultiplex function is provided to allow an output from a previous run to be used as the “initial panel” for a new optimization run. This is not the same as just increasing the number of iterations because the simulated annealing temperature schedule will be recalculated for this set and simulated annealing will possibly allow local minima to be overcome.SEED and a high T_INIT (e.g., T_INIT=10). If no improvements are made at this higher T_INIT, you can be sure that you have reached a solution near the global minima (which is unlikely to be truly reached in complex problems).