def test_add_constraint(self, core_model): cache = ProblemCache(core_model) def add_var(model, var_id): return model.solver.interface.Variable(var_id, ub=0) def add_constraint(m, const_id, var): return m.solver.interface.Constraint(var, lb=-10, ub=10, name=const_id) def update_constraint(model, const, var): return setattr(const, "ub", 1000) for i in range(10): cache.add_variable("%i" % i, add_var, None) cache.add_constraint("c%i" % i, add_constraint, update_constraint, cache.variables["%i" % i]) for i in range(10): assert cache.constraints["c%i" % i] in core_model.solver.constraints assert cache.constraints["c%i" % i].ub == 10 assert cache.constraints["c%i" % i].lb == -10 assert core_model.solver.constraints["c%i" % i].ub == 10 assert core_model.solver.constraints["c%i" % i].lb == -10 for i in range(10): cache.add_constraint("c%i" % i, add_constraint, update_constraint, cache.variables["%i" % i]) assert core_model.solver.constraints["c%i" % i].ub == 1000 cache.reset() for i in range(10): with pytest.raises(KeyError): core_model.solver.variables.__getitem__("%i" % i) with pytest.raises(KeyError): core_model.solver.constraints.__getitem__("c%i" % i)
def test_add_variable(self, core_model): cache = ProblemCache(core_model) def add_var(model, var_id): return model.solver.interface.Variable(var_id, ub=0) def update_var(model, var): return setattr(var, "ub", 1000) for i in range(10): cache.add_variable("%i" % i, add_var, update_var) for i in range(10): assert cache.variables["%i" % i] in core_model.solver.variables assert cache.variables["%i" % i].ub == 0 assert core_model.solver.variables["%i" % i].ub == 0 for i in range(10): cache.add_variable("%i" % i, add_var, update_var) assert cache.variables["%i" % i].ub == 1000 assert core_model.solver.variables["%i" % i].ub == 1000 cache.reset() for i in range(10): with pytest.raises(KeyError): core_model.solver.variables.__getitem__("%i" % i)
class TargetEvaluator(Evaluator): """ Evaluator for targets in a model. It gets a representation, decodes into targets and simulates the model with a given method. Attributes ---------- model : SolverBasedModel A constraint-based model decoder : SetDecoder A decoder to convert the representation into knockouts objective_function : objective_function or list(objective_function) The objectives of the algorithm simulation_method : see flux_analysis.simulation The method use to simulate the knockouts simulation_kwargs : dict The extra parameters used by the simulation method See Also -------- cameo.strain_design.heuristic.objective_function Methods ------- __call__(population) calling the object will evaluate a population (see inspyred) """ def __init__(self, model, decoder, objective_function, simulation_method, simulation_kwargs): self.model = model if not isinstance(decoder, SetDecoder): raise ValueError("Invalid decoder %s" % decoder) self.decoder = decoder if not isinstance(objective_function, ObjectiveFunction): raise ValueError( "'objective_function' must be instance of ObjectiveFunction (%s)" % objective_function) self.objective_function = objective_function self.simulation_method = simulation_method self.simulation_kwargs = simulation_kwargs self.cache = ProblemCache(model) def __call__(self, population): return [self._evaluate_individual(tuple(i)) for i in population] def reset(self): self.cache.reset() def _evaluate_individual(self, individual): raise NotImplementedError
class TargetEvaluator(Evaluator): """ Evaluator for targets in a model. It gets a representation, decodes into targets and simulates the model with a given method. Attributes ---------- model : cobra.Model A constraint-based model decoder : SetDecoder A decoder to convert the representation into knockouts objective_function : objective_function or list(objective_function) The objectives of the algorithm simulation_method : see flux_analysis.simulation The method use to simulate the knockouts simulation_kwargs : dict The extra parameters used by the simulation method See Also -------- cameo.strain_design.heuristic.objective_function Methods ------- __call__(population) calling the object will evaluate a population (see inspyred) """ def __init__(self, model, decoder, objective_function, simulation_method, simulation_kwargs): self.model = model if not isinstance(decoder, SetDecoder): raise ValueError("Invalid decoder %s" % decoder) self.decoder = decoder if not isinstance(objective_function, ObjectiveFunction): raise ValueError("'objective_function' must be instance of ObjectiveFunction (%s)" % objective_function) self.objective_function = objective_function self.simulation_method = simulation_method self.simulation_kwargs = simulation_kwargs self.cache = ProblemCache(model) def __call__(self, population): return [self.evaluate_individual(tuple(i)) for i in population] def reset(self): self.cache.reset()
def test_lmoma_with_cache(self, core_model): original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() lmoma(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("u_") for v in core_model.solver.variables) assert any(c.name.startswith("lmoma_const_") for c in core_model.solver.constraints) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("u_") for v in core_model.solver.variables) assert not any(c.name.startswith("lmoma_const_") for c in core_model.solver.constraints)
def test_cache_problem(self, problem_cache_trial): core_model, reference, n_constraints, n_variables = problem_cache_trial # After the number of variables and constraints remains the same if nothing happens assert n_constraints == len(core_model.solver.constraints) assert n_variables == len(core_model.solver.variables) cache = ProblemCache(core_model) some_method_that_adds_stuff(core_model, cache) # After running some_method_that_adds_stuff with cache, problem has 10 more variables assert n_variables + 10 == len(core_model.solver.variables) # And has 9 more more constraints assert n_constraints + 9 == len(core_model.solver.constraints) cache.reset() # After reset cache, the problem should return to its original size assert n_constraints == len(core_model.solver.constraints) assert n_variables == len(core_model.solver.variables)
def test_moma_with_cache(self, core_model): if current_solver_name(core_model) == 'glpk': pytest.skip('glpk does not support qp') original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() moma(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("moma_aux_") for v in core_model.solver.variables) assert any(c.name.startswith("moma_const_") for c in core_model.solver.constraints) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("moma_aux_") for v in core_model.solver.variables) assert not any(c.name.startswith("moma_const_") for c in core_model.solver.constraints)
def test_room_with_cache(self, core_model): original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) infeasible = 0 for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() try: room(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("y_") for v in core_model.solver.variables) assert any(c.name.startswith("room_const_") for c in core_model.solver.constraints) except OptimizationError: # TODO: room shouldn't return infeasible for non-essential reactions infeasible += 1 continue assert infeasible < len(core_model.reactions) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("y_") for v in core_model.solver.variables) assert not any(c.name.startswith("room_const_") for c in core_model.solver.constraints)
class KnockoutEvaluator(object): """ Evaluator for knockouts. It gets a representation, decodes into knockouts and simulates the model with a given method. Attributes ---------- model : SolverBasedModel A constraint-based model decoder : KnockoutDecoder A decoder to convert the representation into knockouts objective_function : objective_function or list(objective_function) The objectives of the algorithm simulation_method : see flux_analysis.simulation The method use to simulate the knockouts simulation_kwargs : dict The extra parameters used by the simulation method See Also -------- cameo.strain_design.heuristic.objective_function Methods ------- __call__(population) calling the object will evaluate a population (see inspyred) """ def __init__(self, model, decoder, objective_function, simulation_method, simulation_kwargs): self.model = model if not isinstance(decoder, KnockoutDecoder): raise ValueError("Invalid decoder %s" % decoder) self.decoder = decoder if isinstance(objective_function, list): if not len(objective_function) > 0: raise ValueError("list of objectives cannot be empty") invalid = [] for index, of in enumerate(objective_function): if not isinstance(of, ObjectiveFunction): invalid.append((index, of)) if len(invalid) > 0: raise ValueError("objectives %s must be instance of ObjectiveFunction (%s)" % (",".join(str(i[0]) for i in invalid), [i[1] for i in invalid])) elif not isinstance(objective_function, ObjectiveFunction): raise ValueError("'objective_function' must be instance of ObjectiveFunction (%s)" % objective_function) self.objective_function = objective_function self.simulation_method = simulation_method self.simulation_kwargs = simulation_kwargs self.cache = ProblemCache(model) def __call__(self, population): return [self._evaluate_individual(tuple(i)) for i in population] def reset(self): self.cache.reset() @property def is_mo(self): return isinstance(self.objective_function, list) @memoize def _evaluate_individual(self, individual): """ Evaluates a single individual. Arguments --------- individual: set The encoded representation of a single individual. Returns ------- fitness A single real value or a Pareto, depending on the number of objectives. """ decoded = self.decoder(individual) reactions = decoded[0] with TimeMachine() as tm: for reaction in reactions: reaction.knock_out(time_machine=tm) try: solution = self.simulation_method(self.model, cache=self.cache, volatile=False, raw=True, reactions=reactions2filter(self.objective_function), **self.simulation_kwargs) fitness = self._calculate_fitness(solution, decoded) except SolveError as e: logger.debug(e) if self.is_mo: fitness = inspyred.ec.emo.Pareto(values=[0 for _ in self.objective_function]) else: fitness = 0. return fitness def _calculate_fitness(self, solution, decoded): if self.is_mo: logger.debug("evaluate multiobjective solution") return inspyred.ec.emo.Pareto(values=[of(self.model, solution, decoded) for of in self.objective_function]) else: logger.debug("evaluate single objective solution") return self.objective_function(self.model, solution, decoded)
def room(model, reference=None, cache=None, delta=0.03, epsilon=0.001, reactions=None, *args, **kwargs): """Regulatory On/Off Minimization [1]. Parameters ---------- model: cobra.Model reference: FluxDistributionResult, dict delta: float epsilon: float cache: ProblemCache Returns ------- FluxDistributionResult Contains the result of the linear solver. 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 """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) elif not isinstance(cache, ProblemCache): raise TypeError("Invalid cache object (must be a cameo.util.ProblemCache)") cache.begin_transaction() if not isinstance(reference, (dict, pandas.Series, FluxDistributionResult)): raise TypeError("reference must be a flux distribution (dict or FluxDistributionResult") try: for rid, flux_value in six.iteritems(reference): reaction = model.reactions.get_by_id(rid) def create_variable(model, var_id): return model.solver.interface.Variable(var_id, type="binary") cache.add_variable("y_%s" % rid, create_variable, None) def create_upper_constraint(model, constraint_id, reaction, variable, flux_value, epsilon): w_u = flux_value + delta * abs(flux_value) + epsilon return model.solver.interface.Constraint( reaction.flux_expression - variable * (reaction.upper_bound - w_u), ub=w_u, sloppy=True, name=constraint_id) def update_upper_constraint(model, constraint, reaction, variable, flux_value, epsilon): w_u = flux_value + delta * abs(flux_value) + epsilon constraint.set_linear_coefficients({variable: reaction.upper_bound - w_u}) constraint.ub = w_u cache.add_constraint("room_const_%s_upper" % rid, create_upper_constraint, update_upper_constraint, reaction, cache.variables["y_%s" % rid], flux_value, epsilon) def create_lower_constraint(model, constraint_id, reaction, variable, flux_value, epsilon): w_l = flux_value - delta * abs(flux_value) - epsilon return model.solver.interface.Constraint( reaction.flux_expression - variable * (reaction.lower_bound - w_l), lb=w_l, sloppy=True, name=constraint_id) def update_lower_constraint(model, constraint, reaction, variable, flux_value, epsilon): w_l = flux_value - delta * abs(flux_value) - epsilon constraint.set_linear_coefficients({variable: reaction.lower_bound - w_l}) constraint.lb = w_l cache.add_constraint("room_const_%s_lower" % rid, create_lower_constraint, update_lower_constraint, reaction, cache.variables["y_%s" % rid], flux_value, epsilon) model.objective = model.solver.interface.Objective(add([mul([One, var]) for var in cache.variables.values()]), direction='min') solution = model.optimize(raise_error=True) if reactions is not None: result = FluxDistributionResult( {r: solution.get_primal_by_id(r) for r in reactions}, solution.objective_value) else: result = FluxDistributionResult.from_solution(solution) return result except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()
def lmoma(model, reference=None, cache=None, reactions=None, *args, **kwargs): """Linear Minimization Of Metabolic Adjustment [1]. Parameters ---------- model: cobra.Model reference: FluxDistributionResult, dict cache: ProblemCache reactions: list Returns ------- FluxDistributionResult Contains the result of the solver. References ---------- .. [1] Becker, S. A., Feist, A. M., Mo, M. L., Hannum, G., Palsson, B. Ø., & Herrgard, M. J. (2007). Quantitative prediction of cellular metabolism with constraint-based models: the COBRA Toolbox. Nature Protocols, 2(3), 727–38. doi:10.1038/nprot.2007.99 """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) cache.begin_transaction() if not isinstance(reference, (dict, pandas.Series, FluxDistributionResult)): raise TypeError("reference must be a flux distribution (dict or FluxDistributionResult") try: for rid, flux_value in six.iteritems(reference): reaction = model.reactions.get_by_id(rid) def create_variable(model, var_id, lb): var = model.solver.interface.Variable(var_id, lb=lb) return var pos_var_id = "u_%s_pos" % rid cache.add_variable(pos_var_id, create_variable, None, 0) neg_var_id = "u_%s_neg" % rid cache.add_variable(neg_var_id, create_variable, None, 0) # ui = vi - wt def update_upper_constraint(model, constraint, var, reaction, flux_value): if constraint.lb != flux_value: constraint.lb = flux_value def create_upper_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression + var, lb=flux_value, sloppy=True, name=constraint_id) return constraint cache.add_constraint("lmoma_const_%s_ub" % rid, create_upper_constraint, update_upper_constraint, cache.variables[pos_var_id], reaction, flux_value) def update_lower_constraint(model, constraint, var, reaction, flux_value): if constraint.ub != flux_value: constraint.ub = flux_value def create_lower_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression - var, ub=flux_value, sloppy=True, name=constraint_id) return constraint cache.add_constraint("lmoma_const_%s_lb" % rid, create_lower_constraint, update_lower_constraint, cache.variables[neg_var_id], reaction, flux_value) def create_objective(model, variables): return model.solver.interface.Objective(add([mul((One, var)) for var in variables]), direction="min", sloppy=False) cache.add_objective(create_objective, None, cache.variables.values()) solution = model.optimize(raise_error=True) if reactions is not None: result = FluxDistributionResult( {r: solution.get_primal_by_id(r) for r in reactions}, solution.objective_value) else: result = FluxDistributionResult.from_solution(solution) return result except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()
def room(model, reference=None, cache=None, delta=0.03, epsilon=0.001, reactions=None, *args, **kwargs): """Regulatory On/Off Minimization [1]. Parameters ---------- model: cobra.Model reference: FluxDistributionResult, dict delta: float epsilon: float cache: ProblemCache Returns ------- FluxDistributionResult Contains the result of the linear solver. 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 """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) elif not isinstance(cache, ProblemCache): raise TypeError("Invalid cache object (must be a cameo.util.ProblemCache)") cache.begin_transaction() if not isinstance(reference, (dict, pandas.Series, FluxDistributionResult)): raise TypeError("reference must be a flux distribution (dict or FluxDistributionResult") try: for rid, flux_value in six.iteritems(reference): reaction = model.reactions.get_by_id(rid) def create_variable(model, var_id): return model.solver.interface.Variable(var_id, type="binary") cache.add_variable("y_%s" % rid, create_variable, None) def create_upper_constraint(model, constraint_id, reaction, variable, flux_value, epsilon): w_u = flux_value + delta * abs(flux_value) + epsilon return model.solver.interface.Constraint( reaction.flux_expression - variable * (reaction.upper_bound - w_u), ub=w_u, sloppy=True, name=constraint_id) def update_upper_constraint(model, constraint, reaction, variable, flux_value, epsilon): w_u = flux_value + delta * abs(flux_value) + epsilon constraint.set_linear_coefficients({variable: reaction.upper_bound - w_u}) constraint.ub = w_u cache.add_constraint("room_const_%s_upper" % rid, create_upper_constraint, update_upper_constraint, reaction, cache.variables["y_%s" % rid], flux_value, epsilon) def create_lower_constraint(model, constraint_id, reaction, variable, flux_value, epsilon): w_l = flux_value - delta * abs(flux_value) - epsilon return model.solver.interface.Constraint( reaction.flux_expression - variable * (reaction.lower_bound - w_l), lb=w_l, sloppy=True, name=constraint_id) def update_lower_constraint(model, constraint, reaction, variable, flux_value, epsilon): w_l = flux_value - delta * abs(flux_value) - epsilon constraint.set_linear_coefficients({variable: reaction.lower_bound - w_l}) constraint.lb = w_l cache.add_constraint("room_const_%s_lower" % rid, create_lower_constraint, update_lower_constraint, reaction, cache.variables["y_%s" % rid], flux_value, epsilon) model.objective = model.solver.interface.Objective(add([mul([One, var]) for var in cache.variables.values()]), direction='min') solution = model.optimize(raise_error=True) if reactions is not None: result = FluxDistributionResult({r: solution.get_primal_by_id(r) for r in reactions}, solution.f) else: result = FluxDistributionResult.from_solution(solution) return result except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()
class KnockoutEvaluator(object): """ Evaluator for knockouts. It gets a representation, decodes into knockouts and simulates the model with a given method. Attributes ---------- model : SolverBasedModel A constraint-based model decoder : KnockoutDecoder A decoder to convert the representation into knockouts objective_function : objective_function or list(objective_function) The objectives of the algorithm simulation_method : see flux_analysis.simulation The method use to simulate the knockouts simulation_kwargs : dict The extra parameters used by the simulation method See Also -------- cameo.strain_design.heuristic.objective_function Methods ------- __call__(population) calling the object will evaluate a population (see inspyred) """ def __init__(self, model, decoder, objective_function, simulation_method, simulation_kwargs): self.model = model self.decoder = decoder self.objective_function = objective_function self.simulation_method = simulation_method self.simulation_kwargs = simulation_kwargs self.cache = ProblemCache(model) def __call__(self, population): res = [self.evaluate_individual(frozenset(i)) for i in population] self.cache.reset() return res @memoize def evaluate_individual(self, individual): decoded = self.decoder(individual) reactions = decoded[0] with TimeMachine() as tm: for reaction in reactions: reaction.knock_out(time_machine=tm) try: solution = self.simulation_method(self.model, cache=self.cache, volatile=False, raw=True, **self.simulation_kwargs) fitness = self._calculate_fitness(solution, decoded) except SolveError as e: logger.debug(e) if isinstance(self.objective_function, list): fitness = inspyred.ec.emo.Pareto( values=[0 for _ in self.objective_function]) else: fitness = 0 return fitness def _calculate_fitness(self, solution, decoded): if isinstance(self.objective_function, list): logger.debug("evaluate multi objective") return inspyred.ec.emo.Pareto(values=[ of(self.model, solution, decoded) for of in self.objective_function ]) else: logger.debug("evaluate single objective") return self.objective_function(self.model, solution, decoded)
def moma(model, reference=None, cache=None, reactions=None, *args, **kwargs): """ Minimization of Metabolic Adjustment[1] Parameters ---------- model: cobra.Model reference: FluxDistributionResult, dict cache: ProblemCache reactions: list Returns ------- FluxDistributionResult Contains the result of the solver. References ---------- .. [1] Segrè, D., Vitkup, D., & Church, G. M. (2002). Analysis of optimality in natural and perturbed metabolic networks. Proceedings of the National Academy of Sciences of the United States of America, 99(23), 15112–7. doi:10.1073/pnas.232349399 """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) cache.begin_transaction() try: for rid, flux_value in six.iteritems(reference): def create_variable(model, variable_id): var = model.solver.interface.Variable(variable_id) return var var_id = "moma_aux_%s" % rid cache.add_variable(var_id, create_variable, None) def create_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression - var, lb=flux_value, ub=flux_value, name=constraint_id) return constraint def update_constraint(model, constraint, var, reaction, flux_value): if constraint.lb != flux_value: constraint.lb = flux_value constraint.ub = flux_value constraint_id = "moma_const_%s" % rid reaction = model.reactions.get_by_id(rid) cache.add_constraint(constraint_id, create_constraint, update_constraint, cache.variables[var_id], reaction, flux_value) def create_objective(model, variables): return model.solver.interface.Objective(Add(*[FloatOne * var ** 2 for var in variables]), direction="min", sloppy=True) cache.add_objective(create_objective, None, cache.variables.values()) solution = model.optimize(raise_error=True) if reactions is not None: result = FluxDistributionResult({r: solution.get_primal_by_id(r) for r in reactions}, solution.f) else: result = FluxDistributionResult.from_solution(solution) return result except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()
class KnockoutEvaluator(object): """ Evaluator for knockouts. It gets a representation, decodes into knockouts and simulates the model with a given method. Attributes ---------- model : SolverBasedModel A constraint-based model decoder : KnockoutDecoder A decoder to convert the representation into knockouts objective_function : objective_function or list(objective_function) The objectives of the algorithm simulation_method : see flux_analysis.simulation The method use to simulate the knockouts simulation_kwargs : dict The extra parameters used by the simulation method See Also -------- cameo.strain_design.heuristic.objective_function Methods ------- __call__(population) calling the object will evaluate a population (see inspyred) """ def __init__(self, model, decoder, objective_function, simulation_method, simulation_kwargs): self.model = model self.decoder = decoder self.objective_function = objective_function self.simulation_method = simulation_method self.simulation_kwargs = simulation_kwargs self.cache = ProblemCache(model) def __call__(self, population): res = [self.evaluate_individual(frozenset(i)) for i in population] self.cache.reset() return res @memoize def evaluate_individual(self, individual): decoded = self.decoder(individual) reactions = decoded[0] with TimeMachine() as tm: for reaction in reactions: reaction.knock_out(time_machine=tm) try: solution = self.simulation_method(self.model, cache=self.cache, volatile=False, raw=True, **self.simulation_kwargs) fitness = self._calculate_fitness(solution, decoded) except SolveError as e: logger.debug(e) if isinstance(self.objective_function, list): fitness = inspyred.ec.emo.Pareto(values=[0 for _ in self.objective_function]) else: fitness = 0 return fitness def _calculate_fitness(self, solution, decoded): if isinstance(self.objective_function, list): logger.debug("evaluate multi objective") return inspyred.ec.emo.Pareto(values=[of(self.model, solution, decoded) for of in self.objective_function]) else: logger.debug("evaluate single objective") return self.objective_function(self.model, solution, decoded)
def lmoma(model, reference=None, cache=None, *args, **kwargs): """Linear Minimization Of Metabolic Adjustment. Parameters ---------- model: SolverBasedModel reference: dict objective: str or reaction or optlang.Objective An objective to be minimized/maximized for volatile: boolean cache: dict Returns ------- FluxDistributionResult Contains the result of the linear solver. """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) cache.begin_transaction() if not isinstance(reference, (dict, FluxDistributionResult)): raise TypeError("reference must be a flux distribution (dict or FluxDistributionResult") try: for rid, flux_value in six.iteritems(reference): reaction = model.reactions.get_by_id(rid) def create_variable(model, var_id, lb): var = model.solver.interface.Variable(var_id, lb=lb) return var pos_var_id = "u_%s_pos" % rid cache.add_variable(pos_var_id, create_variable, None, 0) neg_var_id = "u_%s_neg" % rid cache.add_variable(neg_var_id, create_variable, None, 0) # ui = vi - wt def update_upper_constraint(model, constraint, var, reaction, flux_value): constraint.lb = flux_value def create_upper_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression + var, lb=flux_value, sloppy=True, name=constraint_id) return constraint cache.add_constraint("c_%s_ub" % rid, create_upper_constraint, update_upper_constraint, cache.variables[pos_var_id], reaction, flux_value) def update_lower_constraint(model, constraint, var, reaction, flux_value): constraint.ub = flux_value def create_lower_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression - var, ub=flux_value, sloppy=True, name=constraint_id) return constraint cache.add_constraint("c_%s_lb" % rid, create_lower_constraint, update_lower_constraint, cache.variables[neg_var_id], reaction, flux_value) model.objective = model.solver.interface.Objective(add([mul([One, var]) for var in cache.variables.values()]), direction="min") try: return FluxDistributionResult(model.solve()) except SolveError as e: raise e except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()
def lmoma(model, reference=None, cache=None, reactions=None, *args, **kwargs): """Linear Minimization Of Metabolic Adjustment [1]. Parameters ---------- model: cobra.Model reference: FluxDistributionResult, dict cache: ProblemCache reactions: list Returns ------- FluxDistributionResult Contains the result of the solver. References ---------- .. [1] Becker, S. A., Feist, A. M., Mo, M. L., Hannum, G., Palsson, B. Ø., & Herrgard, M. J. (2007). Quantitative prediction of cellular metabolism with constraint-based models: the COBRA Toolbox. Nature Protocols, 2(3), 727–38. doi:10.1038/nprot.2007.99 """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) cache.begin_transaction() if not isinstance(reference, (dict, pandas.Series, FluxDistributionResult)): raise TypeError("reference must be a flux distribution (dict or FluxDistributionResult") try: for rid, flux_value in six.iteritems(reference): reaction = model.reactions.get_by_id(rid) def create_variable(model, var_id, lb): var = model.solver.interface.Variable(var_id, lb=lb) return var pos_var_id = "u_%s_pos" % rid cache.add_variable(pos_var_id, create_variable, None, 0) neg_var_id = "u_%s_neg" % rid cache.add_variable(neg_var_id, create_variable, None, 0) # ui = vi - wt def update_upper_constraint(model, constraint, var, reaction, flux_value): if constraint.lb != flux_value: constraint.lb = flux_value def create_upper_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression + var, lb=flux_value, sloppy=True, name=constraint_id) return constraint cache.add_constraint("lmoma_const_%s_ub" % rid, create_upper_constraint, update_upper_constraint, cache.variables[pos_var_id], reaction, flux_value) def update_lower_constraint(model, constraint, var, reaction, flux_value): if constraint.ub != flux_value: constraint.ub = flux_value def create_lower_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression - var, ub=flux_value, sloppy=True, name=constraint_id) return constraint cache.add_constraint("lmoma_const_%s_lb" % rid, create_lower_constraint, update_lower_constraint, cache.variables[neg_var_id], reaction, flux_value) def create_objective(model, variables): return model.solver.interface.Objective(add([mul((One, var)) for var in variables]), direction="min", sloppy=False) cache.add_objective(create_objective, None, cache.variables.values()) solution = model.optimize(raise_error=True) if reactions is not None: result = FluxDistributionResult({r: solution.get_primal_by_id(r) for r in reactions}, solution.f) else: result = FluxDistributionResult.from_solution(solution) return result except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()
def moma(model, reference=None, cache=None, reactions=None, *args, **kwargs): """ Minimization of Metabolic Adjustment[1] Parameters ---------- model: cobra.Model reference: FluxDistributionResult, dict cache: ProblemCache reactions: list Returns ------- FluxDistributionResult Contains the result of the solver. References ---------- .. [1] Segrè, D., Vitkup, D., & Church, G. M. (2002). Analysis of optimality in natural and perturbed metabolic networks. Proceedings of the National Academy of Sciences of the United States of America, 99(23), 15112–7. doi:10.1073/pnas.232349399 """ volatile = False if cache is None: volatile = True cache = ProblemCache(model) cache.begin_transaction() try: for rid, flux_value in six.iteritems(reference): def create_variable(model, variable_id): var = model.solver.interface.Variable(variable_id) return var var_id = "moma_aux_%s" % rid cache.add_variable(var_id, create_variable, None) def create_constraint(model, constraint_id, var, reaction, flux_value): constraint = model.solver.interface.Constraint(reaction.flux_expression - var, lb=flux_value, ub=flux_value, name=constraint_id) return constraint def update_constraint(model, constraint, var, reaction, flux_value): if constraint.lb != flux_value: constraint.lb = flux_value constraint.ub = flux_value constraint_id = "moma_const_%s" % rid reaction = model.reactions.get_by_id(rid) cache.add_constraint(constraint_id, create_constraint, update_constraint, cache.variables[var_id], reaction, flux_value) def create_objective(model, variables): return model.solver.interface.Objective(Add(*[FloatOne * var ** 2 for var in variables]), direction="min", sloppy=True) cache.add_objective(create_objective, None, cache.variables.values()) solution = model.optimize(raise_error=True) if reactions is not None: result = FluxDistributionResult( {r: solution.get_primal_by_id(r) for r in reactions}, solution.objective_value) else: result = FluxDistributionResult.from_solution(solution) return result except Exception as e: cache.rollback() raise e finally: if volatile: cache.reset()