def _add_switches(self, reactions): logger.info("Adding switches.") y_vars = list() switches = list() self._exchanges = list() for reaction in reactions: if reaction.id.startswith('DM_'): # demand reactions don't need integer switches self._exchanges.append(reaction) continue y = self.model.solver.interface.Variable('y_' + reaction.id, lb=0, ub=1, type='binary') y_vars.append(y) # The following is a complicated but efficient way to write the following constraints # switch_lb = self.model.solver.interface.Constraint(y * reaction.lower_bound - reaction.flux_expression, # name='switch_lb_' + reaction.id, ub=0) # switch_ub = self.model.solver.interface.Constraint(y * reaction.upper_bound - reaction.flux_expression, # name='switch_ub_' + reaction.id, lb=0) forward_var_term = Mul._from_args((RealNumber(-1), reaction.forward_variable)) reverse_var_term = Mul._from_args((RealNumber(-1), reaction.reverse_variable)) switch_lb_y_term = Mul._from_args((RealNumber(reaction.lower_bound), y)) switch_ub_y_term = Mul._from_args((RealNumber(reaction.upper_bound), y)) switch_lb = self.model.solver.interface.Constraint( Add._from_args((switch_lb_y_term, forward_var_term, reverse_var_term)), name='switch_lb_' + reaction.id, ub=0, sloppy=True) switch_ub = self.model.solver.interface.Constraint( Add._from_args((switch_ub_y_term, forward_var_term, reverse_var_term)), name='switch_ub_' + reaction.id, lb=0, sloppy=True) switches.extend([switch_lb, switch_ub]) self.model.solver.add(y_vars) self.model.solver.add(switches, sloppy=True) logger.info("Setting minimization of switch variables as objective.") self.model.objective = self.model.solver.interface.Objective(Add(*y_vars), direction='min') self._y_vars_ids = [var.name for var in y_vars]
def _add_reaction_dual_constraint(self, reaction, coefficient, maximization, prefix): """Add a dual constraint corresponding to the reaction's objective coefficient""" stoichiometry = {self.solver.variables["lambda_" + m.id]: c for m, c in six.iteritems(reaction.metabolites)} if maximization: constraint = self.solver.interface.Constraint( Add._from_args(tuple(c * v for v, c in six.iteritems(stoichiometry))), name="r_%s_%s" % (reaction.id, prefix), lb=coefficient) else: constraint = self._dual_solver.interface.Constraint( Add._from_args(tuple(c * v for v, c in six.iteritems(stoichiometry))), name="r_%s_%s" % (reaction.id, prefix), ub=coefficient) self.solver._add_constraint(constraint)
def _add_switches(self, reactions): logger.info("Adding switches.") y_vars = list() switches = list() self._exchanges = list() for reaction in reactions: if reaction.id.startswith('DM_'): # demand reactions don't need integer switches self._exchanges.append(reaction) continue y = self.model.solver.interface.Variable('y_' + reaction.id, lb=0, ub=1, type='binary') y_vars.append(y) # The following is a complicated but efficient way to write the following constraints # switch_lb = self.model.solver.interface.Constraint(y * reaction.lower_bound - reaction.flux_expression, # name='switch_lb_' + reaction.id, ub=0) # switch_ub = self.model.solver.interface.Constraint(y * reaction.upper_bound - reaction.flux_expression, # name='switch_ub_' + reaction.id, lb=0) forward_var_term = Mul._from_args( (RealNumber(-1), reaction.forward_variable)) reverse_var_term = Mul._from_args( (RealNumber(-1), reaction.reverse_variable)) switch_lb_y_term = Mul._from_args( (RealNumber(reaction.lower_bound), y)) switch_ub_y_term = Mul._from_args( (RealNumber(reaction.upper_bound), y)) switch_lb = self.model.solver.interface.Constraint( Add._from_args( (switch_lb_y_term, forward_var_term, reverse_var_term)), name='switch_lb_' + reaction.id, ub=0, sloppy=True) switch_ub = self.model.solver.interface.Constraint( Add._from_args( (switch_ub_y_term, forward_var_term, reverse_var_term)), name='switch_ub_' + reaction.id, lb=0, sloppy=True) switches.extend([switch_lb, switch_ub]) self.model.solver.add(y_vars) self.model.solver.add(switches, sloppy=True) logger.info("Setting minimization of switch variables as objective.") self.model.objective = self.model.solver.interface.Objective( Add(*y_vars), direction='min') self._y_vars_ids = [var.name for var in y_vars]
def remove_infeasible_cycles(model, fluxes, fix=()): """Remove thermodynamically infeasible cycles from a flux distribution. Parameters --------- model : cobra.Model The model that generated the flux distribution. fluxes : dict The flux distribution containing infeasible loops. Returns ------- dict A cycle free flux distribution. References ---------- .. [1] A. A. Desouki, F. Jarre, G. Gelius-Dietrich, and M. J. Lercher, “CycleFreeFlux: efficient removal of thermodynamically infeasible loops from flux distributions.” """ with model: # make sure the original object is restored exchange_reactions = model.boundary exchange_ids = [exchange.id for exchange in exchange_reactions] internal_reactions = [reaction for reaction in model.reactions if reaction.id not in exchange_ids] for exchange in exchange_reactions: exchange_flux = fluxes[exchange.id] exchange.bounds = (exchange_flux, exchange_flux) cycle_free_objective_list = [] for internal_reaction in internal_reactions: internal_flux = fluxes[internal_reaction.id] if internal_flux >= 0: cycle_free_objective_list.append(Mul._from_args((FloatOne, internal_reaction.forward_variable))) internal_reaction.bounds = (0, internal_flux) else: # internal_flux < 0: cycle_free_objective_list.append(Mul._from_args((FloatOne, internal_reaction.reverse_variable))) internal_reaction.bounds = (internal_flux, 0) cycle_free_objective = model.solver.interface.Objective( Add._from_args(cycle_free_objective_list), direction="min", sloppy=True ) model.objective = cycle_free_objective for reaction_id in fix: reaction_to_fix = model.reactions.get_by_id(reaction_id) reaction_to_fix.bounds = (fluxes[reaction_id], fluxes[reaction_id]) try: solution = model.optimize(raise_error=True) except OptimizationError as e: logger.warning("Couldn't remove cycles from reference flux distribution.") raise e result = solution.fluxes return result
def remove_infeasible_cycles(model, fluxes, fix=()): """Remove thermodynamically infeasible cycles from a flux distribution. Arguments --------- model : cobra.Model The model that generated the flux distribution. fluxes : dict The flux distribution containing infeasible loops. Returns ------- dict A cycle free flux distribution. References ---------- .. [1] A. A. Desouki, F. Jarre, G. Gelius-Dietrich, and M. J. Lercher, “CycleFreeFlux: efficient removal of thermodynamically infeasible loops from flux distributions.” """ with model: # make sure the original object is restored exchange_reactions = model.boundary exchange_ids = [exchange.id for exchange in exchange_reactions] internal_reactions = [reaction for reaction in model.reactions if reaction.id not in exchange_ids] for exchange in exchange_reactions: exchange_flux = fluxes[exchange.id] exchange.bounds = (exchange_flux, exchange_flux) cycle_free_objective_list = [] for internal_reaction in internal_reactions: internal_flux = fluxes[internal_reaction.id] if internal_flux >= 0: cycle_free_objective_list.append(Mul._from_args((FloatOne, internal_reaction.forward_variable))) internal_reaction.bounds = (0, internal_flux) else: # internal_flux < 0: cycle_free_objective_list.append(Mul._from_args((FloatOne, internal_reaction.reverse_variable))) internal_reaction.bounds = (internal_flux, 0) cycle_free_objective = model.solver.interface.Objective( Add._from_args(cycle_free_objective_list), direction="min", sloppy=True ) model.objective = cycle_free_objective for reaction_id in fix: reaction_to_fix = model.reactions.get_by_id(reaction_id) reaction_to_fix.bounds = (fluxes[reaction_id], fluxes[reaction_id]) try: solution = model.optimize(raise_error=True) except OptimizationError as e: logger.warning("Couldn't remove cycles from reference flux distribution.") raise e result = solution.fluxes return result
def remove_infeasible_cycles(model, fluxes, fix=()): """Remove thermodynamically infeasible cycles from a flux distribution. Arguments --------- model : SolverBasedModel The model that generated the flux distribution. fluxes : dict The flux distribution containing infeasible loops. Returns ------- dict A cycle free flux distribution. References ---------- .. [1] A. A. Desouki, F. Jarre, G. Gelius-Dietrich, and M. J. Lercher, “CycleFreeFlux: efficient removal of thermodynamically infeasible loops from flux distributions.” """ with TimeMachine() as tm: # make sure the original object is restored tm(do=int, undo=partial(setattr, model, 'objective', model.objective)) exchange_reactions = model.exchanges exchange_ids = [exchange.id for exchange in exchange_reactions] internal_reactions = [ reaction for reaction in model.reactions if reaction.id not in exchange_ids ] for exchange in exchange_reactions: exchange_flux = fluxes[exchange.id] tm(do=partial(setattr, exchange, 'lower_bound', exchange_flux), undo=partial(setattr, exchange, 'lower_bound', exchange.lower_bound)) tm(do=partial(setattr, exchange, 'upper_bound', exchange_flux), undo=partial(setattr, exchange, 'upper_bound', exchange.upper_bound)) cycle_free_objective_list = [] for internal_reaction in internal_reactions: internal_flux = fluxes[internal_reaction.id] if internal_flux >= 0: cycle_free_objective_list.append( Mul._from_args( (FloatOne, internal_reaction.forward_variable))) tm(do=partial(setattr, internal_reaction, 'lower_bound', 0), undo=partial(setattr, internal_reaction, 'lower_bound', internal_reaction.lower_bound)) tm(do=partial(setattr, internal_reaction, 'upper_bound', internal_flux), undo=partial(setattr, internal_reaction, 'upper_bound', internal_reaction.upper_bound)) else: # internal_flux < 0: cycle_free_objective_list.append( Mul._from_args( (FloatOne, internal_reaction.reverse_variable))) tm(do=partial(setattr, internal_reaction, 'lower_bound', internal_flux), undo=partial(setattr, internal_reaction, 'lower_bound', internal_reaction.lower_bound)) tm(do=partial(setattr, internal_reaction, 'upper_bound', 0), undo=partial(setattr, internal_reaction, 'upper_bound', internal_reaction.upper_bound)) cycle_free_objective = model.solver.interface.Objective( Add._from_args(cycle_free_objective_list), direction="min", sloppy=True) model.objective = cycle_free_objective for reaction_id in fix: reaction_to_fix = model.reactions.get_by_id(reaction_id) tm(do=partial(setattr, reaction_to_fix, 'lower_bound', fluxes[reaction_id]), undo=partial(setattr, reaction_to_fix, 'lower_bound', reaction_to_fix.lower_bound)) tm(do=partial(setattr, reaction_to_fix, 'upper_bound', fluxes[reaction_id]), undo=partial(setattr, reaction_to_fix, 'upper_bound', reaction_to_fix.upper_bound)) try: solution = model.solve() except SolveError as e: logger.warning( "Couldn't remove cycles from reference flux distribution.") raise e result = solution.x_dict return result
def remove_infeasible_cycles(model, fluxes, fix=()): """Remove thermodynamically infeasible cycles from a flux distribution. Arguments --------- model : SolverBasedModel The model that generated the flux distribution. fluxes : dict The flux distribution containing infeasible loops. Returns ------- dict A cycle free flux distribution. References ---------- .. [1] A. A. Desouki, F. Jarre, G. Gelius-Dietrich, and M. J. Lercher, “CycleFreeFlux: efficient removal of thermodynamically infeasible loops from flux distributions.” """ with TimeMachine() as tm: # make sure the original object is restored tm(do=int, undo=partial(setattr, model, 'objective', model.objective)) exchange_reactions = model.exchanges exchange_ids = [exchange.id for exchange in exchange_reactions] internal_reactions = [reaction for reaction in model.reactions if reaction.id not in exchange_ids] for exchange in exchange_reactions: exchange_flux = fluxes[exchange.id] tm(do=partial(setattr, exchange, 'lower_bound', exchange_flux), undo=partial(setattr, exchange, 'lower_bound', exchange.lower_bound)) tm(do=partial(setattr, exchange, 'upper_bound', exchange_flux), undo=partial(setattr, exchange, 'upper_bound', exchange.upper_bound)) cycle_free_objective_list = [] for internal_reaction in internal_reactions: internal_flux = fluxes[internal_reaction.id] if internal_flux >= 0: cycle_free_objective_list.append(Mul._from_args((FloatOne, internal_reaction.forward_variable))) tm(do=partial(setattr, internal_reaction, 'lower_bound', 0), undo=partial(setattr, internal_reaction, 'lower_bound', internal_reaction.lower_bound)) tm(do=partial(setattr, internal_reaction, 'upper_bound', internal_flux), undo=partial(setattr, internal_reaction, 'upper_bound', internal_reaction.upper_bound)) else: # internal_flux < 0: cycle_free_objective_list.append(Mul._from_args((FloatOne, internal_reaction.reverse_variable))) tm(do=partial(setattr, internal_reaction, 'lower_bound', internal_flux), undo=partial(setattr, internal_reaction, 'lower_bound', internal_reaction.lower_bound)) tm(do=partial(setattr, internal_reaction, 'upper_bound', 0), undo=partial(setattr, internal_reaction, 'upper_bound', internal_reaction.upper_bound)) cycle_free_objective = model.solver.interface.Objective( Add._from_args(cycle_free_objective_list), direction="min", sloppy=True ) model.objective = cycle_free_objective for reaction_id in fix: reaction_to_fix = model.reactions.get_by_id(reaction_id) tm(do=partial(setattr, reaction_to_fix, 'lower_bound', fluxes[reaction_id]), undo=partial(setattr, reaction_to_fix, 'lower_bound', reaction_to_fix.lower_bound)) tm(do=partial(setattr, reaction_to_fix, 'upper_bound', fluxes[reaction_id]), undo=partial(setattr, reaction_to_fix, 'upper_bound', reaction_to_fix.upper_bound)) try: solution = model.solve() except SolveError as e: logger.warning("Couldn't remove cycles from reference flux distribution.") raise e result = solution.x_dict return result