Source code for cobra.flux_analysis.room

"""Provide regulatory on/off minimization (ROOM)."""

from typing import TYPE_CHECKING, Optional

from optlang.symbolics import Zero

from .parsimonious import pfba


if TYPE_CHECKING:
    from cobra import Model, Solution


[docs]def room( model: "Model", solution: Optional["Solution"] = None, linear: bool = False, delta: float = 0.03, epsilon: float = 1e-03, ) -> "Solution": """Compute a solution based on regulatory on/off minimization (ROOM). Compute a new flux distribution that minimizes the number of active reactions needed to accommodate a previous reference solution. Regulatory on/off minimization (ROOM) is generally used to assess the impact of knock-outs. Thus, the typical usage is to provide a wild-type flux distribution as reference and a `model` in knock-out state. Parameters ---------- model : cobra.Model The model state to compute a ROOM-based solution for. solution : cobra.Solution, optional A (wild-type) reference solution (default None). linear : bool, optional Whether to use the linear ROOM formulation or not (default False). delta: float, optional The relative tolerance range (additive) (default 0.03). epsilon: float, optional The absolute tolerance range (multiplicative) (default 0.001). Returns ------- cobra.Solution A flux distribution with minimal active reaction changes compared to the reference. See Also -------- add_room : add ROOM constraints and objective """ with model: add_room( model=model, solution=solution, linear=linear, delta=delta, epsilon=epsilon ) solution = model.optimize() return solution
[docs]def add_room( model: "Model", solution: Optional["Solution"] = None, linear: bool = False, delta: float = 0.03, epsilon: float = 1e-03, ) -> None: r""" Add constraints and objective for ROOM. This function adds variables and constraints for applying regulatory on/off minimization (ROOM) to the model. Parameters ---------- model : cobra.Model The model to add ROOM constraints and objective to. solution : cobra.Solution, optional A previous solution to use as a reference. If no solution is given, one will be computed using pFBA (default None). linear : bool, optional Whether to use the linear ROOM formulation or not (default False). delta: float, optional The relative tolerance range which is additive in nature (default 0.03). epsilon: float, optional The absolute range of tolerance which is multiplicative (default 0.001). Notes ----- The formulation used here is the same as stated in the original paper [1]_. The mathematical expression is given below: minimize: \sum_{i=1}^m y^i s.t. : Sv = 0 v_min \le v \le v_max v_j = 0 j \in A for 1 \le i \le m v_i - y_i(v_{max,i} - w_i^u) \le w_i^u (1) v_i - y_i(v_{min,i} - w_i^l) \le w_i^l (2) y_i \in {0,1} (3) w_i^u = w_i + \delta|w_i| + \epsilon w_i^l = w_i - \delta|w_i| - \epsilon So, for the linear version of the ROOM , constraint (3) is relaxed to 0 \le y_i \le 1. See Also -------- pfba : parsimonious FBA References ---------- .. [1] Tomer Shlomi, Omer Berkman and Eytan Ruppin, "Regulatory on/off minimization of metabolic flux changes after genetic perturbations", PNAS 2005 102 (21) 7695-7700; doi:10.1073/pnas.0406346102 """ if "room_old_objective" in model.solver.variables: raise ValueError("Model is already adjusted for ROOM.") # optimizes if no reference solution is provided if solution is None: solution = pfba(model) prob = model.problem variable = prob.Variable("room_old_objective", ub=solution.objective_value) constraint = prob.Constraint( model.solver.objective.expression - variable, ub=0.0, lb=0.0, name="room_old_objective_constraint", ) model.objective = prob.Objective(Zero, direction="min", sloppy=True) vars_and_cons = [variable, constraint] obj_vars = [] for rxn in model.reactions: flux = solution.fluxes[rxn.id] if linear: y = prob.Variable("y_" + rxn.id, lb=0, ub=1) delta = epsilon = 0.0 else: y = prob.Variable("y_" + rxn.id, type="binary") # upper constraint w_u = flux + (delta * abs(flux)) + epsilon upper_const = prob.Constraint( rxn.flux_expression - y * (rxn.upper_bound - w_u), ub=w_u, name="room_constraint_upper_" + rxn.id, ) # lower constraint w_l = flux - (delta * abs(flux)) - epsilon lower_const = prob.Constraint( rxn.flux_expression - y * (rxn.lower_bound - w_l), lb=w_l, name="room_constraint_lower_" + rxn.id, ) vars_and_cons.extend([y, upper_const, lower_const]) obj_vars.append(y) model.add_cons_vars(vars_and_cons) model.objective.set_linear_coefficients({v: 1.0 for v in obj_vars})