def test_solver(): """Test assignment of different solvers.""" config = Configuration() config.solver = "glpk" assert interface_to_str(config.solver) == "glpk" config.solver = "glpk_exact" assert interface_to_str(config.solver) == "glpk_exact" # Restore default solver. config.solver = "glpk"
def test_choose_solver(self, model): so = su.choose_solver(model) assert su.interface_to_str(so) == "glpk" so = su.choose_solver(model, "glpk") assert su.interface_to_str(so) == "glpk" if any(s in su.solvers for s in su.qp_solvers): qp_choice = su.choose_solver(model, qp=True) assert su.interface_to_str(qp_choice) in su.qp_solvers else: with pytest.raises(su.SolverNotFound): su.choose_solver(model, qp=True)
def _repr_html_(self): return """ <table> <tr> <td><strong>Solver</strong></td> <td>{solver}</td> </tr> <tr> <td><strong>Solver tolerance</strong></td> <td>{tolerance}</td> </tr> <tr> <td><strong>Lower bound</strong></td> <td>{lower_bound}</td> </tr> <tr> <td><strong>Upper bound</strong></td> <td>{upper_bound}</td> </tr> <tr> <td><strong>Processes</strong></td> <td>{processes}</td> </tr> </table>""".format( solver=interface_to_str(self.solver), tolerance=self.tolerance, lower_bound=self.lower_bound, upper_bound=self.upper_bound, processes=self.processes, )
def __repr__(self): return """ solver: {solver} solver tolerance: {tolerance} lower_bound: {lower_bound} upper_bound: {upper_bound} processes: {processes}""".format( solver=interface_to_str(self.solver), tolerance=self.tolerance, lower_bound=self.lower_bound, upper_bound=self.upper_bound, processes=self.processes, )
def solver(self, value): not_valid_interface = SolverNotFound( '%s is not a valid solver interface. Pick from %s.' % ( value, list(solvers))) if isinstance(value, six.string_types): try: interface = solvers[interface_to_str(value)] except KeyError: raise not_valid_interface elif isinstance(value, types.ModuleType) and hasattr(value, 'Model'): interface = value elif isinstance(value, optlang.interface.Model): interface = value.interface else: raise not_valid_interface # Do nothing if the solver did not change if self.problem == interface: return self._solver = interface.Model.clone(self._solver)
def _multi_deletion(model, entity, element_lists, method="fba", processes=None): """ Provide a common interface for single or multiple knockouts. Parameters ---------- model : cobra.Model The metabolic model to perform deletions in. entity : 'gene' or 'reaction' The entity to knockout (``cobra.Gene`` or ``cobra.Reaction``). element_lists : list List of iterables ``cobra.Reaction``s or ``cobra.Gene``s (or their IDs) to be deleted. method: {"fba", "moma", "linear moma"}, optional Method used to predict the growth rate. processes : int, optional The number of parallel processes to run. Can speed up the computations if the number of knockouts to perform is large. If not passed, will be set to the number of CPUs found. Returns ------- pandas.DataFrame A representation of all combinations of entity deletions. The columns are 'growth' and 'status', where index : frozenset([str]) The gene or reaction identifiers that were knocked out. growth : float The growth rate of the adjusted model. status : str The solution's status. """ solver = sutil.interface_to_str(model.problem.__name__) if "moma" in method and solver not in sutil.qp_solvers: raise RuntimeError( "Cannot use MOMA since '{}' is not QP-capable." "Please choose a different solver or use FBA only.".format(solver)) if processes is None: try: processes = multiprocessing.cpu_count() except NotImplementedError: warn("Number of cores could not be detected - assuming 1.") processes = 1 with model: if "moma" in method: add_moma(model, linear="linear" in method) args = set([frozenset(comb) for comb in product(*element_lists)]) processes = min(processes, len(args)) def extract_knockout_results(result_iter): result = pd.DataFrame([ (frozenset(ids), growth, status) for (ids, growth, status) in result_iter ], columns=['ids', 'growth', 'status']) result.set_index('ids', inplace=True) return result if processes > 1: worker = dict(gene=_gene_deletion_worker, reaction=_reaction_deletion_worker)[entity] chunk_size = len(args) // processes pool = multiprocessing.Pool( processes, initializer=_init_worker, initargs=(model,) ) results = extract_knockout_results(pool.imap_unordered( worker, args, chunksize=chunk_size )) pool.close() pool.join() else: worker = dict(gene=_gene_deletion, reaction=_reaction_deletion)[entity] results = extract_knockout_results(map( partial(worker, model), args)) return results
def test_interface_str(self): assert su.interface_to_str("nonsense") == "nonsense" assert su.interface_to_str("optlang.glpk_interface") == "glpk" assert su.interface_to_str("optlang-cplex") == "cplex"
def _multi_deletion(model, entity, element_lists, method="fba", solution=None, processes=None, **kwargs): """ Provide a common interface for single or multiple knockouts. Parameters ---------- model : cobra.Model The metabolic model to perform deletions in. entity : 'gene' or 'reaction' The entity to knockout (``cobra.Gene`` or ``cobra.Reaction``). element_lists : list List of iterables ``cobra.Reaction``s or ``cobra.Gene``s (or their IDs) to be deleted. method: {"fba", "moma", "linear moma", "room", "linear room"}, optional Method used to predict the growth rate. solution : cobra.Solution, optional A previous solution to use as a reference for (linear) MOMA or ROOM. processes : int, optional The number of parallel processes to run. Can speed up the computations if the number of knockouts to perform is large. If not passed, will be set to the number of CPUs found. kwargs : Passed on to underlying simulation functions. Returns ------- pandas.DataFrame A representation of all combinations of entity deletions. The columns are 'growth' and 'status', where index : tuple(str) The gene or reaction identifiers that were knocked out. growth : float The growth rate of the adjusted model. status : str The solution's status. """ solver = sutil.interface_to_str(model.problem.__name__) if method == "moma" and solver not in sutil.qp_solvers: raise RuntimeError( "Cannot use MOMA since '{}' is not QP-capable." "Please choose a different solver or use FBA only.".format(solver)) if processes is None: processes = configuration.processes with model: if "moma" in method: add_moma(model, solution=solution, linear="linear" in method) elif "room" in method: add_room(model, solution=solution, linear="linear" in method, **kwargs) args = set([frozenset(comb) for comb in product(*element_lists)]) processes = min(processes, len(args)) def extract_knockout_results(result_iter): result = pd.DataFrame( [( set(ids), growth, status, ) for (ids, growth, status) in result_iter], columns=["ids", "growth", "status"], ) return result if processes > 1: worker = dict(gene=_gene_deletion_worker, reaction=_reaction_deletion_worker)[entity] chunk_size = len(args) // processes with ProcessPool(processes, initializer=_init_worker, initargs=(model, )) as pool: results = extract_knockout_results( pool.imap_unordered(worker, args, chunksize=chunk_size)) else: worker = dict(gene=_gene_deletion, reaction=_reaction_deletion)[entity] results = extract_knockout_results( map(partial(worker, model), args)) return results
def test_interface_str() -> None: """Test the string representation of solver interfaces.""" assert su.interface_to_str("nonsense") == "nonsense" assert su.interface_to_str("optlang.glpk_interface") == "glpk" assert su.interface_to_str("optlang-cplex") == "cplex"
def single_reaction_deletion_fba(cobra_model, reaction_list, solver=None, **solver_args): """Sequentially knocks out each reaction in a model using FBA. Not supposed to be called directly use `single_reactions_deletion(..., method="fba")` instead. Parameters ---------- cobra_model : cobra.Model The model from which to delete the reactions. The model will not be modified. reaction_list : iterable List of reaction Ids or cobra.Reaction. solver: str, optional The name of the solver to be used. Returns ------- tuple of dicts A tuple ({reaction_id: growth_rate}, {reaction_id: status}) """ legacy = False if solver is None: solver = cobra_model.solver elif "optlang-" in solver: solver = solvers.interface_to_str(solver) solver = solvers.solvers[solver] else: legacy = True solver = legacy_solvers.solver_dict[solver] lp = solver.create_problem(cobra_model) growth_rate_dict = {} status_dict = {} if not legacy: with cobra_model as m: m.solver = solver for reaction in reaction_list: with m: reaction.knock_out() obj_value = m.slim_optimize() status_dict[reaction.id] = m.solver.status growth_rate_dict[reaction.id] = obj_value else: # This entire block can be removed once the legacy solvers are # deprecated for reaction in reaction_list: old_bounds = (reaction.lower_bound, reaction.upper_bound) index = cobra_model.reactions.index(reaction) solver.change_variable_bounds(lp, index, 0., 0.) solver.solve_problem(lp, **solver_args) # get the status and growth rate status = solver.get_status(lp) status_dict[reaction.id] = status growth_rate_dict[reaction.id] = solver.get_objective_value(lp) \ if status == "optimal" else 0. # reset the problem solver.change_variable_bounds(lp, index, old_bounds[0], old_bounds[1]) return growth_rate_dict, status_dict
def single_gene_deletion_moma(cobra_model, gene_list, linear=False, solver=None, **solver_args): """Sequentially knocks out each gene in a model using MOMA. Not supposed to be called directly use `single_reactions_deletion(..., method="moma")` instead. Parameters ---------- gene_list : iterable List of gene IDs or cobra.Reaction. linear : bool Whether to use linear MOMA. solver : str, optional The name of the solver to be used. Returns ------- tuple of dicts A tuple ({reaction_id: growth_rate}, {reaction_id: status}) """ if moma is None: raise RuntimeError("scipy required for moma") legacy = False if solver is None: solver = cobra_model.solver elif "optlang-" in solver: solver = solvers.interface_to_str(solver) solver = solvers.solvers[solver] else: legacy = True solver = legacy_solvers.solver_dict[solver] moma_model, moma_objective = moma.create_euclidian_moma_model( cobra_model) growth_rate_dict = {} status_dict = {} if not legacy: solution = cobra_model.optimize() with cobra_model as m: m.solver = solver moma.add_moma(m, solution=solution, linear=linear) for gene in gene_list: with m: gene.knock_out() status = m.solver.optimize() status_dict[gene.id] = status if status == OPTIMAL: growth = m.variables.moma_old_objective.primal else: growth = float("nan") growth_rate_dict[gene.id] = growth else: for gene in gene_list: delete_model_genes(moma_model, [gene.id]) solution = moma.solve_moma_model(moma_model, moma_objective, solver=solver, **solver_args) status_dict[gene.id] = solution.status growth_rate_dict[gene.id] = solution.f undelete_model_genes(moma_model) return growth_rate_dict, status_dict
def single_gene_deletion_fba(cobra_model, gene_list, solver=None, **solver_args): """Sequentially knocks out each gene in a model using FBA. Not supposed to be called directly use `single_reactions_deletion(..., method="fba")` instead. Parameters ---------- gene_list : iterable List of gene IDs or cobra.Reaction. solver: str, optional The name of the solver to be used. Returns ------- tuple of dicts A tuple ({reaction_id: growth_rate}, {reaction_id: status}) """ legacy = False if solver is None: solver = cobra_model.solver elif "optlang-" in solver: solver = solvers.interface_to_str(solver) solver = solvers.solvers[solver] else: legacy = True solver = legacy_solvers.solver_dict[solver] lp = solver.create_problem(cobra_model) growth_rate_dict = {} status_dict = {} if not legacy: with cobra_model as m: m.solver = solver for gene in gene_list: with m: gene.knock_out() obj_value = m.slim_optimize() status_dict[gene.id] = m.solver.status growth_rate_dict[gene.id] = obj_value else: for gene in gene_list: old_bounds = {} for reaction in find_gene_knockout_reactions(cobra_model, [gene]): index = cobra_model.reactions.index(reaction) old_bounds[index] = reaction.bounds solver.change_variable_bounds(lp, index, 0., 0.) solver.solve_problem(lp, **solver_args) # get the status and growth rate status = solver.get_status(lp) status_dict[gene.id] = status growth_rate = solver.get_objective_value(lp) \ if status == "optimal" else 0. growth_rate_dict[gene.id] = growth_rate # reset the problem for index, bounds in iteritems(old_bounds): solver.change_variable_bounds(lp, index, bounds[0], bounds[1]) return growth_rate_dict, status_dict
def single_reaction_deletion_moma(cobra_model, reaction_list, linear=False, solver=None, **solver_args): """Sequentially knocks out each reaction in a model using MOMA. Not supposed to be called directly use `single_reactions_deletion(..., method="moma")` instead. Parameters ---------- cobra_model : cobra.Model The model from which to delete the reactions. The model will not be modified. reaction_list : iterable List of reaction IDs or cobra.Reaction. linear : bool Whether to use linear MOMA. solver: str, optional The name of the solver to be used. Returns ------- tuple of dicts A tuple ({reaction_id: growth_rate}, {reaction_id: status}) """ # The same function can not be used because MOMA can not re-use the # same LP object. Problem re-use leads to incorrect solutions. # This is *not* true for optlang solvers! if moma is None: raise RuntimeError("scipy required for moma") legacy = False if solver is None: solver = cobra_model.solver elif "optlang-" in solver: solver = solvers.interface_to_str(solver) solver = solvers.solvers[solver] else: legacy = True solver = legacy_solvers.solver_dict[solver] moma_model, moma_objective = moma.create_euclidian_moma_model( cobra_model) growth_rate_dict = {} status_dict = {} if not legacy: solution = cobra_model.optimize() with cobra_model as m: m.solver = solver moma.add_moma(m, solution=solution, linear=linear) for reaction in reaction_list: with m: reaction.knock_out() status = m.solver.optimize() status_dict[reaction.id] = status if status == OPTIMAL: growth = m.variables.moma_old_objective.primal else: growth = float("nan") growth_rate_dict[reaction.id] = growth else: for reaction in reaction_list: index = cobra_model.reactions.index(reaction) solution = moma.moma_knockout(moma_model, moma_objective, (index, ), solver=solver, **solver_args) status_dict[reaction.id] = solution.status growth_rate_dict[reaction.id] = solution.f return growth_rate_dict, status_dict