def test_single_deletion(self): cobra_model = self.model initialize_growth_medium(cobra_model, 'LB') #Expected growth rates for the salmonella model with deletions in LB medium the_loci = ['STM4081', 'STM0247', 'STM3867', 'STM2952'] the_genes = tpiA, metN, atpA, eno = map(cobra_model.genes.get_by_id, the_loci) id_to_name = dict([(x.id, x.name) for x in the_genes]) growth_dict = {'fba':{tpiA.id:2.41, metN.id:2.44, atpA.id:1.87, eno.id:1.81}, 'moma':{ tpiA.id:1.62, metN.id:2.4, atpA.id:1.40, eno.id:0.33}} #MOMA requires cplex or gurobi try: get_solver_name(qp=True) except: growth_dict.pop('moma') for method, the_growth_rates in growth_dict.items(): element_list = the_growth_rates.keys() results = single_deletion(cobra_model, element_list=element_list, method=method) rates = results[0] statuses = results[1] for the_gene in element_list: self.assertEqual(statuses[the_gene], 'optimal') self.assertAlmostEqual(rates[the_gene], the_growth_rates[the_gene], places=2)
def test_single_gene_deletion_moma_benchmark(self, large_model, benchmark): try: get_solver_name(qp=True) except SolverNotFound: pytest.skip("no qp support") genes = ['b1764', 'b0463', 'b1779', 'b0417'] benchmark(single_gene_deletion, large_model, gene_list=genes, method="moma")
def test_loopless(self): try: get_solver_name(mip=True) except SolverNotFound: pytest.skip("no MILP solver found") test_model = self.construct_ll_test_model() feasible_sol = construct_loopless_model(test_model).optimize() test_model.reactions.get_by_id('v3').lower_bound = 1 infeasible_sol = construct_loopless_model(test_model).optimize() assert feasible_sol.status == "optimal" assert infeasible_sol.status == "infeasible"
def test_single_gene_deletion_moma(self): # MOMA requires a QP solver try: get_solver_name(qp=True) except: self.skipTest("no qp support") cobra_model = create_test_model("textbook") # expected knockouts for textbook model growth_dict = {"b0008": 0.87, "b0114": 0.71, "b0116": 0.56, "b2276": 0.11, "b1779": 0.00} rates, statuses = single_gene_deletion(cobra_model, gene_list=growth_dict.keys(), method="moma") for gene, expected_value in iteritems(growth_dict): self.assertEqual(statuses[gene], "optimal") self.assertAlmostEqual(rates[gene], expected_value, places=2)
def test_loopless(self): try: solver = get_solver_name(mip=True) except: self.skipTest("no MILP solver found") test_model = Model() test_model.add_metabolites(Metabolite("A")) test_model.add_metabolites(Metabolite("B")) test_model.add_metabolites(Metabolite("C")) EX_A = Reaction("EX_A") EX_A.add_metabolites({test_model.metabolites.A: 1}) DM_C = Reaction("DM_C") DM_C.add_metabolites({test_model.metabolites.C: -1}) v1 = Reaction("v1") v1.add_metabolites({test_model.metabolites.A: -1, test_model.metabolites.B: 1}) v2 = Reaction("v2") v2.add_metabolites({test_model.metabolites.B: -1, test_model.metabolites.C: 1}) v3 = Reaction("v3") v3.add_metabolites({test_model.metabolites.C: -1, test_model.metabolites.A: 1}) DM_C.objective_coefficient = 1 test_model.add_reactions([EX_A, DM_C, v1, v2, v3]) feasible_sol = construct_loopless_model(test_model).optimize() v3.lower_bound = 1 infeasible_sol = construct_loopless_model(test_model).optimize() self.assertEqual(feasible_sol.status, "optimal") self.assertEqual(infeasible_sol.status, "infeasible")
def test_single_gene_deletion_moma(self, model): try: get_solver_name(qp=True) except SolverNotFound: pytest.skip("no qp support") # expected knockouts for textbook model growth_dict = {"b0008": 0.87, "b0114": 0.71, "b0116": 0.56, "b2276": 0.11, "b1779": 0.00} rates, statuses = single_gene_deletion(model, gene_list=growth_dict.keys(), method="moma") for gene, expected_value in iteritems(growth_dict): assert statuses[gene] == 'optimal' assert abs(rates[gene] - expected_value) < 0.01
def test_single_gene_deletion(self): cobra_model = create_test_model("textbook") # expected knockouts for textbook model growth_dict = { "fba": {"b0008": 0.87, "b0114": 0.80, "b0116": 0.78, "b2276": 0.21, "b1779": 0.00}, "moma": {"b0008": 0.87, "b0114": 0.71, "b0116": 0.56, "b2276": 0.11, "b1779": 0.00}, } # MOMA requires cplex or gurobi try: get_solver_name(qp=True) except: growth_dict.pop("moma") for method, expected in growth_dict.items(): rates, statuses = single_gene_deletion(cobra_model, gene_list=expected.keys(), method=method) for gene, expected_value in iteritems(expected): self.assertEqual(statuses[gene], "optimal") self.assertAlmostEqual(rates[gene], expected_value, places=2)
def test_gapfilling(self): try: get_solver_name(mip=True) except SolverNotFound: pytest.skip("no MILP solver found") m = Model() m.add_metabolites(map(Metabolite, ["a", "b", "c"])) r = Reaction("EX_A") m.add_reaction(r) r.add_metabolites({m.metabolites.a: 1}) r = Reaction("r1") m.add_reaction(r) r.add_metabolites({m.metabolites.b: -1, m.metabolites.c: 1}) r = Reaction("DM_C") m.add_reaction(r) r.add_metabolites({m.metabolites.c: -1}) r.objective_coefficient = 1 U = Model() r = Reaction("a2b") U.add_reaction(r) r.build_reaction_from_string("a --> b", verbose=False) r = Reaction("a2d") U.add_reaction(r) r.build_reaction_from_string("a --> d", verbose=False) # GrowMatch result = gapfilling.growMatch(m, U)[0] assert len(result) == 1 assert result[0].id == "a2b" # SMILEY result = gapfilling.SMILEY(m, "b", U)[0] assert len(result) == 1 assert result[0].id == "a2b" # 2 rounds of GrowMatch with exchange reactions result = gapfilling.growMatch(m, None, ex_rxns=True, iterations=2) assert len(result) == 2 assert len(result[0]) == 1 assert len(result[1]) == 1 assert {i[0].id for i in result} == {"SMILEY_EX_b", "SMILEY_EX_c"}
def test_single_gene_deletion(self): cobra_model = self.model initialize_growth_medium(cobra_model, "LB") # Expected growth rates for the salmonella model with deletions in LB the_loci = ["STM4081", "STM0247", "STM3867", "STM2952"] the_genes = tpiA, metN, atpA, eno = map(cobra_model.genes.get_by_id, the_loci) id_to_name = dict([(x.id, x.name) for x in the_genes]) growth_dict = { "fba": {tpiA.id: 2.41, metN.id: 2.44, atpA.id: 1.87, eno.id: 1.81}, "moma": {tpiA.id: 1.62, metN.id: 2.4, atpA.id: 1.40, eno.id: 0.33}, } # MOMA requires cplex or gurobi try: get_solver_name(qp=True) except: growth_dict.pop("moma") for method, expected in growth_dict.items(): rates, statuses = single_gene_deletion(cobra_model, gene_list=expected.keys(), method=method) for gene, expected_value in iteritems(expected): self.assertEqual(statuses[gene], "optimal") self.assertAlmostEqual(rates[gene], expected_value, places=2)
def test_gapfilling(self): try: solver = get_solver_name(mip=True) except: self.skipTest("no MILP solver found") m = Model() m.add_metabolites(map(Metabolite, ["a", "b", "c"])) r = Reaction("EX_A") m.add_reaction(r) r.add_metabolites({m.metabolites.a: 1}) r = Reaction("r1") m.add_reaction(r) r.add_metabolites({m.metabolites.b: -1, m.metabolites.c: 1}) r = Reaction("DM_C") m.add_reaction(r) r.add_metabolites({m.metabolites.c: -1}) r.objective_coefficient = 1 U = Model() r = Reaction("a2b") U.add_reaction(r) r.build_reaction_from_string("a --> b", verbose=False) r = Reaction("a2d") U.add_reaction(r) r.build_reaction_from_string("a --> d", verbose=False) # GrowMatch result = gapfilling.growMatch(m, U)[0] self.assertEqual(len(result), 1) self.assertEqual(result[0].id, "a2b") # SMILEY result = gapfilling.SMILEY(m, "b", U)[0] self.assertEqual(len(result), 1) self.assertEqual(result[0].id, "a2b") # 2 rounds of GrowMatch with exchange reactions result = gapfilling.growMatch(m, None, ex_rxns=True, iterations=2) self.assertEqual(len(result), 2) self.assertEqual(len(result[0]), 1) self.assertEqual(len(result[1]), 1) self.assertEqual({i[0].id for i in result}, {"SMILEY_EX_b", "SMILEY_EX_c"})
def test_probabilistic_gapfill(self): """ Test the probabilistic gap-filling approach :return: """ # Adapted from test_gapfilling in test.cobra.flux_analysis try: solver = get_solver_name(mip=True) except: self.skipTest("no MILP solver found") # Simple Test Case 1 model1 = cobra.io.json.load_json_model(SIMPLE_1_MODEL) universe1 = cobra.io.json.load_json_model(SIMPLE_1_UNIVERSE) rxn_probs1 = probanno.ReactionProbabilities.from_json_file(SIMPLE_1_REACTION_PROBABILITIES) reactions = probanno.probabilistic_gapfill(model1, universe1, rxn_probs1) reaction_ids = [r.id for r in reactions[0]] self.assertTrue('a2b' not in reaction_ids) self.assertTrue('a2d' in reaction_ids) self.assertTrue('d2b' in reaction_ids) # Simple Test Case 1b rxn_probs1b = probanno.ReactionProbabilities.from_json_file(SIMPLE_1B_REACTION_PROBABILITIES) reactions = probanno.probabilistic_gapfill(model1, universe1, rxn_probs1b) reaction_ids = [r.id for r in reactions[0]] self.assertTrue('a2b' in reaction_ids) self.assertTrue('a2d' not in reaction_ids) self.assertTrue('d2b' not in reaction_ids) # Simple Test Case 2 model1 = cobra.io.json.load_json_model(SIMPLE_2_MODEL) universe1 = cobra.io.json.load_json_model(SIMPLE_2_UNIVERSE) rxn_probs2 = probanno.ReactionProbabilities.from_json_file(SIMPLE_2_REACTION_PROBABILITIES) reactions = probanno.probabilistic_gapfill(model1, universe1, rxn_probs2) reaction_ids = [r.id for r in reactions[0]] self.assertTrue('a2e' in reaction_ids) self.assertTrue('e2f' in reaction_ids) self.assertTrue('f2d' in reaction_ids) self.assertTrue('e2b' not in reaction_ids) self.assertTrue('a2b' not in reaction_ids) self.assertTrue('c2f' not in reaction_ids) self.assertTrue('c2d' not in reaction_ids) self.assertTrue('e2c' not in reaction_ids)
def generate_fva_warmup(self, solver=None, **solver_args): """Generates the warmup points for the sampler. Generates warmup points by setting each flux as the sole objective and minimizing/maximizing it. Parameters ---------- solver : str or cobra solver interface, optional The solver used for the arising LP problems. **solver_args Additional arguments passed to the solver. """ solver = solver_dict[get_solver_name() if solver is None else solver] lp = solver.create_problem(self.model) for i, r in enumerate(self.model.reactions): solver.change_variable_objective(lp, i, 0.0) self.n_warmup = 0 self.warmup = np.zeros((2 * len(self.model.reactions), len(self.model.reactions))) for sense in ("minimize", "maximize"): for i, r in enumerate(self.model.reactions): # Omit fixed reactions if self.fixed[i]: pass solver.change_variable_objective(lp, i, 1.0) solver.solve_problem(lp, objective_sense=sense, **solver_args) sol = solver.format_solution(lp, self.model).x if not sol: pass # some solvers do not enforce bounds too much -> we reconstrain sol = np.maximum(sol, self.bounds[0, ]) sol = np.minimum(sol, self.bounds[1, ]) self.warmup[self.n_warmup, ] = sol self.n_warmup += 1 # revert objective solver.change_variable_objective(lp, i, 0.) # Shrink warmup points to measure self.warmup = self.warmup[0:self.n_warmup, ]
def single_del(cobraModel, gene_id): rxn = cobraModel.reactions.get_by_id("biomass_Mtb_9_60atp") print("before Knock-Out: %4d < flux_rxn < %4d" % (rxn.lower_bound, rxn.upper_bound)) print('before Knock-Out, the objective value is ', cobraModel.optimize()) """ Deleting gene""" cobra.manipulation.delete_model_genes(cobraModel, [gene_id], cumulative_deletions=True) print("after Knock-Out: %4d < flux_rxn < %4d" % (rxn.lower_bound, rxn.upper_bound)) solver = solver_dict[get_solver_name()] lp = solver.create_problem(cobraModel) solver.solve_problem(lp) print('after Knock-Out, the objective value is ', solver.get_objective_value(lp)) """ Undeleting gene """ cobra.manipulation.undelete_model_genes(cobraModel)
def test_single_deletion(self): cobra_model = self.model initialize_growth_medium(cobra_model, 'LB') #Expected growth rates for the salmonella model with deletions in LB medium the_loci = ['STM4081', 'STM0247', 'STM3867', 'STM2952'] the_genes = tpiA, metN, atpA, eno = map(cobra_model.genes.get_by_id, the_loci) id_to_name = dict([(x.id, x.name) for x in the_genes]) growth_dict = { 'fba': { tpiA.id: 2.41, metN.id: 2.44, atpA.id: 1.87, eno.id: 1.81 }, 'moma': { tpiA.id: 1.62, metN.id: 2.4, atpA.id: 1.40, eno.id: 0.33 } } #MOMA requires cplex or gurobi if get_solver_name(qp=True) is None: growth_dict.pop('moma') for method, the_growth_rates in growth_dict.items(): element_list = the_growth_rates.keys() results = single_deletion(cobra_model, element_list=element_list, method=method) rates = results[0] statuses = results[1] for the_gene in element_list: self.assertEqual(statuses[the_gene], 'optimal') self.assertAlmostEqual(rates[the_gene], the_growth_rates[the_gene], places=2)
def setup_solver(cobra_model, vmax=1.0e16, solver="cglpk", **optimize_kwargs): """Setup an LP solver instance for pFBA that can be recycled. Does the initial setup for the pFBA model. Thus, each reaction is set as part of the objective and the bounds are set to [0, Inf] where Inf is not really infinite (cobrapy does not allow that) but large. Args: cobra_model: A cobra model (class Model) to be set up. Must be irreversible. vmax: A float setting the upper bound for reactions. If you want an unconstrained model this should be very large. solver: The name of the solver to use. optimize_kwargs: Optional solver key word arguments. Returns: A tuple (solver, lp, oid) where solver is the set up solver instance, lp the set up LP problem and oid the index of the original objective reaction. Raises: ValueError: There was more than one objective reaction. """ obj_ids = [] solver = solver_dict[get_solver_name() if solver is None else solver] lp = solver.create_problem(cobra_model, **optimize_kwargs) for i, r in enumerate(cobra_model.reactions): solver.change_variable_objective(lp, i, 1.0) solver.change_variable_bounds(lp, i, 0.0, vmax) if r.objective_coefficient != 0: obj_ids.append(i) if len(obj_ids) != 1: raise ValueError("Need exactly one objective reaction!") return solver, lp, obj_ids[0]
def single_del_all(cobraModel, gene_id, essential_gene, genes_done): rxn = cobraModel.reactions.get_by_id("biomass_Mtb_9_60atp") cmo = cobraModel.solution.f print(cmo) """ Deleting gene""" cobra.manipulation.delete_model_genes(cobraModel, [gene_id], cumulative_deletions=True) rlow = rxn.lower_bound rup = rxn.upper_bound solver = solver_dict[get_solver_name()] lp = solver.create_problem(cobraModel) solver.solve_problem(lp) sgov = solver.get_objective_value(lp) print(sgov) """ Undeleting gene """ cobra.manipulation.undelete_model_genes(cobraModel) compare = 0.001 * cmo if (sgov < (compare)): print(sgov) print('gene deleted is: ', gene_id) print("before Knock-Out: %4d < flux_rxn < %4d" % (rxn.lower_bound, rxn.upper_bound)) print('before Knock-Out, the objective value is ', cmo) print("after Knock-Out: %4d < flux_rxn < %4d" % (rlow, rup)) print('after Knock-Out, the objective value is ', sgov) essential_gene.append(gene_id) genes_done.append(gene_id) print('No. of essential genes are', len(essential_gene), ' out of ', len(genes_done)) return genes_done
# Output: # <2x2 sparse matrix of type '<type 'numpy.float64'>' # with 2 stored elements in Dictionary Of Keys format> # In this case, the quadratic objective is simply the identity matrix Q.todense() # Output: # matrix([[ 1., 0.], # [ 0., 1.]]) # We need to use a solver that supports quadratic programming, such as gurobi # or cplex. If a solver which supports quadratic programming is installed, this # function will return its name. print(solvers.get_solver_name(qp=True)) # Prints: # gurobi c = Metabolite("c") c._bound = 2 x = Reaction("x") y = Reaction("y") x.add_metabolites({c: 1}) y.add_metabolites({c: 1}) m = Model() m.add_reactions([x, y]) sol = m.optimize(quadratic_component=Q, objective_sense="minimize") sol.x_dict # Output: # {'x': 1.0, 'y': 1.0}
def moma(wt_model, mutant_model, objective_sense='maximize', solver=None, tolerance_optimality=1e-8, tolerance_feasibility=1e-8, minimize_norm=True, norm_flux_dict=None, the_problem='return', lp_method=0, combined_model=None, norm_type='euclidean'): """Runs the minimization of metabolic adjustment method described in Segre et al 2002 PNAS 99(23): 15112-7. wt_model: A cobra.Model object mutant_model: A cobra.Model object with different reaction bounds vs wt_model. objective_sense: 'maximize' or 'minimize' solver: 'gurobi', 'cplex', or 'glpk'. Note: glpk cannot be used with norm_type 'euclidean' tolerance_optimality: Solver tolerance for optimality. tolerance_feasibility: Solver tolerance for feasibility. the_problem: None or a problem object for the specific solver that can be used to hot start the next solution. lp_method: The method to use for solving the problem. Depends on the solver. See the cobra.flux_analysis.solvers.py file for more info. For norm_type == 'euclidean': the primal simplex works best for the test model (gurobi: lp_method=0, cplex: lp_method=1) combined_model: an output from moma that represents the combined optimization to be solved. """ if solver is None: if norm_type == "euclidean": solver = get_solver_name(qp=True) else: solver = get_solver_name() # linear is not even implemented yet if combined_model is not None or the_problem not in ['return']: warn("moma currently does not support reusing models or problems. " +\ "continuing without them") combined_model = None the_problem = 'return' if solver.lower() == 'cplex' and lp_method == 0: #print 'for moma, solver method 0 is very slow for cplex. changing to method 1' lp_method = 1 if solver.lower() == 'glpk' and norm_type == 'euclidean': try: # from gurobipy import Model solver = 'gurobi' warn("GLPK can't solve quadratic problems like MOMA. Switched solver to %s"%solver) except: warn("GLPK can't solve quadratic problems like MOMA. Switching to linear MOMA") if norm_type == 'euclidean': #Reusing the basis can get the solver stuck. reuse_basis = False if combined_model and combined_model.norm_type != norm_type: print('Cannot use combined_model.norm_type = %s with user-specified norm type'%(combined_model.norm_type, norm_type)) print('Defaulting to user-specified norm_type') combined_model = None if norm_type == 'linear': raise Exception('linear MOMA is not currently implmented') quadratic_component = None if minimize_norm: if norm_flux_dict is None: optimize_minimum_flux(wt_model, objective_sense='maximize', tolerance_feasibility=tolerance_feasibility) norm_flux_dict = wt_model.solution.x_dict else: # update the solution of wt model according to norm_flux_dict wt_model.optimize() # this is just to make sure wt_model.solution and mutant_model.solution refer to different object. objective_reaction_coefficient_dict = dict([(x.id, x.objective_coefficient) for x in wt_model.reactions if x.objective_coefficient]) try: wt_model.solution.f = sum([norm_flux_dict[k] * v for k, v in objective_reaction_coefficient_dict.items()]) wt_model.solution.x_dict = norm_flux_dict except: print('incorrect norm_flux_dict') raise # formulate qMOMA using wt_flux as reference # make a copy not to change the objective coefficients of original mutant model mutant_model_moma = mutant_model.copy() nRxns = len(mutant_model_moma.reactions) quadratic_component = 2 * eye(nRxns, nRxns) # linear component [setattr(x, 'objective_coefficient', -2 * norm_flux_dict[x.id]) for x in mutant_model_moma.reactions] the_problem = mutant_model_moma.optimize(objective_sense='minimize', quadratic_component=quadratic_component, solver=solver, tolerance_optimality=tolerance_optimality, tolerance_feasibility=tolerance_feasibility, lp_method=lp_method) #, reuse_basis=reuse_basis) # this should be commented out when solver is 'cplex' if mutant_model_moma.solution.status != 'optimal': warn('optimal moma solution not found: solver status %s'%mutant_model_moma.solution.status +\ ' returning the problem, the_combined model, and the quadratic component for trouble shooting') return(the_problem, mutant_model_moma, quadratic_component) solution = mutant_model_moma.solution mutant_dict = {} mutant_f = sum([mutant_model.reactions.get_by_id(x.id).objective_coefficient * x.x for x in mutant_model_moma.reactions]) mutant_dict['objective_value'] = mutant_f mutant_dict['status'] = solution.status #TODO: Deal with maximize / minimize issues for a reversible model that's been converted to irreversible mutant_dict['flux_difference'] = flux_difference = sum([(norm_flux_dict[r.id] - mutant_model_moma.solution.x_dict[r.id])**2 for r in mutant_model_moma.reactions]) mutant_dict['the_problem'] = the_problem mutant_dict['mutant_model'] = mutant_model_moma # update the solution of original mutant model mutant_model.solution.x_dict = the_problem.x_dict mutant_model.solution.status = solution.status mutant_model.solution.f = mutant_f # del wt_model, mutant_model, quadratic_component, solution return(mutant_dict) else: #Construct a problem that attempts to maximize the objective in the WT model while #solving the quadratic problem. This new problem is constructed to try to find #a solution for the WT model that lies close to the mutant model. There are #often multiple equivalent solutions with M matrices and the one returned #by a simple cobra_model.optimize call may be too far from the mutant. #This only needs to be adjusted if we update mutant_model._S after deleting reactions number_of_reactions_in_common = len(set([x.id for x in wt_model.reactions]).intersection([x.id for x in mutant_model.reactions])) number_of_reactions = len(wt_model.reactions) + len(mutant_model.reactions) #Get the optimal wt objective value and adjust based on optimality tolerances wt_model.optimize(solver=solver) wt_optimal = deepcopy(wt_model.solution.f) if objective_sense == 'maximize': wt_optimal = floor(wt_optimal/tolerance_optimality)*tolerance_optimality else: wt_optimal = ceil(wt_optimal/tolerance_optimality)*tolerance_optimality if not combined_model: #Collect the set of wt reactions contributing to the objective. objective_reaction_coefficient_dict = dict([(x.id, x.objective_coefficient) for x in wt_model.reactions if x.objective_coefficient]) combined_model = construct_difference_model(wt_model, mutant_model, norm_type) #Add in the virtual objective metabolite to constrain the wt_model to the space where #the objective was maximal objective_metabolite = Metabolite('wt_optimal') objective_metabolite._bound = wt_optimal if objective_sense == 'maximize': objective_metabolite._constraint_sense = 'G' else: objective_metabolite._constraint_sense = 'L' #TODO: this couples the wt_model objective reaction to the virtual metabolite #Currently, assumes a single objective reaction; however, this may be extended [combined_model.reactions.get_by_id(k).add_metabolites({objective_metabolite: v}) for k, v in objective_reaction_coefficient_dict.items()] if norm_type == 'euclidean': #Makes assumptions about the structure of combined model quadratic_component = s_vstack((lil_matrix((number_of_reactions, number_of_reactions + number_of_reactions_in_common )), s_hstack((lil_matrix((number_of_reactions_in_common, number_of_reactions)), eye(number_of_reactions_in_common,number_of_reactions_in_common))))) elif norm_type == 'linear': quadratic_component = None combined_model.norm_type = norm_type cobra_model = combined_model the_problem = combined_model.optimize(objective_sense='minimize', quadratic_component=quadratic_component, solver=solver, tolerance_optimality=tolerance_optimality, tolerance_feasibility=tolerance_feasibility, lp_method=lp_method) #, reuse_basis=reuse_basis) # this should be commented out when solver is 'cplex' if combined_model.solution.status != 'optimal': warn('optimal moma solution not found: solver status %s'%combined_model.solution.status +\ ' returning the problem, the_combined model, and the quadratic component for trouble shooting') return(the_problem, combined_model, quadratic_component) solution = combined_model.solution mutant_dict = {} #Might be faster to quey based on mutant_model.reactions with the 'mutant_' prefix added _reaction_list = [x for x in combined_model.reactions if x.id.startswith('mutant_')] mutant_f = sum([mutant_model.reactions.get_by_id(x.id[len('mutant_'):]).objective_coefficient * x.x for x in _reaction_list]) mutant_dict['objective_value'] = mutant_f wild_type_flux_total = sum([abs(solution.x_dict[x.id]) for x in wt_model.reactions]) mutant_flux_total = sum(abs(x.x) for x in _reaction_list) #Need to use the new solution as there are multiple ways to achieve an optimal solution in #simulations with M matrices. mutant_dict['status'] = solution.status #TODO: Deal with maximize / minimize issues for a reversible model that's been converted to irreversible mutant_dict['flux_difference'] = flux_difference = sum([(solution.x_dict[x.id[len('mutant_'):]] - x.x)**2 for x in _reaction_list]) mutant_dict['the_problem'] = the_problem mutant_dict['combined_model'] = combined_model del wt_model, mutant_model, quadratic_component, solution return(mutant_dict)
DM_C.objective_coefficient = 1 test_model.add_reactions([EX_A, DM_C, v1, v2, v3]) # While this model contains a loop, a flux state exists which has no flux # through reaction v3, and is identified by loopless FBA. construct_loopless_model(test_model).optimize() # Output: # <Solution 1000.00 at 0x62cd250> # However, if flux is forced through v3, then there is no longer a feasible # loopless solution. v3.lower_bound = 1 construct_loopless_model(test_model).optimize() # Output: # <Solution 'infeasible' at 0x62cd5d0> # Loopless FBA is also possible on genome scale models, but it requires a # capable MILP solver. salmonella = cobra.test.create_test_model() construct_loopless_model(salmonella).optimize(solver=get_solver_name(mip=True)) # Output: # <Solution 0.38 at 0x9e67650> ecoli = cobra.test.create_test_model("ecoli") construct_loopless_model(ecoli).optimize(solver=get_solver_name(mip=True)) # Output: # <Solution 0.98 at 0x8e463d0>
import pytest from cobra.design import * from cobra.design.design_algorithms import _add_decision_variable from cobra.solvers import get_solver_name from .conftest import model try: solver = get_solver_name(mip=True) except ImportError: no_mip_solver = True else: no_mip_solver = False class TestDesignAlgorithms: """Test functions in cobra.design""" def test_dual(self, model): assert abs(model.optimize("maximize").f - 0.874) < 0.001 dual = dual_problem(model) assert abs(dual.optimize("minimize").f - 0.874) < 0.001 def test_dual_integer_vars_as_lp(self, model): var = _add_decision_variable(model, "AKGDH") assert abs(model.optimize("maximize").f - 0.874) < 0.001 # as lp: make integer continuous, set to 1 dual = dual_problem(model, "maximize", [var.id], copy=True) r = dual.reactions.get_by_id(var.id) r.variable_kind = "continuous" r.lower_bound = r.upper_bound = 1 assert abs(dual.optimize("minimize").f - 0.874) < 0.001
test_model.add_reactions([EX_A, DM_C, v1, v2, v3]) # While this model contains a loop, a flux state exists which has no flux # through reaction v3, and is identified by loopless FBA. construct_loopless_model(test_model).optimize() # Output: # <Solution 1000.00 at 0x62cd250> # However, if flux is forced through v3, then there is no longer a feasible # loopless solution. v3.lower_bound = 1 construct_loopless_model(test_model).optimize() # Output: # <Solution 'infeasible' at 0x62cd5d0> # Loopless FBA is also possible on genome scale models, but it requires a # capable MILP solver. salmonella = cobra.test.create_test_model() construct_loopless_model(salmonella).optimize(solver=get_solver_name(mip=True)) # Output: # <Solution 0.38 at 0x9e67650> ecoli = cobra.test.create_test_model("ecoli") construct_loopless_model(ecoli).optimize(solver=get_solver_name(mip=True)) # Output: # <Solution 0.98 at 0x8e463d0>
def fast_consistency_check(model,the_reactions=None, epsilon=1e-4, zero_tolerance=1e-7, debug=False): solver = solver_dict[get_solver_name()] if the_reactions is None: the_reactions = model.reactions if hasattr(the_reactions[0], 'id'): the_reactions = [r.id for r in the_reactions] the_reactions = set(the_reactions) irrev_reactions = {r for r in the_reactions if model.reactions.get_by_id(r).lower_bound >= 0} solution_dict = LP7(model,list(irrev_reactions),epsilon=epsilon) consistent = {r for r,v in solution_dict.items() if abs(v) > zero_tolerance } inconsistent_irrev = irrev_reactions - consistent the_reactions = the_reactions - consistent J = the_reactions - irrev_reactions flipped = False singleton = False FVA_Flag = False while len(J) > 0 and not FVA_Flag: if singleton: blocked = find_blocked_reactions(model,reaction_list=map(model.reactions.get_by_id,J)) consistent = consistent.union(J - set(blocked)) FVA_Flag = True else: Ji = J solution_dict = LP7(model,list(Ji),epsilon=epsilon) consistent = consistent.union({r for r,v in solution_dict.items() if abs(v) > zero_tolerance and not r.startswith('dummy')}) if len(J.intersection(consistent)) > 0: J -= consistent flipped = False else: if flipped or len(Ji) == 0: flipped = False if singleton: J -= Ji if debug: print "Inconsistent reversible reactions detected:",len(Ji) else: singleton = True else: for r in Ji: reaction = model.reactions.get_by_id(r) reaction_dict = dict([(k, -2*v) for k, v in reaction._metabolites.items()]) reaction.add_metabolites(reaction_dict) lb = reaction.lower_bound reaction.lower_bound = -reaction.upper_bound reaction.upper_bound = -lb flipped = True return list(consistent)
import pytest from cobra.design import * from cobra.design.design_algorithms import _add_decision_variable from cobra.solvers import get_solver_name from .conftest import model try: solver = get_solver_name(mip=True) except ImportError: no_mip_solver = True else: no_mip_solver = False class TestDesignAlgorithms: """Test functions in cobra.design""" def test_dual(self, model): assert abs(model.optimize("maximize").f - 0.874) < 0.001 dual = dual_problem(model) assert abs(dual.optimize("minimize").f - 0.874) < 0.001 def test_dual_integer_vars_as_lp(self, model): var = _add_decision_variable(model, "AKGDH") assert abs(model.optimize("maximize").f - 0.874) < 0.001 # as lp: make integer continuous, set to 1 dual = dual_problem(model, "maximize", [var.id], copy=True) r = dual.reactions.get_by_id(var.id) r.variable_kind = "continuous" r.lower_bound = r.upper_bound = 1
def calculate_phenotype_phase_plane(model, reaction1_name, reaction2_name, reaction1_range_max=20, reaction2_range_max=20, reaction1_npoints=50, reaction2_npoints=50, solver=None, n_processes=1, tolerance=1e-6): """calculates the growth rates while varying the uptake rates for two reactions. :returns: a `phenotypePhasePlaneData` object containing the growth rates for the uptake rates. To plot the result, call the plot function of the returned object. :Example: >>> import cobra.test >>> model = cobra.test.create_test_model("textbook") >>> ppp = calculate_phenotype_phase_plane(model, "EX_glc__D_e", "EX_o2_e") >>> ppp.plot() """ warn( 'calculate_phenotype_phase_plane is deprecated, consider using ' 'production_envelope instead', DeprecationWarning) if solver is None: solver = get_solver_name() data = phenotypePhasePlaneData(str(reaction1_name), str(reaction2_name), reaction1_range_max, reaction2_range_max, reaction1_npoints, reaction2_npoints) # find the objects for the reactions and metabolites index1 = model.reactions.index(data.reaction1_name) index2 = model.reactions.index(data.reaction2_name) metabolite1_name = list(model.reactions[index1]._metabolites)[0].id metabolite2_name = list(model.reactions[index2]._metabolites)[0].id if n_processes > reaction1_npoints: # limit the number of processes n_processes = reaction1_npoints range_add = reaction1_npoints // n_processes # prepare the list of arguments for each _calculate_subset call arguments_list = [] i = arange(reaction1_npoints) j = arange(reaction2_npoints) for n in range(n_processes): start = n * range_add if n != n_processes - 1: r1_range = data.reaction1_fluxes[start:start + range_add] i_list = i[start:start + range_add] else: r1_range = data.reaction1_fluxes[start:] i_list = i[start:] arguments_list.append({ "model": model, "index1": index1, "index2": index2, "metabolite1_name": metabolite1_name, "metabolite2_name": metabolite2_name, "reaction1_fluxes": r1_range, "reaction2_fluxes": data.reaction2_fluxes.copy(), "i_list": i_list, "j_list": j.copy(), "tolerance": tolerance, "solver": solver }) if n_processes > 1: p = Pool(n_processes) results = list(p.map(_calculate_subset, arguments_list)) else: results = [_calculate_subset(arguments_list[0])] for result_list in results: for result in result_list: i = result[0] j = result[1] data.growth_rates[i, j] = result[2] data.shadow_prices1[i, j] = result[3] data.shadow_prices2[i, j] = result[4] data.segment() return data
def double_reaction_deletion(cobra_model, reaction_list1=None, reaction_list2=None, method="fba", return_frame=False, solver=None, zero_cutoff=1e-12, **kwargs): """sequentially knocks out pairs of reactions in a model cobra_model : :class:`~cobra.core.Model.Model` cobra model in which to perform deletions reaction_list1 : [:class:`~cobra.core.Reaction.Reaction`:] (or their id's) Reactions to be deleted. These will be the rows in the result. If not provided, all reactions will be used. reaction_list2 : [:class:`~cobra.core.Reaction`:] (or their id's) Reactions to be deleted. These will be the rows in the result. If not provided, reaction_list1 will be used. method: "fba" or "moma" Procedure used to predict the growth rate solver: str for solver name This must be a QP-capable solver for MOMA. If left unspecified, a suitable solver will be automatically chosen. zero_cutoff: float When checking to see if a value is 0, this threshold is used. return_frame: bool If true, formats the results as a pandas.Dataframe. Otherwise returns a dict of the form: {"x": row_labels, "y": column_labels", "data": 2D matrix} """ # handle arguments which need to be passed on if solver is None: solver = get_solver_name(qp=(method == "moma")) kwargs["solver"] = solver kwargs["zero_cutoff"] = zero_cutoff # generate other arguments # identifiers for reactions are their indexes if reaction_list1 is None: reaction_indexes1 = range(len(cobra_model.reactions)) else: reaction_indexes1 = [ cobra_model.reactions.index(r) for r in reaction_list1 ] if reaction_list2 is None: reaction_indexes2 = reaction_indexes1 else: reaction_indexes2 = [ cobra_model.reactions.index(r) for r in reaction_list2 ] reaction_to_result = generate_matrix_indexes(reaction_indexes1, reaction_indexes2) # Determine 0 flux reactions. If an optimal solution passes no flux # through the deleted reactions, then we know removing them will # not change the solution. wt_solution = solver_dict[solver].solve(cobra_model) if wt_solution.status == "optimal": kwargs["wt_growth_rate"] = wt_solution.f kwargs["no_flux_reaction_indexes"] = \ {i for i, v in enumerate(wt_solution.x) if abs(v) < zero_cutoff} else: warn("wild-type solution status is '%s'" % wt_solution.status) # call the computing functions if method == "fba": results = _double_reaction_deletion_fba(cobra_model, reaction_indexes1, reaction_indexes2, reaction_to_result, **kwargs) elif method == "moma": results = _double_reaction_deletion_moma(cobra_model, reaction_indexes1, reaction_indexes2, reaction_to_result, **kwargs) else: raise ValueError("Unknown deletion method '%s'" % method) # convert upper triangular matrix to full matrix full_result = _format_upper_triangular_matrix( [reaction_to_result[i] for i in reaction_indexes1], # row indexes [reaction_to_result[i] for i in reaction_indexes2], # col indexes results) # format appropriately with labels row_ids = [cobra_model.reactions[i].id for i in reaction_indexes1] column_ids = [cobra_model.reactions[i].id for i in reaction_indexes2] return format_results_frame(row_ids, column_ids, full_result, return_frame)
def double_gene_deletion(cobra_model, gene_list1=None, gene_list2=None, method="fba", return_frame=False, solver=None, zero_cutoff=1e-12, **kwargs): """sequentially knocks out pairs of genes in a model cobra_model : :class:`~cobra.core.Model.Model` cobra model in which to perform deletions gene_list1 : [:class:`~cobra.core.Gene.Gene`:] (or their id's) Genes to be deleted. These will be the rows in the result. If not provided, all reactions will be used. gene_list1 : [:class:`~cobra.core.Gene.Gene`:] (or their id's) Genes to be deleted. These will be the rows in the result. If not provided, reaction_list1 will be used. method: "fba" or "moma" Procedure used to predict the growth rate solver: str for solver name This must be a QP-capable solver for MOMA. If left unspecified, a suitable solver will be automatically chosen. zero_cutoff: float When checking to see if a value is 0, this threshold is used. number_of_processes: int for number of processes to use. If unspecified, the number of parallel processes to use will be automatically determined. Setting this to 1 explicitly disables used of the multiprocessing library. .. note:: multiprocessing is not supported with method=moma return_frame: bool If true, formats the results as a pandas.Dataframe. Otherwise returns a dict of the form: {"x": row_labels, "y": column_labels", "data": 2D matrix} """ # handle arguments which need to be passed on if solver is None: solver = get_solver_name(qp=(method == "moma")) kwargs["solver"] = solver kwargs["zero_cutoff"] = zero_cutoff # generate other arguments # identifiers for genes if gene_list1 is None: gene_ids1 = cobra_model.genes.list_attr("id") else: gene_ids1 = [str(i) for i in gene_list1] if gene_list2 is None: gene_ids2 = gene_ids1 else: gene_ids2 = [str(i) for i in gene_list2] # The gene_id_to_result dict will map each gene id to the index # in the result matrix. gene_id_to_result = generate_matrix_indexes(gene_ids1, gene_ids2) # Determine 0 flux reactions. If an optimal solution passes no flux # through the deleted reactions, then we know removing them will # not change the solution. wt_solution = solver_dict[solver].solve(cobra_model) if wt_solution.status == "optimal": kwargs["wt_growth_rate"] = wt_solution.f kwargs["no_flux_reaction_indexes"] = \ {i for i, v in enumerate(wt_solution.x) if abs(v) < zero_cutoff} else: warn("wild-type solution status is '%s'" % wt_solution.status) if method == "fba": result = _double_gene_deletion_fba(cobra_model, gene_ids1, gene_ids2, gene_id_to_result, **kwargs) elif method == "moma": result = _double_gene_deletion_moma(cobra_model, gene_ids1, gene_ids2, gene_id_to_result, **kwargs) else: raise ValueError("Unknown deletion method '%s'" % method) # convert upper triangular matrix to full matrix full_result = _format_upper_triangular_matrix( [gene_id_to_result[id] for id in gene_ids1], # row indexes [gene_id_to_result[id] for id in gene_ids2], # col indexes, result) # format as a Dataframe if required return format_results_frame(gene_ids1, gene_ids2, full_result, return_frame)
def _double_reaction_deletion_fba(cobra_model, reaction_indexes1, reaction_indexes2, reaction_to_result, solver, number_of_processes=None, zero_cutoff=1e-15, wt_growth_rate=None, no_flux_reaction_indexes=set(), **kwargs): """compute double reaction deletions using fba cobra_model: model reaction_indexes1, reaction_indexes2: reaction indexes (used as unique identifiers) reaction_to_result: maps each reaction identifier to the entry in the result matrix no_flux_reaction_indexes: set of indexes for reactions in the model which carry no flux in an optimal solution. For deletions only in this set, the result will beset to wt_growth_rate. returns an upper triangular square matrix """ if solver is None: solver = get_solver_name() # generate the square result matrix n_results = len(reaction_to_result) results = numpy.empty((n_results, n_results)) results.fill(numpy.nan) PoolClass = CobraDeletionMockPool if number_of_processes == 1 \ else CobraDeletionPool # explicitly disable multiprocessing with PoolClass(cobra_model, n_processes=number_of_processes, solver=solver, **kwargs) as pool: # precompute all single deletions in the pool and store them along # the diagonal for reaction_index, result_index in iteritems(reaction_to_result): pool.submit((reaction_index, ), label=result_index) for result_index, value in pool.receive_all(): # if singly lethal, set everything in row and column to 0 value = value if abs(value) > zero_cutoff else 0. if value == 0.: results[result_index, :] = 0. results[:, result_index] = 0. else: # only the diagonal needs to be set results[result_index, result_index] = value # Run double knockouts in the upper triangle index_selector = yield_upper_tria_indexes(reaction_indexes1, reaction_indexes2, reaction_to_result) for result_index, (r1_index, r2_index) in index_selector: # skip if the result was already computed to be lethal if results[result_index] == 0: continue # reactions removed carry no flux if r1_index in no_flux_reaction_indexes and \ r2_index in no_flux_reaction_indexes: results[result_index] = wt_growth_rate continue pool.submit((r1_index, r2_index), label=result_index) # get results for result in pool.receive_all(): results[result[0]] = result[1] return results
def __init__(self, model, confidence, met_prod=None, n=5, penalty_factor=100, support=5, solver=None, **solver_kwargs): """Initialize parameters and model""" self.model = deepcopy(model) self.objective = model.objective.copy() # Add metabolic targets as mock reactions arrow_re = re.compile("<?(-+|=+)>") if met_prod: if type(met_prod) != list: met_prod = [met_prod] for i, mid in enumerate(met_prod): r = Reaction("EX_CORDA_" + str(i)) r.notes["mock"] = mid r.upper_bound = UPPER self.model.add_reaction(r) if type(mid) == str: if arrow_re.search(mid): r.build_reaction_from_string(mid) else: r.add_metabolites({mid: -1}) elif type(mid) == dict: r.add_metabolites(mid) else: raise TypeError("metabolite test not string or dictionary") confidence[r.id] = 3 convert_to_irreversible(self.model) # Map confidences from forward to backward reactions self.conf = {} for r in self.model.reactions: r.objective_coefficient = 0 r.upper_bound = UPPER if r.id in confidence: if confidence[r.id] not in [-1, 0, 1, 2, 3]: raise ValueError("Not a valid confidence value!") else: self.conf[r.id] = confidence[r.id] elif "reflection" in r.notes: rev = self.model.reactions.get_by_id(r.notes["reflection"]) if confidence[rev.id] not in [-1, 0, 1, 2, 3]: raise ValueError("Not a valid confidence value!") self.conf[r.id] = confidence[rev.id] else: raise ValueError("{} missing from confidences!".format(r.id)) self.__conf_old = self.conf.copy() self.built = False self.tflux = 1 self.impossible = [] self.n = n self.support = support self.pf = penalty_factor self.solver = solver_dict[get_solver_name( ) if solver is None else solver] self.sargs = solver_kwargs
def fast_consistency_check(model, the_reactions=None, epsilon=1e-4, zero_tolerance=1e-7, debug=False): solver = solver_dict[get_solver_name()] if the_reactions is None: the_reactions = model.reactions if hasattr(the_reactions[0], 'id'): the_reactions = [r.id for r in the_reactions] the_reactions = set(the_reactions) irrev_reactions = { r for r in the_reactions if model.reactions.get_by_id(r).lower_bound >= 0 } solution_dict = LP7(model, list(irrev_reactions), epsilon=epsilon) consistent = { r for r, v in solution_dict.items() if abs(v) > zero_tolerance } inconsistent_irrev = irrev_reactions - consistent the_reactions = the_reactions - consistent J = the_reactions - irrev_reactions flipped = False singleton = False FVA_Flag = False while len(J) > 0 and not FVA_Flag: if singleton: blocked = find_blocked_reactions(model, reaction_list=map( model.reactions.get_by_id, J)) consistent = consistent.union(J - set(blocked)) FVA_Flag = True else: Ji = J solution_dict = LP7(model, list(Ji), epsilon=epsilon) consistent = consistent.union({ r for r, v in solution_dict.items() if abs(v) > zero_tolerance and not r.startswith('dummy') }) if len(J.intersection(consistent)) > 0: J -= consistent flipped = False else: if flipped or len(Ji) == 0: flipped = False if singleton: J -= Ji if debug: print "Inconsistent reversible reactions detected:", len( Ji) else: singleton = True else: for r in Ji: reaction = model.reactions.get_by_id(r) reaction_dict = dict([ (k, -2 * v) for k, v in reaction._metabolites.items() ]) reaction.add_metabolites(reaction_dict) lb = reaction.lower_bound reaction.lower_bound = -reaction.upper_bound reaction.upper_bound = -lb flipped = True return list(consistent)