- Biological Background
- The Bilevel Problem Structure
- From Bilevel to Single-Level via LP Duality
- The Complete MILP Formulation
- Objective Function Variants
- Greedy Baseline
- Batch Production Metric
- Implementation Overview
- Experimental Results
OptKnock is an algorithm for metabolic engineering: given a genome-scale metabolic model of a microorganism, find a small set of gene knockouts that force the cell to overproduce a desired chemical — such as ethanol or succinate — as a consequence of its own growth optimization.
The key biological insight is growth-coupling. A cell's primary goal is to maximize its own growth rate. If you eliminate competing pathways, the cell may have no viable route to regenerate the energy carriers (ATP, NADH) it needs to grow other than routing flux through the target product pathway. The target becomes a growth-coupled byproduct: it is produced automatically whenever the cell divides.
This is fundamentally different from expressing a heterologous pathway or overexpressing an enzyme. A growth-coupled strain is evolutionarily stable — any mutant that stops producing the target would also grow more slowly and be outcompeted. The engineering problem is: which genes to delete?
The E. coli core model (e_coli_core.json) used in this implementation is the canonical COBRA metabolic reconstruction of Escherichia coli's central carbon metabolism — 95 reactions and 72 metabolites. The stoichiometric matrix
OptKnock has an inherently nested structure: two levels of optimization with opposing players.
Given a fixed set of gene knockouts (some reactions disabled), the cell distributes metabolic flux to maximize its own biomass production rate. This is standard Flux Balance Analysis (FBA), a well-established LP:
where:
-
$v_j$ is the flux through reaction$j$ (units: mmol/gDW/h) -
$S \in \mathbb{R}^{m \times n}$ is the stoichiometric matrix ($S_{ij}$ = net stoichiometry of metabolite$i$ in reaction$j$ ; positive = produced, negative = consumed) -
$\ell_j,, u_j$ are the lower and upper flux bounds on reaction$j$ -
$r_j \in {0, 1}$ is the knockout indicator:$r_j = 0$ forces$v_j = 0$ (reaction silenced)
The mass balance constraint
The engineer controls which genes to delete. The objective is to find at most
The constraint "$v$ solves the inner FBA given
The fundamental insight of OptKnock is that the inner FBA is a linear program, and every LP has an equivalent dual LP. Replacing the inner optimization by its optimality conditions — using LP duality theory — collapses the bilevel problem into a single-level MILP.
Before taking the dual, all reactions are made non-negative by splitting each reversible reaction (
- Forward: $v^+j \in [0, u_j]$, stoichiometry column $+S{:,j}$
- Reverse: $v^-j \in [0, -\ell_j]$, stoichiometry column $-S{:,j}$
After splitting, every flux variable is non-negative (
The inner FBA (after splitting) has the standard primal form
| Primal constraint | Dual variable | Interpretation |
|---|---|---|
|
|
|
Shadow price of metabolite |
|
|
Reduced cost: positive when reaction |
|
|
|
Reduced cost: positive when reaction |
The dual LP is:
The KKT stationarity condition for the primal maximization states that at any optimal primal-dual pair, the gradient of the Lagrangian with respect to
This is the dual feasibility constraint. It holds as a strict equality for every reaction — both active (
For any LP, strong duality holds at the optimum: the primal and dual objectives are equal. For the inner FBA (after splitting, so
This single equality, combined with primal feasibility (
Why does this work? The Karush-Kuhn-Tucker theorem states that for a linear program, a primal-dual pair $(v^, \lambda^, \mu^{+}, \mu^{-})$ is optimal if and only if:
-
Primal feasibility:
$Sv = 0$ ,$0 \leq v \leq u \cdot r$ -
Dual feasibility:
$S^\top \lambda + \mu^+ - \mu^- = c$ ,$\mu^+, \mu^- \geq 0$ -
Complementary slackness:
$\mu^+_j (u_j r_j - v_j) = 0$ and$\mu^-_j v_j = 0$ for all$j$
Strong duality (primal obj = dual obj) is equivalent to conditions 1–3 holding simultaneously. Enforcing conditions 1 and 2 plus the strong duality equality in the outer MILP is sufficient to guarantee that any feasible
The strong duality constraint nominally reads
Since
and replace each bilinear term with four linear inequalities (assuming
The logic is exact:
- When
$r_j = 1$ : the four constraints force$p_j = \mu^+_j$ exactly. - When
$r_j = 0$ : the first constraint forces$p_j \leq 0$ , so$p_j = 0$ .
The strong duality constraint becomes the linear equality:
which, since
Complementary slackness (CS) is implied by primal/dual feasibility plus strong duality, so it is mathematically redundant. However, the LP relaxation of the MILP (obtained by relaxing the binary constraints) is much weaker without it — the branch-and-bound solver takes many more nodes to close the optimality gap. We add explicit CS constraints using additional binary indicator variables
The first pair enforces: either
Combining everything, the bilevel OptKnock reduces to the following single-level MILP over variables
Primal feasibility (inner LP):
Dual feasibility (KKT stationarity):
Optimality certificate (strong duality):
McCormick linearization of
Complementary slackness (tightens LP relaxation):
Gene-Protein-Reaction (GPR) logic (links gene presence
Knockout budget:
Viability floor (optional):
This is a Mixed-Integer Linear Program (MILP). The binary variables are
The outer objective — what the engineer is optimizing — affects both what knockout sets are found and how the MILP behaves. Two variants are implemented.
This maximizes a weighted sum of the target production rate and growth rate, with
This is derived from the batch production formula (see Section 7): maximizing the log of total batch production encourages the solver to balance target flux against growth rate rather than maximizing either to the exclusion of the other. This is a nonlinear objective that Gurobi handles via its general constraint feature (addGenConstrLog), which introduces piecewise-linear approximations internally. The log objective requires
The log objective typically takes longer to solve and has higher MILP objective values that do not directly translate to batch production — the relationship is nonlinear. This explains the large MILP error seen for the log objective in the results.
The greedy algorithm is a sequential one-at-a-time heuristic. At each step, it evaluates every candidate gene for knockout, picks the one that maximizes the batch production score (see Section 7), adds it to the knockout set, and repeats for up to
knocked_out = []
for step in 1..k:
best_gene = argmax over genes not yet knocked out of:
batch_production(q_p, μ, t) subject to min_biomass ≥ 10% WT
knocked_out.append(best_gene)
After selecting knockouts, a post-processing LP re-solves FBA under the knockout set and minimizes target flux at fixed optimal biomass — this reveals the forced-coupling floor: the minimum target production that must occur at maximum growth.
The greedy algorithm is fast (each step is just a COBRApy FBA call), but it is myopic: it cannot identify knockout combinations whose synergistic effect only appears when multiple genes are deleted simultaneously. OptKnock's MILP formulation considers all
Both methods are ultimately evaluated on a common biological objective: total product accumulated during a batch fermentation of length
Assuming exponential growth at specific growth rate
Units: mmol/gDW. This metric simultaneously rewards a high target flux and a high growth rate — the exponential amplifies the specific productivity by the total biomass produced during the fermentation. It is the standard objective used in the greedy's gene selection score.
Each reaction with
Gene-Protein-Reaction rules in the COBRA model are Boolean expressions (e.g., (b0351 and b0352) or b1702). The implementation converts each rule to Disjunctive Normal Form (DNF) using SymPy, then encodes each AND-clause as a binary auxiliary
- AND-clause:
$z_{j,c} = 1$ iff all genes in the clause are present - OR between clauses: reaction is active iff any clause is satisfied
Reactions with no GPR annotation are always active (
This shared helper builds the dual variables (
-
FBA mode (
r=None): for verification — strong duality uses$u^\top \mu^+$ directly (no McCormick) -
OptKnock mode (
rprovided): introduces McCormick variables$p, q$ and uses the linearized strong duality
After the MILP finds a knockout set, postprocess_lp verifies it with a two-step LP:
- Maximize biomass under the knockouts →
$\mu^*$ - Fix biomass at
$\mu^*$ , minimize target flux → production floor
The minimum target flux at maximum biomass is the true forced-coupling floor. This verification step catches cases where the MILP objective value does not correspond to actual forced production (particularly with the log objective).
Experiments were run on the E. coli core model sweeping:
-
Targets: ethanol (
EX_etoh_e), succinate (EX_succ_e) -
Knockout budgets
$k$ :${0, 2, 4, 7, 10}$ -
Fermentation times
$t$ :${1, 4, 8, 16}$ hours - Methods: greedy, OptKnock (linear), OptKnock (log)
- Solver: Gurobi with a 300-second time limit per solve
mean median
method objective
greedy batch 10407.647844 0.000000
optknock linear 5008.773718 37.935391
log 46589.748987 17.421627
The greedy median of zero is striking. It reflects that for many parameter combinations — particularly
The OptKnock linear objective has a non-zero median (37.9), indicating it consistently finds at least some forced production even at modest knockout budgets. The log objective's very high mean (46589) with a low median (17.4) reflects heavy skew from a few outlier cases where the nonlinear objective found unusual solutions — often not matching actual batch production (see MILP error below).
mean median
objective
linear 260.06 49.91
log 2589.87 58.38
The median improvements — 50% for linear, 58% for log — tell the more reliable story: OptKnock consistently outperforms greedy by about half again in the typical case. The extreme means (260%, 2590%) are dominated by cases where greedy produced near-zero output while OptKnock found a genuinely growth-coupled solution, causing the ratio to blow up. Dividing by a near-zero greedy value amplifies any OptKnock output enormously.
mean median
objective
linear 17.12 3.31 × 10⁻⁶
log 4451.72 4.11 × 10⁻⁸
The near-zero medians for both objectives confirm that the MILP formulation is tight: in the vast majority of cases the MILP's internal production estimate exactly matches the post-verification LP. The large means reflect a small number of outlier cases:
- For the linear objective, errors are small overall (mean 17 mmol/gDW), with isolated large deviations likely caused by the solver hitting the time limit and returning a suboptimal integer solution.
- For the log objective, the large mean error (4452 mmol/gDW) arises because the log MILP objective is not directly comparable to batch production: the solver maximizes
$\ln(v_{\text{target}}) + t v_{\text{biomass}} - \ln(v_{\text{biomass}})$ , which can be large even when the actual batch production is moderate. The post-verification LP then reveals the true forced production, which can differ substantially.
mean median
objective
linear 1.21 1.01
log 4.37 1.19
The linear objective solves in about one second at median, very fast for a MILP. The log objective takes slightly longer on average (4.4 s mean) due to the nonlinear constraint handling, but the median (1.2 s) is still near one second — a few hard instances pull the mean up. Both are well within the 300-second time limit.
The knockouts returned by OptKnock are the globally optimal set (within the budget
The greedy algorithm finds locally optimal knockouts sequentially, which is faster but can miss synergistic combinations. The MILP explores the full space of