from cameo import models
from cameo.strain_design.deterministic.linear_programming import OptKnock

model = models.bigg.iJO1366

"""
Explanation: Deterministic knockout prediction
cameo also contains state-of-the-art deterministic methods for knockout prediction:
Burgard, A.P., Pharkya, P., Maranas, C.D. (2003), "OptKnock: A Bilevel Programming Framework for Identifying Gene Knockout Strategies for Microbial Strain Optimization," Biotechnology and Bioengineering, 84(6), 647-657.
OptKnock uses the following bi-level formulation:
$$
\begin{matrix}
maximize & \mathit{v_{chemical}} & & (\mathbf{OptKnock}) \
\mathit{y_j} & & & \
subject~to & maximize & \mathit{v_{biomass}} & (\mathbf{Primal}) \
& \mathit{v_j} & & & & \
\end{matrix}\
\begin{bmatrix}
subject~to  & \sum_{j=1}^{M}S_{ij}v_{j} = 0,\ 
& v_{carbon_uptake} = v_{carbon~target}\ 
& v_{apt} \ge v_{apt_main}\ 
& v_{biomass} \ge v_{target_biomass}\ 
& v_{j}^{min} \cdot y_j \le v_j \le v_{j}^{max} \cdot y_j, \forall j \in \boldsymbol{M} \
\end{bmatrix}\
\begin{align}
 & y_j = {0, 1}, & & \forall j \in \boldsymbol{M} & \
 & \sum_{j \in M} (1 - y_j) \le K& & & \
\end{align}
$$
End of explanation
"""


optknock = OptKnock(model)

"""
Explanation: On initialization, OptKnock will compute essential reaction, blocked reaction (via FVA, it is optional). All of those preprocessing conditions allow OptKnock to run faster by reducing the search space (the number of variables).
Exchange reactions are also removed from the formulation.
End of explanation
"""


%time result = optknock.run(2, "EX_succ_e", max_results=2)

result

"""
Explanation: Running OptKnock requires at least two parameters:

Target - the flux to maximize - e.g. Exchange of Succinate, EX_succ_e_
Number of knockouts - K 

OptKnockout will return one solution by default, but max_results can be set to another number. It will try to find up to max_results unless the problem becomes infeasible, meaning that all solutions have been found.
End of explanation
"""


