def test_solve_mip(self, solver_test): solver, old_solution, infeasible_model = solver_test if not hasattr(solver, "_SUPPORTS_MILP") or not solver._SUPPORTS_MILP: pytest.skip("no milp support") cobra_model = Model('MILP_implementation_test') constraint = Metabolite("constraint") constraint._bound = 2.5 x = Reaction("x") x.lower_bound = 0. x.objective_coefficient = 1. x.add_metabolites({constraint: 2.5}) y = Reaction("y") y.lower_bound = 0. y.objective_coefficient = 1. y.add_metabolites({constraint: 1.}) cobra_model.add_reactions([x, y]) float_sol = solver.solve(cobra_model) # add an integer constraint y.variable_kind = "integer" int_sol = solver.solve(cobra_model) assert abs(float_sol.f - 2.5) < 10 ** -5 assert abs(float_sol.x_dict["y"] - 2.5) < 10 ** -5 assert int_sol.status == "optimal" assert abs(int_sol.f - 2.2) < 10 ** -3 assert abs(int_sol.x_dict["y"] - 2.0) < 10 ** -3
def construct_loopless_model(cobra_model): """Construct a loopless model. This adds MILP constraints to prevent flux from proceeding in a loop, as done in http://dx.doi.org/10.1016/j.bpj.2010.12.3707 Please see the documentation for an explanation of the algorithm. This must be solved with an MILP capable solver. """ # copy the model and make it irreversible model = cobra_model.copy() convert_to_irreversible(model) max_ub = max(model.reactions.list_attr("upper_bound")) # a dict for storing S^T thermo_stoic = { "thermo_var_" + metabolite.id: {} for metabolite in model.metabolites } # Slice operator is so that we don't get newly added metabolites original_metabolites = model.metabolites[:] for reaction in model.reactions[:]: # Boundary reactions are not subjected to these constraints if len(reaction._metabolites) == 1: continue # populate the S^T dict bound_id = "thermo_bound_" + reaction.id for met, stoic in iteritems(reaction._metabolites): thermo_stoic["thermo_var_" + met.id][bound_id] = stoic # I * 1000 > v --> I * 1000 - v > 0 reaction_ind = Reaction(reaction.id + "_indicator") reaction_ind.variable_kind = "integer" reaction_ind.upper_bound = 1 reaction_ub = Metabolite(reaction.id + "_ind_ub") reaction_ub._constraint_sense = "G" reaction.add_metabolites({reaction_ub: -1}) reaction_ind.add_metabolites({reaction_ub: max_ub}) # This adds a compensating term for 0 flux reactions, so we get # S^T x - (1 - I) * 1001 < -1 which becomes # S^T x < 1000 for 0 flux reactions and # S^T x < -1 for reactions with nonzero flux. reaction_bound = Metabolite(bound_id) reaction_bound._constraint_sense = "L" reaction_bound._bound = max_ub reaction_ind.add_metabolites({reaction_bound: max_ub + 1}) model.add_reaction(reaction_ind) for metabolite in original_metabolites: metabolite_var = Reaction("thermo_var_" + metabolite.id) metabolite_var.lower_bound = -max_ub model.add_reaction(metabolite_var) metabolite_var.add_metabolites({ model.metabolites.get_by_id(k): v for k, v in iteritems(thermo_stoic[metabolite_var.id]) }) return model
def construct_loopless_model(cobra_model): """Construct a loopless model. This adds MILP constraints to prevent flux from proceeding in a loop, as done in http://dx.doi.org/10.1016/j.bpj.2010.12.3707 Please see the documentation for an explanation of the algorithm. This must be solved with an MILP capable solver. """ # copy the model and make it irreversible model = cobra_model.copy() convert_to_irreversible(model) max_ub = max(model.reactions.list_attr("upper_bound")) # a dict for storing S^T thermo_stoic = {"thermo_var_" + metabolite.id: {} for metabolite in model.metabolites} # Slice operator is so that we don't get newly added metabolites original_metabolites = model.metabolites[:] for reaction in model.reactions[:]: # Boundary reactions are not subjected to these constraints if len(reaction._metabolites) == 1: continue # populate the S^T dict bound_id = "thermo_bound_" + reaction.id for met, stoic in iteritems(reaction._metabolites): thermo_stoic["thermo_var_" + met.id][bound_id] = stoic # I * 1000 > v --> I * 1000 - v > 0 reaction_ind = Reaction(reaction.id + "_indicator") reaction_ind.variable_kind = "integer" reaction_ind.upper_bound = 1 reaction_ub = Metabolite(reaction.id + "_ind_ub") reaction_ub._constraint_sense = "G" reaction.add_metabolites({reaction_ub: -1}) reaction_ind.add_metabolites({reaction_ub: max_ub}) # This adds a compensating term for 0 flux reactions, so we get # S^T x - (1 - I) * 1001 < -1 which becomes # S^T x < 1000 for 0 flux reactions and # S^T x < -1 for reactions with nonzero flux. reaction_bound = Metabolite(bound_id) reaction_bound._constraint_sense = "L" reaction_bound._bound = max_ub reaction_ind.add_metabolites({reaction_bound: max_ub + 1}) model.add_reaction(reaction_ind) for metabolite in original_metabolites: metabolite_var = Reaction("thermo_var_" + metabolite.id) metabolite_var.lower_bound = -max_ub model.add_reaction(metabolite_var) metabolite_var.add_metabolites( {model.metabolites.get_by_id(k): v for k, v in iteritems(thermo_stoic[metabolite_var.id])}) return model