Beispiel #1
0
    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)
Beispiel #2
0
 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)
Beispiel #3
0
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
Beispiel #4
0
    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)
Beispiel #5
0
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()
Beispiel #6
0
 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)
Beispiel #7
0
    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)
Beispiel #8
0
 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)
Beispiel #9
0
 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)
Beispiel #10
0
    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)
Beispiel #11
0
 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)
Beispiel #12
0
 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)
Beispiel #13
0
    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)
Beispiel #14
0
 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)
Beispiel #15
0
 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)
Beispiel #16
0
    def test_with(self, problem_cache_trial):
        core_model, reference, n_constraints, n_variables = problem_cache_trial
        with ProblemCache(core_model) as cache:
            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)

            # If the method runs again, it does not add repeated variables
            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)

        # 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)
Beispiel #17
0
    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)
Beispiel #18
0
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)
Beispiel #19
0
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()
Beispiel #20
0
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)
Beispiel #21
0
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()
Beispiel #22
0
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)
Beispiel #23
0
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()
Beispiel #24
0
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()
Beispiel #25
0
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()
Beispiel #26
0
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()
Beispiel #27
0
    # print("cobra pfba")
    # tic = time.time()
    # optimize_minimal_flux(cb_model, solver='cglpk')
    # print("flux sum:", sum([abs(val) for val in list(cb_model.solution.x_dict.values())]))
    # print("cobra pfba runtime:", time.time() - tic)

    print("pfba")
    tic = time.time()
    ref = pfba(model)
    print("flux sum:", end=' ')
    print(sum([abs(val) for val in list(ref.values())]))
    print("cameo pfba runtime:", time.time() - tic)

    print("lmoma")
    cache = ProblemCache(model)
    tic = time.time()
    res = lmoma(model, reference=ref, cache=cache)
    print("flux distance:", end=' ')
    print(sum([abs(res[v] - ref[v]) for v in list(res.keys())]))
    print("cameo lmoma runtime:", time.time() - tic)

    print("room")
    tic = time.time()
    res = room(model, reference=ref)
    print(sum([abs(res[v] - ref[v]) for v in list(res.keys())]))
    print("cameo room runtime:", time.time() - tic)

    print("flux distance:", end=' ')
    print(sum([abs(res[v] - ref[v]) for v in list(res.keys())]))
    print("sum yi:", res.objective_value)
Beispiel #28
0
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()