def shadow_price(self):
        """
        The shadow price in the most recent solution.

        Shadow price is the dual value of the corresponding constraint in the
        model.

        Warnings
        --------
        * Accessing shadow prices through a `Solution` object is the safer,
          preferred, and only guaranteed to be correct way. You can see how to
          do so easily in the examples.
        * Shadow price is retrieved from the currently defined
          `self._model.solver`. The solver status is checked but there are no
          guarantees that the current solver state is the one you are looking
          for.
        * If you modify the underlying model after an optimization, you will
          retrieve the old optimization values.

        Raises
        ------
        RuntimeError
            If the underlying model was never optimized beforehand or the
            metabolite is not part of a model.
        OptimizationError
            If the solver status is anything other than 'optimal'.

        Examples
        --------
        >>> import cobra
        >>> import cobra.test
        >>> model = cobra.test.create_test_model("textbook")
        >>> solution = model.optimize()
        >>> model.metabolites.glc__D_e.shadow_price
        -0.09166474637510488
        >>> solution.shadow_prices.glc__D_e
        -0.091664746375104883
        """
        try:
            check_solver_status(self._model.solver.status)
            return self._model.constraints[self.id].dual
        except AttributeError:
            raise RuntimeError(
                "metabolite '{}' is not part of a model".format(self.id))
        # Due to below all-catch, which sucks, need to reraise these.
        except (RuntimeError, OptimizationError) as err:
            raise_with_traceback(err)
        # Would love to catch CplexSolverError and GurobiError here.
        except Exception as err:
            raise_from(OptimizationError(
                "Likely no solution exists. Original solver message: {}."
                "".format(str(err))), err)

The shadow price in the most recent solution .


def to_yaml(model, sort=False, **kwargs):
    """
    Return the model as a YAML document.

    ``kwargs`` are passed on to ``yaml.dump``.

    Parameters
    ----------
    model : cobra.Model
        The cobra model to represent.
    sort : bool, optional
        Whether to sort the metabolites, reactions, and genes or maintain the
        order defined in the model.

    Returns
    -------
    str
        String representation of the cobra model as a YAML document.

    See Also
    --------
    save_yaml_model : Write directly to a file.
    ruamel.yaml.dump : Base function.
    """

    obj = model_to_dict(model, sort=sort)
    obj["version"] = YAML_SPEC
    return yaml.dump(obj, **kwargs)

def to_yaml ( model , sort = False , ** kwargs ) : obj = model_to_dict ( model , sort = sort ) obj [ "version" ] = YAML_SPEC return yaml . dump ( obj , ** kwargs )


def save_yaml_model(model, filename, sort=False, **kwargs):
    """
    Write the cobra model to a file in YAML format.

    ``kwargs`` are passed on to ``yaml.dump``.

    Parameters
    ----------
    model : cobra.Model
        The cobra model to represent.
    filename : str or file-like
        File path or descriptor that the YAML representation should be
        written to.
    sort : bool, optional
        Whether to sort the metabolites, reactions, and genes or maintain the
        order defined in the model.

    See Also
    --------
    to_yaml : Return a string representation.
    ruamel.yaml.dump : Base function.
    """
    obj = model_to_dict(model, sort=sort)
    obj["version"] = YAML_SPEC
    if isinstance(filename, string_types):
        with io.open(filename, "w") as file_handle:
            yaml.dump(obj, file_handle, **kwargs)
    else:
        yaml.dump(obj, filename, **kwargs)

def save_yaml_model ( model , filename , sort = False , ** kwargs ) : obj = model_to_dict ( model , sort = sort ) obj [ "version" ] = YAML_SPEC if isinstance ( filename , string_types ) : with io . open ( filename , "w" ) as file_handle : yaml . dump ( obj , file_handle , ** kwargs ) else : yaml . dump ( obj , filename , ** kwargs )

Write the cobra model to a file in YAML format .


def load_yaml_model(filename):
    """
    Load a cobra model from a file in YAML format.

    Parameters
    ----------
    filename : str or file-like
        File path or descriptor that contains the YAML document describing the
        cobra model.

    Returns
    -------
    cobra.Model
        The cobra model as represented in the YAML document.

    See Also
    --------
    from_yaml : Load from a string.
    """
    if isinstance(filename, string_types):
        with io.open(filename, "r") as file_handle:
            return model_from_dict(yaml.load(file_handle))
    else:
        return model_from_dict(yaml.load(filename))

def load_yaml_model ( filename ) : if isinstance ( filename , string_types ) : with io . open ( filename , "r" ) as file_handle : return model_from_dict ( yaml . load ( file_handle ) ) else : return model_from_dict ( yaml . load ( filename ) )

Load a cobra model from a file in YAML format .


def add_pfba(model, objective=None, fraction_of_optimum=1.0):
    """Add pFBA objective

    Add objective to minimize the summed flux of all reactions to the
    current objective.

    See Also
    -------
    pfba

    Parameters
    ----------
    model : cobra.Model
        The model to add the objective to
    objective :
        An objective to set in combination with the pFBA objective.
    fraction_of_optimum : float
        Fraction of optimum which must be maintained. The original objective
        reaction is constrained to be greater than maximal_value *
        fraction_of_optimum.
    """
    if objective is not None:
        model.objective = objective
    if model.solver.objective.name == '_pfba_objective':
        raise ValueError('The model already has a pFBA objective.')
    sutil.fix_objective_as_constraint(model, fraction=fraction_of_optimum)
    reaction_variables = ((rxn.forward_variable, rxn.reverse_variable)
                          for rxn in model.reactions)
    variables = chain(*reaction_variables)
    model.objective = model.problem.Objective(
        Zero, direction='min', sloppy=True, name="_pfba_objective")
    model.objective.set_linear_coefficients({v: 1.0 for v in variables})


def _process_flux_dataframe(flux_dataframe, fva, threshold, floatfmt):
    """Some common methods for processing a database of flux information into
    print-ready formats. Used in both model_summary and metabolite_summary. """

    abs_flux = flux_dataframe['flux'].abs()
    flux_threshold = threshold * abs_flux.max()

    # Drop unused boundary fluxes
    if fva is None:
        flux_dataframe = flux_dataframe.loc[
            abs_flux >= flux_threshold, :].copy()
    else:
        flux_dataframe = flux_dataframe.loc[
            (abs_flux >= flux_threshold) |
            (flux_dataframe['fmin'].abs() >= flux_threshold) |
            (flux_dataframe['fmax'].abs() >= flux_threshold), :].copy()

        # Why set to zero? If included show true value?
        # flux_dataframe.loc[
        #     flux_dataframe['flux'].abs() < flux_threshold, 'flux'] = 0

    # Make all fluxes positive
    if fva is None:
        flux_dataframe['is_input'] = (flux_dataframe['flux'] >= 0)
        flux_dataframe['flux'] = flux_dataframe['flux'].abs()
    else:

        def get_direction(flux, fmin, fmax):
            """ decide whether or not to reverse a flux to make it positive """

            if flux < 0:
                return -1
            elif flux > 0:
                return 1
            elif (fmax > 0) & (fmin <= 0):
                return 1
            elif (fmax < 0) & (fmin >= 0):
                return -1
            elif ((fmax + fmin) / 2) < 0:
                return -1
            else:
                return 1

        sign = flux_dataframe.apply(
            lambda x: get_direction(x.flux, x.fmin, x.fmax), 1)

        flux_dataframe['is_input'] = sign == 1

        flux_dataframe.loc[:, ['flux', 'fmin', 'fmax']] = \
            flux_dataframe.loc[:, ['flux', 'fmin', 'fmax']].multiply(
                sign, 0).astype('float').round(6)

        flux_dataframe.loc[:, ['flux', 'fmin', 'fmax']] = \
            flux_dataframe.loc[:, ['flux', 'fmin', 'fmax']].applymap(
                lambda x: x if abs(x) > 1E-6 else 0)

    if fva is not None:
        flux_dataframe['fva_fmt'] = flux_dataframe.apply(
            lambda x: ("[{0.fmin:" + floatfmt + "}, {0.fmax:" +
                       floatfmt + "}]").format(x), 1)

        flux_dataframe = flux_dataframe.sort_values(
            by=['flux', 'fmax', 'fmin', 'id'],
            ascending=[False, False, False, True])

    else:
        flux_dataframe = flux_dataframe.sort_values(
            by=['flux', 'id'], ascending=[False, True])

    return flux_dataframe

def
_process_flux_dataframe
(
flux_dataframe
,
fva
,
threshold
,
floatfmt
)
:
abs_flux
=
flux_dataframe
[
'flux'
]
.
abs
(
)
flux_threshold
=
threshold
*
abs_flux
.
max
(
)
if
fva
is
:
flux_dataframe
=
flux_dataframe
.
loc
[
abs_flux
>=
flux_threshold
,
:
]
.
copy
(
)
else
:
flux_dataframe
=
flux_dataframe
.
loc
[
(
abs_flux
>=
flux_threshold
)
|
(
flux_dataframe
[
'fmin'
]
.
abs
(
)
>=
flux_threshold
)
|
(
flux_dataframe
[
'fmax'
]
.
abs
(
)
>=
flux_threshold
)
,
:
]
.
copy
(
)
if
fva
is
:
flux_dataframe
[
'is_input'
]
=
(
flux_dataframe
[
'flux'
]
>=
0
)
flux_dataframe
[
'flux'
]
=
flux_dataframe
[
'flux'
]
.
abs
(
)
else
:
def
get_direction
(
flux
,
fmin
,
fmax
)
:
if
flux
<
0
:
return
1
elif
flux
>
0
:
return
1
elif
(
fmax
>
0
)
&
(
fmin
<=
0
)
:
return
1
elif
(
fmax
<
0
)
&
(
fmin
>=
0
)
:
return
1
elif
(
(
fmax
+
fmin
)
/
2
)
<
0
:
return
1
else
:
return
1
sign
=
flux_dataframe
.
apply
(
lambda
x
:
get_direction
(
x
.
flux
,
x
.
fmin
,
x
.
fmax
)
,
1
)
flux_dataframe
[
'is_input'
]
=
sign
==
1
flux_dataframe
.
loc
[
:
,
[
'flux'
,
'fmin'
,
'fmax'
]
]
=
flux_dataframe
.
loc
[
:
,
[
'flux'
,
'fmin'
,
'fmax'
]
]
.
multiply
(
sign
,
0
)
.
astype
(
'float'
)
.
round
(
6
)
flux_dataframe
.
loc
[
:
,
[
'flux'
,
'fmin'
,
'fmax'
]
]
=
flux_dataframe
.
loc
[
:
,
[
'flux'
,
'fmin'
,
'fmax'
]
]
.
applymap
(
lambda
x
:
x
if
abs
(
x
)
>
1E-6
else
0
)
if
fva
is
not
:
flux_dataframe
[
'fva_fmt'
]
=
flux_dataframe
.
apply
(
lambda
x
:
(
"[{0.fmin:"
+
floatfmt
+
"}, {0.fmax:"
+
floatfmt
+
"}]"
)
.
format
(
x
)
,
1
)
flux_dataframe
=
flux_dataframe
.
sort_values
(
by
=
[
'flux'
,
'fmax'
,
'fmin'
,
'id'
]
,
ascending
=
[
False
,
False
,
False
,
True
]
)
else
:
flux_dataframe
=
flux_dataframe
.
sort_values
(
by
=
[
'flux'
,
'id'
]
,
ascending
=
[
False
,
True
]
)
return
flux_dataframe

Some common methods for processing a database of flux information into print - ready formats . Used in both model_summary and metabolite_summary .


def linear_reaction_coefficients(model, reactions=None):
    """Coefficient for the reactions in a linear objective.

    Parameters
    ----------
    model : cobra model
        the model object that defined the objective
    reactions : list
        an optional list for the reactions to get the coefficients for. All
        reactions if left missing.

    Returns
    -------
    dict
        A dictionary where the key is the reaction object and the value is
        the corresponding coefficient. Empty dictionary if there are no
        linear terms in the objective.
    """
    linear_coefficients = {}
    reactions = model.reactions if not reactions else reactions
    try:
        objective_expression = model.solver.objective.expression
        coefficients = objective_expression.as_coefficients_dict()
    except AttributeError:
        return linear_coefficients
    for rxn in reactions:
        forward_coefficient = coefficients.get(rxn.forward_variable, 0)
        reverse_coefficient = coefficients.get(rxn.reverse_variable, 0)
        if forward_coefficient != 0:
            if forward_coefficient == -reverse_coefficient:
                linear_coefficients[rxn] = float(forward_coefficient)
    return linear_coefficients

def linear_reaction_coefficients ( model , reactions = None ) : linear_coefficients = { } reactions = model . reactions if not reactions else reactions try : objective_expression = model . solver . objective . expression coefficients = objective_expression . as_coefficients_dict ( ) except AttributeError : return linear_coefficients for rxn in reactions : forward_coefficient = coefficients . get ( rxn . forward_variable , 0 ) reverse_coefficient = coefficients . get ( rxn . reverse_variable , 0 ) if forward_coefficient != 0 : if forward_coefficient == - reverse_coefficient : linear_coefficients [ rxn ] = float ( forward_coefficient ) return linear_coefficients

Coefficient for the reactions in a linear objective .


def _valid_atoms(model, expression):
    """Check whether a sympy expression references the correct variables.

    Parameters
    ----------
    model : cobra.Model
        The model in which to check for variables.
    expression : sympy.Basic
        A sympy expression.

    Returns
    -------
    boolean
        True if all referenced variables are contained in model, False
        otherwise.
    """
    atoms = expression.atoms(optlang.interface.Variable)
    return all(a.problem is model.solver for a in atoms)

def _valid_atoms ( model , expression ) : atoms = expression . atoms ( optlang . interface . Variable ) return all ( a . problem is model . solver for a in atoms )

Check whether a sympy expression references the correct variables .


def set_objective(model, value, additive=False):
    """Set the model objective.

    Parameters
    ----------
    model : cobra model
       The model to set the objective for
    value : model.problem.Objective,
            e.g. optlang.glpk_interface.Objective, sympy.Basic or dict

        If the model objective is linear, the value can be a new Objective
        object or a dictionary with linear coefficients where each key is a
        reaction and the element the new coefficient (float).

        If the objective is not linear and `additive` is true, only values
        of class Objective.

    additive : boolmodel.reactions.Biomass_Ecoli_core.bounds = (0.1, 0.1)
        If true, add the terms to the current objective, otherwise start with
        an empty objective.
    """
    interface = model.problem
    reverse_value = model.solver.objective.expression
    reverse_value = interface.Objective(
        reverse_value, direction=model.solver.objective.direction,
        sloppy=True)

    if isinstance(value, dict):
        if not model.objective.is_Linear:
            raise ValueError('can only update non-linear objectives '
                             'additively using object of class '
                             'model.problem.Objective, not %s' %
                             type(value))

        if not additive:
            model.solver.objective = interface.Objective(
                Zero, direction=model.solver.objective.direction)
        for reaction, coef in value.items():
            model.solver.objective.set_linear_coefficients(
                {reaction.forward_variable: coef,
                 reaction.reverse_variable: -coef})

    elif isinstance(value, (Basic, optlang.interface.Objective)):
        if isinstance(value, Basic):
            value = interface.Objective(
                value, direction=model.solver.objective.direction,
                sloppy=False)
        # Check whether expression only uses variables from current model
        # clone the objective if not, faster than cloning without checking
        if not _valid_atoms(model, value.expression):
            value = interface.Objective.clone(value, model=model.solver)

        if not additive:
            model.solver.objective = value
        else:
            model.solver.objective += value.expression
    else:
        raise TypeError(
            '%r is not a valid objective for %r.' % (value, model.solver))

    context = get_context(model)
    if context:
        def reset():
            model.solver.objective = reverse_value
            model.solver.objective.direction = reverse_value.direction

        context(reset)


def interface_to_str(interface):
    """Give a string representation for an optlang interface.

    Parameters
    ----------
    interface : string, ModuleType
        Full name of the interface in optlang or cobra representation.
        For instance 'optlang.glpk_interface' or 'optlang-glpk'.

    Returns
    -------
    string
       The name of the interface as a string
    """
    if isinstance(interface, ModuleType):
        interface = interface.__name__
    return re.sub(r"optlang.|.interface", "", interface)

def interface_to_str ( interface ) : if isinstance ( interface , ModuleType ) : interface = interface . __name__ return re . sub ( r"optlang.|.interface" , "" , interface )

Give a string representation for an optlang interface .


def get_solver_name(mip=False, qp=False):
    """Select a solver for a given optimization problem.

    Parameters
    ----------
    mip : bool
        Does the solver require mixed integer linear programming capabilities?
    qp : bool
        Does the solver require quadratic programming capabilities?

    Returns
    -------
    string
        The name of feasible solver.

    Raises
    ------
    SolverNotFound
        If no suitable solver could be found.
    """
    if len(solvers) == 0:
        raise SolverNotFound("no solvers installed")
    # Those lists need to be updated as optlang implements more solvers
    mip_order = ["gurobi", "cplex", "glpk"]
    lp_order = ["glpk", "cplex", "gurobi"]
    qp_order = ["gurobi", "cplex"]

    if mip is False and qp is False:
        for solver_name in lp_order:
            if solver_name in solvers:
                return solver_name
        # none of them are in the list order - so return the first one
        return list(solvers)[0]
    elif qp:  # mip does not yet matter for this determination
        for solver_name in qp_order:
            if solver_name in solvers:
                return solver_name
        raise SolverNotFound("no qp-capable solver found")
    else:
        for solver_name in mip_order:
            if solver_name in solvers:
                return solver_name
    raise SolverNotFound("no mip-capable solver found")

def
get_solver_name
(
mip
=
False
,
qp
=
False
)
:
if
len
(
solvers
)
==
0
:
raise
SolverNotFound
(
"no solvers installed"
)
mip_order
=
[
"gurobi"
,
"cplex"
,
"glpk"
]
lp_order
=
[
"glpk"
,
"cplex"
,
"gurobi"
]
qp_order
=
[
"gurobi"
,
"cplex"
]
if
mip
is
False
and
qp
is
False
:
for
solver_name
in
lp_order
:
if
solver_name
in
solvers
:
return
solver_name
return
list
(
solvers
)
[
0
]
elif
qp
:
for
solver_name
in
qp_order
:
if
solver_name
in
solvers
:
return
solver_name
raise
SolverNotFound
(
"no qp-capable solver found"
)
else
:
for
solver_name
in
mip_order
:
if
solver_name
in
solvers
:
return
solver_name
raise
SolverNotFound
(
"no mip-capable solver found"
)

Select a solver for a given optimization problem .


def choose_solver(model, solver=None, qp=False):
    """Choose a solver given a solver name and model.

    This will choose a solver compatible with the model and required
    capabilities. Also respects model.solver where it can.

    Parameters
    ----------
    model : a cobra model
        The model for which to choose the solver.
    solver : str, optional
        The name of the solver to be used.
    qp : boolean, optional
        Whether the solver needs Quadratic Programming capabilities.

    Returns
    -------
    solver : an optlang solver interface
        Returns a valid solver for the problem.

    Raises
    ------
    SolverNotFound
        If no suitable solver could be found.
    """
    if solver is None:
        solver = model.problem
    else:
        model.solver = solver

    # Check for QP, raise error if no QP solver found
    if qp and interface_to_str(solver) not in qp_solvers:
        solver = solvers[get_solver_name(qp=True)]

    return solver

def choose_solver ( model , solver = None , qp = False ) : if solver is None : solver = model . problem else : model . solver = solver if qp and interface_to_str ( solver ) not in qp_solvers : solver = solvers [ get_solver_name ( qp = True ) ] return solver

Choose a solver given a solver name and model .


def add_cons_vars_to_problem(model, what, **kwargs):
    """Add variables and constraints to a Model's solver object.

    Useful for variables and constraints that can not be expressed with
    reactions and lower/upper bounds. Will integrate with the Model's context
    manager in order to revert changes upon leaving the context.

    Parameters
    ----------
    model : a cobra model
       The model to which to add the variables and constraints.
    what : list or tuple of optlang variables or constraints.
       The variables or constraints to add to the model. Must be of class
       `model.problem.Variable` or
       `model.problem.Constraint`.
    **kwargs : keyword arguments
        passed to solver.add()
    """
    context = get_context(model)

    model.solver.add(what, **kwargs)
    if context:
        context(partial(model.solver.remove, what))

def add_cons_vars_to_problem ( model , what , ** kwargs ) : context = get_context ( model ) model . solver . add ( what , ** kwargs ) if context : context ( partial ( model . solver . remove , what ) )

Add variables and constraints to a Model s solver object .


def remove_cons_vars_from_problem(model, what):
    """Remove variables and constraints from a Model's solver object.

    Useful to temporarily remove variables and constraints from a Models's
    solver object.

    Parameters
    ----------
    model : a cobra model
       The model from which to remove the variables and constraints.
    what : list or tuple of optlang variables or constraints.
       The variables or constraints to remove from the model. Must be of
       class `model.problem.Variable` or
       `model.problem.Constraint`.
    """
    context = get_context(model)

    model.solver.remove(what)
    if context:
        context(partial(model.solver.add, what))

def remove_cons_vars_from_problem ( model , what ) : context = get_context ( model ) model . solver . remove ( what ) if context : context ( partial ( model . solver . add , what ) )

Remove variables and constraints from a Model s solver object .


def add_absolute_expression(model, expression, name="abs_var", ub=None,
                            difference=0, add=True):
    """Add the absolute value of an expression to the model.

    Also defines a variable for the absolute value that can be used in other
    objectives or constraints.

    Parameters
    ----------
    model : a cobra model
       The model to which to add the absolute expression.
    expression : A sympy expression
       Must be a valid expression within the Model's solver object. The
       absolute value is applied automatically on the expression.
    name : string
       The name of the newly created variable.
    ub : positive float
       The upper bound for the variable.
    difference : positive float
        The difference between the expression and the variable.
    add : bool
        Whether to add the variable to the model at once.

    Returns
    -------
    namedtuple
        A named tuple with variable and two constraints (upper_constraint,
        lower_constraint) describing the new variable and the constraints
        that assign the absolute value of the expression to it.
    """
    Components = namedtuple('Components', ['variable', 'upper_constraint',
                                           'lower_constraint'])
    variable = model.problem.Variable(name, lb=0, ub=ub)
    # The following constraints enforce variable > expression and
    # variable > -expression
    upper_constraint = model.problem.Constraint(expression - variable,
                                                ub=difference,
                                                name="abs_pos_" + name),
    lower_constraint = model.problem.Constraint(expression + variable,
                                                lb=difference,
                                                name="abs_neg_" + name)
    to_add = Components(variable, upper_constraint, lower_constraint)
    if add:
        add_cons_vars_to_problem(model, to_add)
    return to_add

def add_absolute_expression ( model , expression , name = "abs_var" , ub = None , difference = 0 , add = True ) : Components = namedtuple ( 'Components' , [ 'variable' , 'upper_constraint' , 'lower_constraint' ] ) variable = model . problem . Variable ( name , lb = 0 , ub = ub ) upper_constraint = model . problem . Constraint ( expression - variable , ub = difference , name = "abs_pos_" + name ) , lower_constraint = model . problem . Constraint ( expression + variable , lb = difference , name = "abs_neg_" + name ) to_add = Components ( variable , upper_constraint , lower_constraint ) if add : add_cons_vars_to_problem ( model , to_add ) return to_add

Add the absolute value of an expression to the model .


def fix_objective_as_constraint(model, fraction=1, bound=None,
                                name='fixed_objective_{}'):
    """Fix current objective as an additional constraint.

    When adding constraints to a model, such as done in pFBA which
    minimizes total flux, these constraints can become too powerful,
    resulting in solutions that satisfy optimality but sacrifices too
    much for the original objective function. To avoid that, we can fix
    the current objective value as a constraint to ignore solutions that
    give a lower (or higher depending on the optimization direction)
    objective value than the original model.

    When done with the model as a context, the modification to the
    objective will be reverted when exiting that context.

    Parameters
    ----------
    model : cobra.Model
        The model to operate on
    fraction : float
        The fraction of the optimum the objective is allowed to reach.
    bound : float, None
        The bound to use instead of fraction of maximum optimal value. If
        not None, fraction is ignored.
    name : str
        Name of the objective. May contain one `{}` placeholder which is filled
        with the name of the old objective.

    Returns
    -------
        The value of the optimized objective * fraction
    """
    fix_objective_name = name.format(model.objective.name)
    if fix_objective_name in model.constraints:
        model.solver.remove(fix_objective_name)
    if bound is None:
        bound = model.slim_optimize(error_value=None) * fraction
    if model.objective.direction == 'max':
        ub, lb = None, bound
    else:
        ub, lb = bound, None
    constraint = model.problem.Constraint(
        model.objective.expression,
        name=fix_objective_name, ub=ub, lb=lb)
    add_cons_vars_to_problem(model, constraint, sloppy=True)
    return bound

def fix_objective_as_constraint ( model , fraction = 1 , bound = None , name = 'fixed_objective_{}' ) : fix_objective_name = name . format ( model . objective . name ) if fix_objective_name in model . constraints : model . solver . remove ( fix_objective_name ) if bound is None : bound = model . slim_optimize ( error_value = None ) * fraction if model . objective . direction == 'max' : ub , lb = None , bound else : ub , lb = bound , None constraint = model . problem . Constraint ( model . objective . expression , name = fix_objective_name , ub = ub , lb = lb ) add_cons_vars_to_problem ( model , constraint , sloppy = True ) return bound

Fix current objective as an additional constraint .


def check_solver_status(status, raise_error=False):
    """Perform standard checks on a solver's status."""
    if status == OPTIMAL:
        return
    elif (status in has_primals) and not raise_error:
        warn("solver status is '{}'".format(status), UserWarning)
    elif status is None:
        raise OptimizationError(
            "model was not optimized yet or solver context switched")
    else:
        raise OptimizationError("solver status is '{}'".format(status))

Perform standard checks on a solver s status .


def assert_optimal(model, message='optimization failed'):
    """Assert model solver status is optimal.

    Do nothing if model solver status is optimal, otherwise throw
    appropriate exception depending on the status.

    Parameters
    ----------
    model : cobra.Model
        The model to check the solver status for.
    message : str (optional)
        Message to for the exception if solver status was not optimal.
    """
    status = model.solver.status
    if status != OPTIMAL:
        exception_cls = OPTLANG_TO_EXCEPTIONS_DICT.get(
            status, OptimizationError)
        raise exception_cls("{} ({})".format(message, status))

def
assert_optimal
(
model
,
message
=
'optimization failed'
)
:
status
=
model
.
solver
.
status
if
status
!=
OPTIMAL
:
exception_cls
=
OPTLANG_TO_EXCEPTIONS_DICT
.
get
(
status
,
OptimizationError
)
raise
exception_cls
(
"{} ({})"
.
format
(
message
,
status
)
)


def add_lp_feasibility(model):
    """
    Add a new objective and variables to ensure a feasible solution.

    The optimized objective will be zero for a feasible solution and otherwise
    represent the distance from feasibility (please see [1]_ for more
    information).

    Parameters
    ----------
    model : cobra.Model
        The model whose feasibility is to be tested.

    References
    ----------
    .. [1] Gomez, Jose A., Kai Höffner, and Paul I. Barton.
    “DFBAlab: A Fast and Reliable MATLAB Code for Dynamic Flux Balance
    Analysis.” BMC Bioinformatics 15, no. 1 (December 18, 2014): 409.
    https://doi.org/10.1186/s12859-014-0409-8.

    """

    obj_vars = []
    prob = model.problem
    for met in model.metabolites:
        s_plus = prob.Variable("s_plus_" + met.id, lb=0)
        s_minus = prob.Variable("s_minus_" + met.id, lb=0)

        model.add_cons_vars([s_plus, s_minus])
        model.constraints[met.id].set_linear_coefficients(
            {s_plus: 1.0, s_minus: -1.0})
        obj_vars.append(s_plus)
        obj_vars.append(s_minus)

    model.objective = prob.Objective(Zero, sloppy=True, direction="min")
    model.objective.set_linear_coefficients({v: 1.0 for v in obj_vars})

def add_lp_feasibility ( model ) : obj_vars = [ ] prob = model . problem for met in model . metabolites : s_plus = prob . Variable ( "s_plus_" + met . id , lb = 0 ) s_minus = prob . Variable ( "s_minus_" + met . id , lb = 0 ) model . add_cons_vars ( [ s_plus , s_minus ] ) model . constraints [ met . id ] . set_linear_coefficients ( { s_plus : 1.0 , s_minus : - 1.0 } ) obj_vars . append ( s_plus ) obj_vars . append ( s_minus ) model . objective = prob . Objective ( Zero , sloppy = True , direction = "min" ) model . objective . set_linear_coefficients ( { v : 1.0 for v in obj_vars } )

Add a new objective and variables to ensure a feasible solution .


def add_lexicographic_constraints(model,
                                  objectives,
                                  objective_direction='max'):
    """
    Successively optimize separate targets in a specific order.

    For each objective, optimize the model and set the optimal value as a
    constraint. Proceed in the order of the objectives given. Due to the
    specific order this is called lexicographic FBA [1]_. This
    procedure is useful for returning unique solutions for a set of important
    fluxes. Typically this is applied to exchange fluxes.

    Parameters
    ----------
    model : cobra.Model
        The model to be optimized.
    objectives : list
        A list of reactions (or objectives) in the model for which unique
        fluxes are to be determined.
    objective_direction : str or list, optional
        The desired objective direction for each reaction (if a list) or the
        objective direction to use for all reactions (default maximize).

    Returns
    -------
    optimized_fluxes : pandas.Series
        A vector containing the optimized fluxes for each of the given
        reactions in `objectives`.

    References
    ----------
    .. [1] Gomez, Jose A., Kai Höffner, and Paul I. Barton.
    “DFBAlab: A Fast and Reliable MATLAB Code for Dynamic Flux Balance
    Analysis.” BMC Bioinformatics 15, no. 1 (December 18, 2014): 409.
    https://doi.org/10.1186/s12859-014-0409-8.

    """

    if type(objective_direction) is not list:
        objective_direction = [objective_direction] * len(objectives)

    constraints = []
    for rxn_id, obj_dir in zip(objectives, objective_direction):
        model.objective = model.reactions.get_by_id(rxn_id)
        model.objective_direction = obj_dir
        constraints.append(fix_objective_as_constraint(model))

    return pd.Series(constraints, index=objectives)

def add_lexicographic_constraints ( model , objectives , objective_direction = 'max' ) : if type ( objective_direction ) is not list : objective_direction = [ objective_direction ] * len ( objectives ) constraints = [ ] for rxn_id , obj_dir in zip ( objectives , objective_direction ) : model . objective = model . reactions . get_by_id ( rxn_id ) model . objective_direction = obj_dir constraints . append ( fix_objective_as_constraint ( model ) ) return pd . Series ( constraints , index = objectives )

Successively optimize separate targets in a specific order .


def shared_np_array(shape, data=None, integer=False):
    """Create a new numpy array that resides in shared memory.

    Parameters
    ----------
    shape : tuple of ints
        The shape of the new array.
    data : numpy.array
        Data to copy to the new array. Has to have the same shape.
    integer : boolean
        Whether to use an integer array. Defaults to False which means
        float array.

    """

    size = np.prod(shape)

    if integer:
        array = Array(ctypes.c_int64, int(size))
        np_array = np.frombuffer(array.get_obj(), dtype="int64")
    else:
        array = Array(ctypes.c_double, int(size))
        np_array = np.frombuffer(array.get_obj())

    np_array = np_array.reshape(shape)

    if data is not None:
        if len(shape) != len(data.shape):
            raise ValueError("`data` must have the same dimensions"
                             "as the created array.")
        same = all(x == y for x, y in zip(shape, data.shape))

        if not same:
            raise ValueError("`data` must have the same shape"
                             "as the created array.")
        np_array[:] = data

    return np_array

def
shared_np_array
(
shape
,
data
=
,
integer
=
False
)
:
size
=
np
.
prod
(
shape
)
if
integer
:
array
=
Array
(
ctypes
.
c_int64
,
int
(
size
)
)
np_array
=
np
.
frombuffer
(
array
.
get_obj
(
)
,
dtype
=
"int64"
)
else
:
array
=
Array
(
ctypes
.
c_double
,
int
(
size
)
)
np_array
=
np
.
frombuffer
(
array
.
get_obj
(
)
)
np_array
=
np_array
.
reshape
(
shape
)
if
data
is
not
:
if
len
(
shape
)
!=
len
(
data
.
shape
)
:
raise
ValueError
(
"`data` must have the same dimensions"
"as the created array."
)
same
=
all
(
x
==
y
for
x
,
y
in
zip
(
shape
,
data
.
shape
)
)
if
not
same
:
raise
ValueError
(
"`data` must have the same shape"
"as the created array."
)
np_array
[
:
]
=
data
return
np_array

Create a new numpy array that resides in shared memory .


def step(sampler, x, delta, fraction=None, tries=0):
    """Sample a new feasible point from the point `x` in direction `delta`."""

    prob = sampler.problem
    valid = ((np.abs(delta) > sampler.feasibility_tol) &
             np.logical_not(prob.variable_fixed))

    # permissible alphas for staying in variable bounds
    valphas = ((1.0 - sampler.bounds_tol) * prob.variable_bounds -
               x)[:, valid]
    valphas = (valphas / delta[valid]).flatten()

    if prob.bounds.shape[0] > 0:
        # permissible alphas for staying in constraint bounds
        ineqs = prob.inequalities.dot(delta)
        valid = np.abs(ineqs) > sampler.feasibility_tol
        balphas = ((1.0 - sampler.bounds_tol) * prob.bounds -
                   prob.inequalities.dot(x))[:, valid]
        balphas = (balphas / ineqs[valid]).flatten()

        # combined alphas
        alphas = np.hstack([valphas, balphas])
    else:
        alphas = valphas
    pos_alphas = alphas[alphas > 0.0]
    neg_alphas = alphas[alphas <= 0.0]
    alpha_range = np.array([neg_alphas.max() if len(neg_alphas) > 0 else 0,
                            pos_alphas.min() if len(pos_alphas) > 0 else 0])

    if fraction:
        alpha = alpha_range[0] + fraction * (alpha_range[1] - alpha_range[0])
    else:
        alpha = np.random.uniform(alpha_range[0], alpha_range[1])

    p = x + alpha * delta

    # Numerical instabilities may cause bounds invalidation
    # reset sampler and sample from one of the original warmup directions
    # if that occurs. Also reset if we got stuck.
    if (np.any(sampler._bounds_dist(p) < -sampler.bounds_tol) or
            np.abs(np.abs(alpha_range).max() * delta).max() <
            sampler.bounds_tol):
        if tries > MAX_TRIES:
            raise RuntimeError("Can not escape sampling region, model seems"
                               " numerically unstable :( Reporting the "
                               "model to "
                               "https://github.com/opencobra/cobrapy/issues "
                               "will help us to fix this :)")
        LOGGER.info("found bounds infeasibility in sample, "
                    "resetting to center")
        newdir = sampler.warmup[np.random.randint(sampler.n_warmup)]
        sampler.retries += 1

        return step(sampler, sampler.center, newdir - sampler.center, None,
                    tries + 1)
    return p

Sample a new feasible point from the point x in direction delta .


def __build_problem(self):
        """Build the matrix representation of the sampling problem."""

        # Set up the mathematical problem
        prob = constraint_matrices(self.model, zero_tol=self.feasibility_tol)

        # check if there any non-zero equality constraints
        equalities = prob.equalities
        b = prob.b
        bounds = np.atleast_2d(prob.bounds).T
        var_bounds = np.atleast_2d(prob.variable_bounds).T
        homogeneous = all(np.abs(b) < self.feasibility_tol)
        fixed_non_zero = np.abs(prob.variable_bounds[:, 1]) > \
            self.feasibility_tol
        fixed_non_zero &= prob.variable_fixed

        # check if there are any non-zero fixed variables, add them as
        # equalities to the stoichiometric matrix
        if any(fixed_non_zero):
            n_fixed = fixed_non_zero.sum()
            rows = np.zeros((n_fixed, prob.equalities.shape[1]))
            rows[range(n_fixed), np.where(fixed_non_zero)] = 1.0
            equalities = np.vstack([equalities, rows])
            var_b = prob.variable_bounds[:, 1]
            b = np.hstack([b, var_b[fixed_non_zero]])
            homogeneous = False

        # Set up a projection that can cast point into the nullspace
        nulls = nullspace(equalities)

        # convert bounds to a matrix and add variable bounds as well
        return Problem(
            equalities=shared_np_array(equalities.shape, equalities),
            b=shared_np_array(b.shape, b),
            inequalities=shared_np_array(prob.inequalities.shape,
                                         prob.inequalities),
            bounds=shared_np_array(bounds.shape, bounds),
            variable_fixed=shared_np_array(prob.variable_fixed.shape,
                                           prob.variable_fixed, integer=True),
            variable_bounds=shared_np_array(var_bounds.shape, var_bounds),
            nullspace=shared_np_array(nulls.shape, nulls),
            homogeneous=homogeneous
        )

def __build_problem ( self ) : prob = constraint_matrices ( self . model , zero_tol = self . feasibility_tol ) equalities = prob . equalities b = prob . b bounds = np . atleast_2d ( prob . bounds ) . T var_bounds = np . atleast_2d ( prob . variable_bounds ) . T homogeneous = all ( np . abs ( b ) < self . feasibility_tol ) fixed_non_zero = np . abs ( prob . variable_bounds [ : , 1 ] ) > self . feasibility_tol fixed_non_zero &= prob . variable_fixed if any ( fixed_non_zero ) : n_fixed = fixed_non_zero . sum ( ) rows = np . zeros ( ( n_fixed , prob . equalities . shape [ 1 ] ) ) rows [ range ( n_fixed ) , np . where ( fixed_non_zero ) ] = 1.0 equalities = np . vstack ( [ equalities , rows ] ) var_b = prob . variable_bounds [ : , 1 ] b = np . hstack ( [ b , var_b [ fixed_non_zero ] ] ) homogeneous = False nulls = nullspace ( equalities ) return Problem ( equalities = shared_np_array ( equalities . shape , equalities ) , b = shared_np_array ( b . shape , b ) , inequalities = shared_np_array ( prob . inequalities . shape , prob . inequalities ) , bounds = shared_np_array ( bounds . shape , bounds ) , variable_fixed = shared_np_array ( prob . variable_fixed . shape , prob . variable_fixed , integer = True ) , variable_bounds = shared_np_array ( var_bounds . shape , var_bounds ) , nullspace = shared_np_array ( nulls . shape , nulls ) , homogeneous = homogeneous )

Build the matrix representation of the sampling problem .


def generate_fva_warmup(self):
        """Generate the warmup points for the sampler.

        Generates warmup points by setting each flux as the sole objective
        and minimizing/maximizing it. Also caches the projection of the
        warmup points into the nullspace for non-homogeneous problems (only
        if necessary).

        """

        self.n_warmup = 0
        reactions = self.model.reactions
        self.warmup = np.zeros((2 * len(reactions), len(self.model.variables)))
        self.model.objective = Zero

        for sense in ("min", "max"):
            self.model.objective_direction = sense

            for i, r in enumerate(reactions):
                variables = (self.model.variables[self.fwd_idx[i]],
                             self.model.variables[self.rev_idx[i]])

                # Omit fixed reactions if they are non-homogeneous
                if r.upper_bound - r.lower_bound < self.bounds_tol:
                    LOGGER.info("skipping fixed reaction %s" % r.id)
                    continue

                self.model.objective.set_linear_coefficients(
                    {variables[0]: 1, variables[1]: -1})

                self.model.slim_optimize()

                if not self.model.solver.status == OPTIMAL:
                    LOGGER.info("can not maximize reaction %s, skipping it" %
                                r.id)
                    continue

                primals = self.model.solver.primal_values
                sol = [primals[v.name] for v in self.model.variables]
                self.warmup[self.n_warmup, ] = sol
                self.n_warmup += 1

                # Reset objective
                self.model.objective.set_linear_coefficients(
                    {variables[0]: 0, variables[1]: 0})

        # Shrink to measure
        self.warmup = self.warmup[0:self.n_warmup, :]

        # Remove redundant search directions
        keep = np.logical_not(self._is_redundant(self.warmup))
        self.warmup = self.warmup[keep, :]
        self.n_warmup = self.warmup.shape[0]

        # Catch some special cases
        if len(self.warmup.shape) == 1 or self.warmup.shape[0] == 1:
            raise ValueError("Your flux cone consists only of a single point!")
        elif self.n_warmup == 2:
            if not self.problem.homogeneous:
                raise ValueError("Can not sample from an inhomogenous problem"
                                 " with only 2 search directions :(")
            LOGGER.info("All search directions on a line, adding another one.")
            newdir = self.warmup.T.dot([0.25, 0.25])
            self.warmup = np.vstack([self.warmup, newdir])
            self.n_warmup += 1

        # Shrink warmup points to measure
        self.warmup = shared_np_array(
            (self.n_warmup, len(self.model.variables)), self.warmup)

Generate the warmup points for the sampler .


def _reproject(self, p):
        """Reproject a point into the feasibility region.

        This function is guaranteed to return a new feasible point. However,
        no guarantees in terms of proximity to the original point can be made.

        Parameters
        ----------
        p : numpy.array
            The current sample point.

        Returns
        -------
        numpy.array
            A new feasible point. If `p` was feasible it wil return p.

        """

        nulls = self.problem.nullspace
        equalities = self.problem.equalities

        # don't reproject if point is feasible
        if np.allclose(equalities.dot(p), self.problem.b,
                       rtol=0, atol=self.feasibility_tol):
            new = p
        else:
            LOGGER.info("feasibility violated in sample"
                        " %d, trying to reproject" % self.n_samples)
            new = nulls.dot(nulls.T.dot(p))

        # Projections may violate bounds
        # set to random point in space in that case
        if any(new != p):
            LOGGER.info("reprojection failed in sample"
                        " %d, using random point in space" % self.n_samples)
            new = self._random_point()

        return new

def
_reproject
(
self
,
p
)
:
nulls
=
self
.
problem
.
nullspace
equalities
=
self
.
problem
.
equalities
if
np
.
allclose
(
equalities
.
dot
(
p
)
,
self
.
problem
.
b
,
rtol
=
0
,
atol
=
self
.
feasibility_tol
)
:
new
=
p
else
:
LOGGER
.
info
(
"feasibility violated in sample"
" %d, trying to reproject"
%
self
.
n_samples
)
new
=
nulls
.
dot
(
nulls
.
T
.
dot
(
p
)
)
if
any
(
new
!=
p
)
:
LOGGER
.
info
(
"reprojection failed in sample"
" %d, using random point in space"
%
self
.
n_samples
)
new
=
self
.
_random_point
(
)
return
new

Reproject a point into the feasibility region .


def _random_point(self):
        """Find an approximately random point in the flux cone."""

        idx = np.random.randint(self.n_warmup,
                                size=min(2, np.ceil(np.sqrt(self.n_warmup))))
        return self.warmup[idx, :].mean(axis=0)

def _random_point ( self ) : idx = np . random . randint ( self . n_warmup , size = min ( 2 , np . ceil ( np . sqrt ( self . n_warmup ) ) ) ) return self . warmup [ idx , : ] . mean ( axis = 0 )

Find an approximately random point in the flux cone .


def _is_redundant(self, matrix, cutoff=None):
        """Identify rdeundant rows in a matrix that can be removed."""

        cutoff = 1.0 - self.feasibility_tol

        # Avoid zero variances
        extra_col = matrix[:, 0] + 1

        # Avoid zero rows being correlated with constant rows
        extra_col[matrix.sum(axis=1) == 0] = 2
        corr = np.corrcoef(np.c_[matrix, extra_col])
        corr = np.tril(corr, -1)

        return (np.abs(corr) > cutoff).any(axis=1)

def _is_redundant ( self , matrix , cutoff = None ) : cutoff = 1.0 - self . feasibility_tol extra_col = matrix [ : , 0 ] + 1 extra_col [ matrix . sum ( axis = 1 ) == 0 ] = 2 corr = np . corrcoef ( np . c_ [ matrix , extra_col ] ) corr = np . tril ( corr , - 1 ) return ( np . abs ( corr ) > cutoff ) . any ( axis = 1 )

Identify rdeundant rows in a matrix that can be removed .


def _bounds_dist(self, p):
        """Get the lower and upper bound distances. Negative is bad."""

        prob = self.problem
        lb_dist = (p - prob.variable_bounds[0, ]).min()
        ub_dist = (prob.variable_bounds[1, ] - p).min()

        if prob.bounds.shape[0] > 0:
            const = prob.inequalities.dot(p)
            const_lb_dist = (const - prob.bounds[0, ]).min()
            const_ub_dist = (prob.bounds[1, ] - const).min()
            lb_dist = min(lb_dist, const_lb_dist)
            ub_dist = min(ub_dist, const_ub_dist)

        return np.array([lb_dist, ub_dist])

def _bounds_dist ( self , p ) : prob = self . problem lb_dist = ( p - prob . variable_bounds [ 0 , ] ) . min ( ) ub_dist = ( prob . variable_bounds [ 1 , ] - p ) . min ( ) if prob . bounds . shape [ 0 ] > 0 : const = prob . inequalities . dot ( p ) const_lb_dist = ( const - prob . bounds [ 0 , ] ) . min ( ) const_ub_dist = ( prob . bounds [ 1 , ] - const ) . min ( ) lb_dist = min ( lb_dist , const_lb_dist ) ub_dist = min ( ub_dist , const_ub_dist ) return np . array ( [ lb_dist , ub_dist ] )

Get the lower and upper bound distances . Negative is bad .


def batch(self, batch_size, batch_num, fluxes=True):
        """Create a batch generator.

        This is useful to generate n batches of m samples each.

        Parameters
        ----------
        batch_size : int
            The number of samples contained in each batch (m).
        batch_num : int
            The number of batches in the generator (n).
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Yields
        ------
        pandas.DataFrame
            A DataFrame with dimensions (batch_size x n_r) containing
            a valid flux sample for a total of n_r reactions (or variables if
            fluxes=False) in each row.

        """

        for i in range(batch_num):
            yield self.sample(batch_size, fluxes=fluxes)

def batch ( self , batch_size , batch_num , fluxes = True ) : for i in range ( batch_num ) : yield self . sample ( batch_size , fluxes = fluxes )


def validate(self, samples):
        """Validate a set of samples for equality and inequality feasibility.

        Can be used to check whether the generated samples and warmup points
        are feasible.

        Parameters
        ----------
        samples : numpy.matrix
            Must be of dimension (n_samples x n_reactions). Contains the
            samples to be validated. Samples must be from fluxes.

        Returns
        -------
        numpy.array
            A one-dimensional numpy array of length containing
            a code of 1 to 3 letters denoting the validation result:

            - 'v' means feasible in bounds and equality constraints
            - 'l' means a lower bound violation
            - 'u' means a lower bound validation
            - 'e' means and equality constraint violation

        """

        samples = np.atleast_2d(samples)
        prob = self.problem

        if samples.shape[1] == len(self.model.reactions):
            S = create_stoichiometric_matrix(self.model)
            b = np.array([self.model.constraints[m.id].lb for m in
                          self.model.metabolites])
            bounds = np.array([r.bounds for r in self.model.reactions]).T
        elif samples.shape[1] == len(self.model.variables):
            S = prob.equalities
            b = prob.b
            bounds = prob.variable_bounds
        else:
            raise ValueError("Wrong number of columns. samples must have a "
                             "column for each flux or variable defined in the "
                             "model!")

        feasibility = np.abs(S.dot(samples.T).T - b).max(axis=1)
        lb_error = (samples - bounds[0, ]).min(axis=1)
        ub_error = (bounds[1, ] - samples).min(axis=1)

        if (samples.shape[1] == len(self.model.variables) and
                prob.inequalities.shape[0]):
            consts = prob.inequalities.dot(samples.T)
            lb_error = np.minimum(
                lb_error,
                (consts - prob.bounds[0, ]).min(axis=1))
            ub_error = np.minimum(
                ub_error,
                (prob.bounds[1, ] - consts).min(axis=1)
            )

        valid = (
            (feasibility < self.feasibility_tol) &
            (lb_error > -self.bounds_tol) &
            (ub_error > -self.bounds_tol))
        codes = np.repeat("", valid.shape[0]).astype(np.dtype((str, 3)))
        codes[valid] = "v"
        codes[lb_error <= -self.bounds_tol] = np.char.add(
            codes[lb_error <= -self.bounds_tol], "l")
        codes[ub_error <= -self.bounds_tol] = np.char.add(
            codes[ub_error <= -self.bounds_tol], "u")
        codes[feasibility > self.feasibility_tol] = np.char.add(
            codes[feasibility > self.feasibility_tol], "e")

        return codes

Validate a set of samples for equality and inequality feasibility .


def prune_unused_metabolites(cobra_model):
    """Remove metabolites that are not involved in any reactions and
    returns pruned model

    Parameters
    ----------
    cobra_model: class:`~cobra.core.Model.Model` object
        the model to remove unused metabolites from

    Returns
    -------
    output_model: class:`~cobra.core.Model.Model` object
        input model with unused metabolites removed
    inactive_metabolites: list of class:`~cobra.core.reaction.Reaction`
        list of metabolites that were removed
    """

    output_model = cobra_model.copy()
    inactive_metabolites = [m for m in output_model.metabolites
                            if len(m.reactions) == 0]
    output_model.remove_metabolites(inactive_metabolites)
    return output_model, inactive_metabolites

def prune_unused_metabolites ( cobra_model ) : output_model = cobra_model . copy ( ) inactive_metabolites = [ m for m in output_model . metabolites if len ( m . reactions ) == 0 ] output_model . remove_metabolites ( inactive_metabolites ) return output_model , inactive_metabolites


def prune_unused_reactions(cobra_model):
    """Remove reactions with no assigned metabolites, returns pruned model

    Parameters
    ----------
    cobra_model: class:`~cobra.core.Model.Model` object
        the model to remove unused reactions from

    Returns
    -------
    output_model: class:`~cobra.core.Model.Model` object
        input model with unused reactions removed
    reactions_to_prune: list of class:`~cobra.core.reaction.Reaction`
        list of reactions that were removed
    """

    output_model = cobra_model.copy()
    reactions_to_prune = [r for r in output_model.reactions
                          if len(r.metabolites) == 0]
    output_model.remove_reactions(reactions_to_prune)
    return output_model, reactions_to_prune

def prune_unused_reactions ( cobra_model ) : output_model = cobra_model . copy ( ) reactions_to_prune = [ r for r in output_model . reactions if len ( r . metabolites ) == 0 ] output_model . remove_reactions ( reactions_to_prune ) return output_model , reactions_to_prune

Remove reactions with no assigned metabolites returns pruned model


def undelete_model_genes(cobra_model):
    """Undoes the effects of a call to delete_model_genes in place.

    cobra_model:  A cobra.Model which will be modified in place

    """

    if cobra_model._trimmed_genes is not None:
        for x in cobra_model._trimmed_genes:
            x.functional = True

    if cobra_model._trimmed_reactions is not None:
        for the_reaction, (lower_bound, upper_bound) in \
                cobra_model._trimmed_reactions.items():
            the_reaction.lower_bound = lower_bound
            the_reaction.upper_bound = upper_bound

    cobra_model._trimmed_genes = []
    cobra_model._trimmed_reactions = {}
    cobra_model._trimmed = False

def undelete_model_genes ( cobra_model ) : if cobra_model . _trimmed_genes is not None : for x in cobra_model . _trimmed_genes : x . functional = True if cobra_model . _trimmed_reactions is not None : for the_reaction , ( lower_bound , upper_bound ) in cobra_model . _trimmed_reactions . items ( ) : the_reaction . lower_bound = lower_bound the_reaction . upper_bound = upper_bound cobra_model . _trimmed_genes = [ ] cobra_model . _trimmed_reactions = { } cobra_model . _trimmed = False

Undoes the effects of a call to delete_model_genes in place .


def find_gene_knockout_reactions(cobra_model, gene_list,
                                 compiled_gene_reaction_rules=None):
    """identify reactions which will be disabled when the genes are knocked out

    cobra_model: :class:`~cobra.core.Model.Model`

    gene_list: iterable of :class:`~cobra.core.Gene.Gene`

    compiled_gene_reaction_rules: dict of {reaction_id: compiled_string}
        If provided, this gives pre-compiled gene_reaction_rule strings.
        The compiled rule strings can be evaluated much faster. If a rule
        is not provided, the regular expression evaluation will be used.
        Because not all gene_reaction_rule strings can be evaluated, this
        dict must exclude any rules which can not be used with eval.

    """
    potential_reactions = set()
    for gene in gene_list:
        if isinstance(gene, string_types):
            gene = cobra_model.genes.get_by_id(gene)
        potential_reactions.update(gene._reaction)
    gene_set = {str(i) for i in gene_list}
    if compiled_gene_reaction_rules is None:
        compiled_gene_reaction_rules = {r: parse_gpr(r.gene_reaction_rule)[0]
                                        for r in potential_reactions}

    return [r for r in potential_reactions
            if not eval_gpr(compiled_gene_reaction_rules[r], gene_set)]

def find_gene_knockout_reactions ( cobra_model , gene_list , compiled_gene_reaction_rules = None ) : potential_reactions = set ( ) for gene in gene_list : if isinstance ( gene , string_types ) : gene = cobra_model . genes . get_by_id ( gene ) potential_reactions . update ( gene . _reaction ) gene_set = { str ( i ) for i in gene_list } if compiled_gene_reaction_rules is None : compiled_gene_reaction_rules = { r : parse_gpr ( r . gene_reaction_rule ) [ 0 ] for r in potential_reactions } return [ r for r in potential_reactions if not eval_gpr ( compiled_gene_reaction_rules [ r ] , gene_set ) ]


def remove_genes(cobra_model, gene_list, remove_reactions=True):
    """remove genes entirely from the model

    This will also simplify all gene_reaction_rules with this
    gene inactivated."""
    gene_set = {cobra_model.genes.get_by_id(str(i)) for i in gene_list}
    gene_id_set = {i.id for i in gene_set}
    remover = _GeneRemover(gene_id_set)
    ast_rules = get_compiled_gene_reaction_rules(cobra_model)
    target_reactions = []
    for reaction, rule in iteritems(ast_rules):
        if reaction.gene_reaction_rule is None or \
                len(reaction.gene_reaction_rule) == 0:
            continue
        # reactions to remove
        if remove_reactions and not eval_gpr(rule, gene_id_set):
            target_reactions.append(reaction)
        else:
            # if the reaction is not removed, remove the gene
            # from its gpr
            remover.visit(rule)
            new_rule = ast2str(rule)
            if new_rule != reaction.gene_reaction_rule:
                reaction.gene_reaction_rule = new_rule
    for gene in gene_set:
        cobra_model.genes.remove(gene)
        # remove reference to the gene in all groups
        associated_groups = cobra_model.get_associated_groups(gene)
        for group in associated_groups:
            group.remove_members(gene)
    cobra_model.remove_reactions(target_reactions)

def remove_genes ( cobra_model , gene_list , remove_reactions = True ) : gene_set = { cobra_model . genes . get_by_id ( str ( i ) ) for i in gene_list } gene_id_set = { i . id for i in gene_set } remover = _GeneRemover ( gene_id_set ) ast_rules = get_compiled_gene_reaction_rules ( cobra_model ) target_reactions = [ ] for reaction , rule in iteritems ( ast_rules ) : if reaction . gene_reaction_rule is None or len ( reaction . gene_reaction_rule ) == 0 : continue if remove_reactions and not eval_gpr ( rule , gene_id_set ) : target_reactions . append ( reaction ) else : remover . visit ( rule ) new_rule = ast2str ( rule ) if new_rule != reaction . gene_reaction_rule : reaction . gene_reaction_rule = new_rule for gene in gene_set : cobra_model . genes . remove ( gene ) associated_groups = cobra_model . get_associated_groups ( gene ) for group in associated_groups : group . remove_members ( gene ) cobra_model . remove_reactions ( target_reactions )


def gapfill(model, universal=None, lower_bound=0.05,
            penalties=None, demand_reactions=True, exchange_reactions=False,
            iterations=1):
    """Perform gapfilling on a model.

    See documentation for the class GapFiller.

    Parameters
    ----------
    model : cobra.Model
        The model to perform gap filling on.
    universal : cobra.Model, None
        A universal model with reactions that can be used to complete the
        model. Only gapfill considering demand and exchange reactions if
        left missing.
    lower_bound : float
        The minimally accepted flux for the objective in the filled model.
    penalties : dict, None
        A dictionary with keys being 'universal' (all reactions included in
        the universal model), 'exchange' and 'demand' (all additionally
        added exchange and demand reactions) for the three reaction types.
        Can also have reaction identifiers for reaction specific costs.
        Defaults are 1, 100 and 1 respectively.
    iterations : int
        The number of rounds of gapfilling to perform. For every iteration,
        the penalty for every used reaction increases linearly. This way,
        the algorithm is encouraged to search for alternative solutions
        which may include previously used reactions. I.e., with enough
        iterations pathways including 10 steps will eventually be reported
        even if the shortest pathway is a single reaction.
    exchange_reactions : bool
        Consider adding exchange (uptake) reactions for all metabolites
        in the model.
    demand_reactions : bool
        Consider adding demand reactions for all metabolites.

    Returns
    -------
    iterable
        list of lists with on set of reactions that completes the model per
        requested iteration.

    Examples
    --------
    >>> import cobra.test as ct
    >>> from cobra import Model
    >>> from cobra.flux_analysis import gapfill
    >>> model = ct.create_test_model("salmonella")
    >>> universal = Model('universal')
    >>> universal.add_reactions(model.reactions.GF6PTA.copy())
    >>> model.remove_reactions([model.reactions.GF6PTA])
    >>> gapfill(model, universal)
    """
    gapfiller = GapFiller(model, universal=universal,
                          lower_bound=lower_bound, penalties=penalties,
                          demand_reactions=demand_reactions,
                          exchange_reactions=exchange_reactions)
    return gapfiller.fill(iterations=iterations)

def gapfill ( model , universal = None , lower_bound = 0.05 , penalties = None , demand_reactions = True , exchange_reactions = False , iterations = 1 ) : gapfiller = GapFiller ( model , universal = universal , lower_bound = lower_bound , penalties = penalties , demand_reactions = demand_reactions , exchange_reactions = exchange_reactions ) return gapfiller . fill ( iterations = iterations )


def extend_model(self, exchange_reactions=False, demand_reactions=True):
        """Extend gapfilling model.

        Add reactions from universal model and optionally exchange and
        demand reactions for all metabolites in the model to perform
        gapfilling on.

        Parameters
        ----------
        exchange_reactions : bool
            Consider adding exchange (uptake) reactions for all metabolites
            in the model.
        demand_reactions : bool
            Consider adding demand reactions for all metabolites.
        """
        for rxn in self.universal.reactions:
            rxn.gapfilling_type = 'universal'
        new_metabolites = self.universal.metabolites.query(
            lambda metabolite: metabolite not in self.model.metabolites
                                                           )
        self.model.add_metabolites(new_metabolites)
        existing_exchanges = []
        for rxn in self.universal.boundary:
            existing_exchanges = existing_exchanges + \
                [met.id for met in list(rxn.metabolites)]

        for met in self.model.metabolites:
            if exchange_reactions:
                # check for exchange reaction in model already
                if met.id not in existing_exchanges:
                    rxn = self.universal.add_boundary(
                        met, type='exchange_smiley', lb=-1000, ub=0,
                        reaction_id='EX_{}'.format(met.id))
                    rxn.gapfilling_type = 'exchange'
            if demand_reactions:
                rxn = self.universal.add_boundary(
                    met, type='demand_smiley', lb=0, ub=1000,
                    reaction_id='DM_{}'.format(met.id))
                rxn.gapfilling_type = 'demand'

        new_reactions = self.universal.reactions.query(
            lambda reaction: reaction not in self.model.reactions
        )
        self.model.add_reactions(new_reactions)

def extend_model ( self , exchange_reactions = False , demand_reactions = True ) : for rxn in self . universal . reactions : rxn . gapfilling_type = 'universal' new_metabolites = self . universal . metabolites . query ( lambda metabolite : metabolite not in self . model . metabolites ) self . model . add_metabolites ( new_metabolites ) existing_exchanges = [ ] for rxn in self . universal . boundary : existing_exchanges = existing_exchanges + [ met . id for met in list ( rxn . metabolites ) ] for met in self . model . metabolites : if exchange_reactions : if met . id not in existing_exchanges : rxn = self . universal . add_boundary ( met , type = 'exchange_smiley' , lb = - 1000 , ub = 0 , reaction_id = 'EX_{}' . format ( met . id ) ) rxn . gapfilling_type = 'exchange' if demand_reactions : rxn = self . universal . add_boundary ( met , type = 'demand_smiley' , lb = 0 , ub = 1000 , reaction_id = 'DM_{}' . format ( met . id ) ) rxn . gapfilling_type = 'demand' new_reactions = self . universal . reactions . query ( lambda reaction : reaction not in self . model . reactions ) self . model . add_reactions ( new_reactions )


def update_costs(self):
        """Update the coefficients for the indicator variables in the objective.

        Done incrementally so that second time the function is called,
        active indicators in the current solutions gets higher cost than the
        unused indicators.
        """
        for var in self.indicators:
            if var not in self.costs:
                self.costs[var] = var.cost
            else:
                if var._get_primal() > self.integer_threshold:
                    self.costs[var] += var.cost
        self.model.objective.set_linear_coefficients(self.costs)

def update_costs ( self ) : for var in self . indicators : if var not in self . costs : self . costs [ var ] = var . cost else : if var . _get_primal ( ) > self . integer_threshold : self . costs [ var ] += var . cost self . model . objective . set_linear_coefficients ( self . costs )

Update the coefficients for the indicator variables in the objective .


def add_switches_and_objective(self):
        """ Update gapfilling model with switches and the indicator objective.
        """
        constraints = list()
        big_m = max(max(abs(b) for b in r.bounds)
                    for r in self.model.reactions)
        prob = self.model.problem
        for rxn in self.model.reactions:
            if not hasattr(rxn, 'gapfilling_type'):
                continue
            indicator = prob.Variable(
                name='indicator_{}'.format(rxn.id), lb=0, ub=1, type='binary')
            if rxn.id in self.penalties:
                indicator.cost = self.penalties[rxn.id]
            else:
                indicator.cost = self.penalties[rxn.gapfilling_type]
            indicator.rxn_id = rxn.id
            self.indicators.append(indicator)

            # if z = 1 v_i is allowed non-zero
            # v_i - Mz <= 0   and   v_i + Mz >= 0
            constraint_lb = prob.Constraint(
                rxn.flux_expression - big_m * indicator, ub=0,
                name='constraint_lb_{}'.format(rxn.id), sloppy=True)
            constraint_ub = prob.Constraint(
                rxn.flux_expression + big_m * indicator, lb=0,
                name='constraint_ub_{}'.format(rxn.id), sloppy=True)

            constraints.extend([constraint_lb, constraint_ub])

        self.model.add_cons_vars(self.indicators)
        self.model.add_cons_vars(constraints, sloppy=True)
        self.model.objective = prob.Objective(
            Zero, direction='min', sloppy=True)
        self.model.objective.set_linear_coefficients({
            i: 1 for i in self.indicators})
        self.update_costs()

def add_switches_and_objective ( self ) : constraints = list ( ) big_m = max ( max ( abs ( b ) for b in r . bounds ) for r in self . model . reactions ) prob = self . model . problem for rxn in self . model . reactions : if not hasattr ( rxn , 'gapfilling_type' ) : continue indicator = prob . Variable ( name = 'indicator_{}' . format ( rxn . id ) , lb = 0 , ub = 1 , type = 'binary' ) if rxn . id in self . penalties : indicator . cost = self . penalties [ rxn . id ] else : indicator . cost = self . penalties [ rxn . gapfilling_type ] indicator . rxn_id = rxn . id self . indicators . append ( indicator ) constraint_lb = prob . Constraint ( rxn . flux_expression - big_m * indicator , ub = 0 , name = 'constraint_lb_{}' . format ( rxn . id ) , sloppy = True ) constraint_ub = prob . Constraint ( rxn . flux_expression + big_m * indicator , lb = 0 , name = 'constraint_ub_{}' . format ( rxn . id ) , sloppy = True ) constraints . extend ( [ constraint_lb , constraint_ub ] ) self . model . add_cons_vars ( self . indicators ) self . model . add_cons_vars ( constraints , sloppy = True ) self . model . objective = prob . Objective ( Zero , direction = 'min' , sloppy = True ) self . model . objective . set_linear_coefficients ( { i : 1 for i in self . indicators } ) self . update_costs ( )

Update gapfilling model with switches and the indicator objective .


def fill(self, iterations=1):
        """Perform the gapfilling by iteratively solving the model, updating
        the costs and recording the used reactions.

        Parameters
        ----------
        iterations : int
            The number of rounds of gapfilling to perform. For every
            iteration, the penalty for every used reaction increases
            linearly. This way, the algorithm is encouraged to search for
            alternative solutions which may include previously used
            reactions. I.e., with enough iterations pathways including 10
            steps will eventually be reported even if the shortest pathway
            is a single reaction.

        Returns
        -------
        iterable
            A list of lists where each element is a list reactions that were
            used to gapfill the model.

        Raises
        ------
        RuntimeError
            If the model fails to be validated (i.e. the original model with
            the proposed reactions added, still cannot get the required flux
            through the objective).
        """
        used_reactions = list()
        for i in range(iterations):
            self.model.slim_optimize(error_value=None,
                                     message='gapfilling optimization failed')
            solution = [self.model.reactions.get_by_id(ind.rxn_id)
                        for ind in self.indicators if
                        ind._get_primal() > self.integer_threshold]
            if not self.validate(solution):
                raise RuntimeError('failed to validate gapfilled model, '
                                   'try lowering the integer_threshold')
            used_reactions.append(solution)
            self.update_costs()
        return used_reactions

def
fill
(
self
,
iterations
=
1
)
:
used_reactions
=
list
(
)
for
i
in
range
(
iterations
)
:
self
.
model
.
slim_optimize
(
error_value
=
,
message
=
'gapfilling optimization failed'
)
solution
=
[
self
.
model
.
reactions
.
get_by_id
(
ind
.
rxn_id
)
for
ind
in
self
.
indicators
if
ind
.
_get_primal
(
)
>
self
.
integer_threshold
]
if
not
self
.
validate
(
solution
)
:
raise
RuntimeError
(
'failed to validate gapfilled model, '
'try lowering the integer_threshold'
)
used_reactions
.
append
(
solution
)
self
.
update_costs
(
)
return
used_reactions

Perform the gapfilling by iteratively solving the model updating the costs and recording the used reactions .


def find_external_compartment(model):
    """Find the external compartment in the model.

    Uses a simple heuristic where the external compartment should be the one
    with the most exchange reactions.

    Arguments
    ---------
    model : cobra.Model
        A cobra model.

    Returns
    -------
    str
        The putative external compartment.
    """
    if model.boundary:
        counts = pd.Series(tuple(r.compartments)[0] for r in model.boundary)
        most = counts.value_counts()
        most = most.index[most == most.max()].to_series()
    else:
        most = None
    like_external = compartment_shortlist["e"] + ["e"]
    matches = pd.Series([co in like_external for co in model.compartments],
                        index=model.compartments)

    if matches.sum() == 1:
        compartment = matches.index[matches][0]
        LOGGER.info("Compartment `%s` sounds like an external compartment. "
                    "Using this one without counting boundary reactions" %
                    compartment)
        return compartment
    elif most is not None and matches.sum() > 1 and matches[most].sum() == 1:
        compartment = most[matches[most]][0]
        LOGGER.warning("There are several compartments that look like an "
                       "external compartment but `%s` has the most boundary "
                       "reactions, so using that as the external "
                       "compartment." % compartment)
        return compartment
    elif matches.sum() > 1:
        raise RuntimeError("There are several compartments (%s) that look "
                           "like external compartments but we can't tell "
                           "which one to use. Consider renaming your "
                           "compartments please.")

    if most is not None:
        return most[0]
        LOGGER.warning("Could not identify an external compartment by name and"
                       " choosing one with the most boundary reactions. That "
                       "might be complete nonsense or change suddenly. "
                       "Consider renaming your compartments using "
                       "`Model.compartments` to fix this.")
    # No info in the model, so give up
    raise RuntimeError("The heuristic for discovering an external compartment "
                       "relies on names and boundary reactions. Yet, there "
                       "are neither compartments with recognized names nor "
                       "boundary reactions in the model.")

Find the external compartment in the model .


def is_boundary_type(reaction, boundary_type, external_compartment):
    """Check whether a reaction is an exchange reaction.

    Arguments
    ---------
    reaction : cobra.Reaction
        The reaction to check.
    boundary_type : str
        What boundary type to check for. Must be one of
        "exchange", "demand", or "sink".
    external_compartment : str
        The id for the external compartment.

    Returns
    -------
    boolean
        Whether the reaction looks like the requested type. Might be based
        on a heuristic.
    """
    # Check if the reaction has an annotation. Annotations dominate everything.
    sbo_term = reaction.annotation.get("sbo", "")
    if isinstance(sbo_term, list):
        sbo_term = sbo_term[0]
    sbo_term = sbo_term.upper()

    if sbo_term == sbo_terms[boundary_type]:
        return True
    if sbo_term in [sbo_terms[k] for k in sbo_terms if k != boundary_type]:
        return False

    # Check if the reaction is in the correct compartment (exterior or inside)
    correct_compartment = external_compartment in reaction.compartments
    if boundary_type != "exchange":
        correct_compartment = not correct_compartment

    # Check if the reaction has the correct reversibility
    rev_type = True
    if boundary_type == "demand":
        rev_type = not reaction.reversibility
    elif boundary_type == "sink":
        rev_type = reaction.reversibility

    return (reaction.boundary and not
            any(ex in reaction.id for ex in excludes[boundary_type]) and
            correct_compartment and rev_type)

def is_boundary_type ( reaction , boundary_type , external_compartment ) : sbo_term = reaction . annotation . get ( "sbo" , "" ) if isinstance ( sbo_term , list ) : sbo_term = sbo_term [ 0 ] sbo_term = sbo_term . upper ( ) if sbo_term == sbo_terms [ boundary_type ] : return True if sbo_term in [ sbo_terms [ k ] for k in sbo_terms if k != boundary_type ] : return False correct_compartment = external_compartment in reaction . compartments if boundary_type != "exchange" : correct_compartment = not correct_compartment rev_type = True if boundary_type == "demand" : rev_type = not reaction . reversibility elif boundary_type == "sink" : rev_type = reaction . reversibility return ( reaction . boundary and not any ( ex in reaction . id for ex in excludes [ boundary_type ] ) and correct_compartment and rev_type )

Check whether a reaction is an exchange reaction .


def find_boundary_types(model, boundary_type, external_compartment=None):
    """Find specific boundary reactions.

    Arguments
    ---------
    model : cobra.Model
        A cobra model.
    boundary_type : str
        What boundary type to check for. Must be one of
        "exchange", "demand", or "sink".
    external_compartment : str or None
        The id for the external compartment. If None it will be detected
        automatically.

    Returns
    -------
    list of cobra.reaction
        A list of likely boundary reactions of a user defined type.
    """
    if not model.boundary:
        LOGGER.warning("There are no boundary reactions in this model. "
                       "Therefore specific types of boundary reactions such "
                       "as 'exchanges', 'demands' or 'sinks' cannot be "
                       "identified.")
        return []
    if external_compartment is None:
        external_compartment = find_external_compartment(model)
    return model.reactions.query(
        lambda r: is_boundary_type(r, boundary_type, external_compartment))


def normalize_cutoff(model, zero_cutoff=None):
    """Return a valid zero cutoff value."""
    if zero_cutoff is None:
        return model.tolerance
    else:
        if zero_cutoff < model.tolerance:
            raise ValueError(
                "The chosen zero cutoff cannot be less than the model's "
                "tolerance value."
            )
        else:
            return zero_cutoff


def _sample_chain(args):
    """Sample a single chain for OptGPSampler.

    center and n_samples are updated locally and forgotten afterwards.

    """

    n, idx = args       # has to be this way to work in Python 2.7
    center = sampler.center
    np.random.seed((sampler._seed + idx) % np.iinfo(np.int32).max)
    pi = np.random.randint(sampler.n_warmup)

    prev = sampler.warmup[pi, ]
    prev = step(sampler, center, prev - center, 0.95)

    n_samples = max(sampler.n_samples, 1)
    samples = np.zeros((n, center.shape[0]))

    for i in range(1, sampler.thinning * n + 1):
        pi = np.random.randint(sampler.n_warmup)
        delta = sampler.warmup[pi, ] - center

        prev = step(sampler, prev, delta)

        if sampler.problem.homogeneous and (
                n_samples * sampler.thinning % sampler.nproj == 0):
            prev = sampler._reproject(prev)
            center = sampler._reproject(center)

        if i % sampler.thinning == 0:
            samples[i//sampler.thinning - 1, ] = prev

        center = ((n_samples * center) / (n_samples + 1) +
                  prev / (n_samples + 1))
        n_samples += 1

    return (sampler.retries, samples)

def _sample_chain ( args ) : n , idx = args center = sampler . center np . random . seed ( ( sampler . _seed + idx ) % np . iinfo ( np . int32 ) . max ) pi = np . random . randint ( sampler . n_warmup ) prev = sampler . warmup [ pi , ] prev = step ( sampler , center , prev - center , 0.95 ) n_samples = max ( sampler . n_samples , 1 ) samples = np . zeros ( ( n , center . shape [ 0 ] ) ) for i in range ( 1 , sampler . thinning * n + 1 ) : pi = np . random . randint ( sampler . n_warmup ) delta = sampler . warmup [ pi , ] - center prev = step ( sampler , prev , delta ) if sampler . problem . homogeneous and ( n_samples * sampler . thinning % sampler . nproj == 0 ) : prev = sampler . _reproject ( prev ) center = sampler . _reproject ( center ) if i % sampler . thinning == 0 : samples [ i // sampler . thinning - 1 , ] = prev center = ( ( n_samples * center ) / ( n_samples + 1 ) + prev / ( n_samples + 1 ) ) n_samples += 1 return ( sampler . retries , samples )

Sample a single chain for OptGPSampler .


def ast2str(expr, level=0, names=None):
    """convert compiled ast to gene_reaction_rule str

    Parameters
    ----------
    expr : str
        string for a gene reaction rule, e.g "a and b"
    level : int
        internal use only
    names : dict
        Dict where each element id a gene identifier and the value is the
        gene name. Use this to get a rule str which uses names instead. This
        should be done for display purposes only. All gene_reaction_rule
        strings which are computed with should use the id.

    Returns
    ------
    string
        The gene reaction rule
    """
    if isinstance(expr, Expression):
        return ast2str(expr.body, 0, names) \
            if hasattr(expr, "body") else ""
    elif isinstance(expr, Name):
        return names.get(expr.id, expr.id) if names else expr.id
    elif isinstance(expr, BoolOp):
        op = expr.op
        if isinstance(op, Or):
            str_exp = " or ".join(ast2str(i, level + 1, names)
                                  for i in expr.values)
        elif isinstance(op, And):
            str_exp = " and ".join(ast2str(i, level + 1, names)
                                   for i in expr.values)
        else:
            raise TypeError("unsupported operation " + op.__class__.__name)
        return "(" + str_exp + ")" if level else str_exp
    elif expr is None:
        return ""
    else:
        raise TypeError("unsupported operation  " + repr(expr))

def
ast2str
(
expr
,
level
=
0
,
names
=
)
:
if
isinstance
(
expr
,
Expression
)
:
return
ast2str
(
expr
.
body
,
0
,
names
)
if
hasattr
(
expr
,
"body"
)
else
""
elif
isinstance
(
expr
,
Name
)
:
return
names
.
get
(
expr
.
id
,
expr
.
id
)
if
names
else
expr
.
id
elif
isinstance
(
expr
,
BoolOp
)
:
op
=
expr
.
op
if
isinstance
(
op
,
Or
)
:
str_exp
=
" or "
.
join
(
ast2str
(
i
,
level
+
1
,
names
)
for
i
in
expr
.
values
)
elif
isinstance
(
op
,
And
)
:
str_exp
=
" and "
.
join
(
ast2str
(
i
,
level
+
1
,
names
)
for
i
in
expr
.
values
)
else
:
raise
TypeError
(
"unsupported operation "
+
op
.
__class__
.
__name
)
return
"("
+
str_exp
+
")"
if
level
else
str_exp
elif
expr
is
:
return
""
else
:
raise
TypeError
(
"unsupported operation  "
+
repr
(
expr
)
)


def eval_gpr(expr, knockouts):
    """evaluate compiled ast of gene_reaction_rule with knockouts

    Parameters
    ----------
    expr : Expression
        The ast of the gene reaction rule
    knockouts : DictList, set
        Set of genes that are knocked out

    Returns
    -------
    bool
        True if the gene reaction rule is true with the given knockouts
        otherwise false
    """
    if isinstance(expr, Expression):
        return eval_gpr(expr.body, knockouts)
    elif isinstance(expr, Name):
        return expr.id not in knockouts
    elif isinstance(expr, BoolOp):
        op = expr.op
        if isinstance(op, Or):
            return any(eval_gpr(i, knockouts) for i in expr.values)
        elif isinstance(op, And):
            return all(eval_gpr(i, knockouts) for i in expr.values)
        else:
            raise TypeError("unsupported operation " + op.__class__.__name__)
    elif expr is None:
        return True
    else:
        raise TypeError("unsupported operation  " + repr(expr))

def
eval_gpr
(
expr
,
knockouts
)
:
if
isinstance
(
expr
,
Expression
)
:
return
eval_gpr
(
expr
.
body
,
knockouts
)
elif
isinstance
(
expr
,
Name
)
:
return
expr
.
id
not
in
knockouts
elif
isinstance
(
expr
,
BoolOp
)
:
op
=
expr
.
op
if
isinstance
(
op
,
Or
)
:
return
any
(
eval_gpr
(
i
,
knockouts
)
for
i
in
expr
.
values
)
elif
isinstance
(
op
,
And
)
:
return
all
(
eval_gpr
(
i
,
knockouts
)
for
i
in
expr
.
values
)
else
:
raise
TypeError
(
"unsupported operation "
+
op
.
__class__
.
__name__
)
elif
expr
is
:
return
True
else
:
raise
TypeError
(
"unsupported operation  "
+
repr
(
expr
)
)


def parse_gpr(str_expr):
    """parse gpr into AST

    Parameters
    ----------
    str_expr : string
        string with the gene reaction rule to parse

    Returns
    -------
    tuple
        elements ast_tree and gene_ids as a set
    """
    str_expr = str_expr.strip()
    if len(str_expr) == 0:
        return None, set()
    for char, escaped in replacements:
        if char in str_expr:
            str_expr = str_expr.replace(char, escaped)
    escaped_str = keyword_re.sub("__cobra_escape__", str_expr)
    escaped_str = number_start_re.sub("__cobra_escape__", escaped_str)
    tree = ast_parse(escaped_str, "<string>", "eval")
    cleaner = GPRCleaner()
    cleaner.visit(tree)
    eval_gpr(tree, set())  # ensure the rule can be evaluated
    return tree, cleaner.gene_set

def parse_gpr ( str_expr ) : str_expr = str_expr . strip ( ) if len ( str_expr ) == 0 : return None , set ( ) for char , escaped in replacements : if char in str_expr : str_expr = str_expr . replace ( char , escaped ) escaped_str = keyword_re . sub ( "__cobra_escape__" , str_expr ) escaped_str = number_start_re . sub ( "__cobra_escape__" , escaped_str ) tree = ast_parse ( escaped_str , "<string>" , "eval" ) cleaner = GPRCleaner ( ) cleaner . visit ( tree ) eval_gpr ( tree , set ( ) ) return tree , cleaner . gene_set


def knock_out(self):
        """Knockout gene by marking it as non-functional and setting all
        associated reactions bounds to zero.

        The change is reverted upon exit if executed within the model as
        context.
        """
        self.functional = False
        for reaction in self.reactions:
            if not reaction.functional:
                reaction.bounds = (0, 0)

def knock_out ( self ) : self . functional = False for reaction in self . reactions : if not reaction . functional : reaction . bounds = ( 0 , 0 )

Knockout gene by marking it as non - functional and setting all associated reactions bounds to zero .


def remove_from_model(self, model=None,
                          make_dependent_reactions_nonfunctional=True):
        """Removes the association

        Parameters
        ----------
        model : cobra model
           The model to remove the gene from
        make_dependent_reactions_nonfunctional : bool
           If True then replace the gene with 'False' in the gene
           association, else replace the gene with 'True'

        .. deprecated :: 0.4
            Use cobra.manipulation.delete_model_genes to simulate knockouts
            and cobra.manipulation.remove_genes to remove genes from
            the model.

        """
        warn("Use cobra.manipulation.remove_genes instead")
        if model is not None:
            if model != self._model:
                raise Exception("%s is a member of %s, not %s" %
                                (repr(self), repr(self._model), repr(model)))
        if self._model is None:
            raise Exception('%s is not in a model' % repr(self))

        if make_dependent_reactions_nonfunctional:
            gene_state = 'False'
        else:
            gene_state = 'True'
        the_gene_re = re.compile('(^|(?<=( |\()))%s(?=( |\)|$))' %
                                 re.escape(self.id))

        # remove reference to the gene in all groups
        associated_groups = self._model.get_associated_groups(self)
        for group in associated_groups:
            group.remove_members(self)

        self._model.genes.remove(self)
        self._model = None

        for the_reaction in list(self._reaction):
            the_reaction._gene_reaction_rule = the_gene_re.sub(
                gene_state, the_reaction.gene_reaction_rule)
            the_reaction._genes.remove(self)
            # Now, deactivate the reaction if its gene association evaluates
            # to False
            the_gene_reaction_relation = the_reaction.gene_reaction_rule
            for other_gene in the_reaction._genes:
                other_gene_re = re.compile('(^|(?<=( |\()))%s(?=( |\)|$))' %
                                           re.escape(other_gene.id))
                the_gene_reaction_relation = other_gene_re.sub(
                    'True',
                    the_gene_reaction_relation)

            if not eval(the_gene_reaction_relation):
                the_reaction.lower_bound = 0
                the_reaction.upper_bound = 0
        self._reaction.clear()


def add_moma(model, solution=None, linear=True):
    r"""Add constraints and objective representing for MOMA.

    This adds variables and constraints for the minimization of metabolic
    adjustment (MOMA) to the model.

    Parameters
    ----------
    model : cobra.Model
        The model to add MOMA constraints and objective to.
    solution : cobra.Solution, optional
        A previous solution to use as a reference. If no solution is given,
        one will be computed using pFBA.
    linear : bool, optional
        Whether to use the linear MOMA formulation or not (default True).

    Notes
    -----
    In the original MOMA [1]_ specification one looks for the flux distribution
    of the deletion (v^d) closest to the fluxes without the deletion (v).
    In math this means:

    minimize \sum_i (v^d_i - v_i)^2
    s.t. Sv^d = 0
         lb_i <= v^d_i <= ub_i

    Here, we use a variable transformation v^t := v^d_i - v_i. Substituting
    and using the fact that Sv = 0 gives:

    minimize \sum_i (v^t_i)^2
    s.t. Sv^d = 0
         v^t = v^d_i - v_i
         lb_i <= v^d_i <= ub_i

    So basically we just re-center the flux space at the old solution and then
    find the flux distribution closest to the new zero (center). This is the
    same strategy as used in cameo.

    In the case of linear MOMA [2]_, we instead minimize \sum_i abs(v^t_i). The
    linear MOMA is typically significantly faster. Also quadratic MOMA tends
    to give flux distributions in which all fluxes deviate from the reference
    fluxes a little bit whereas linear MOMA tends to give flux distributions
    where the majority of fluxes are the same reference with few fluxes
    deviating a lot (typical effect of L2 norm vs L1 norm).

    The former objective function is saved in the optlang solver interface as
    ``"moma_old_objective"`` and this can be used to immediately extract the
    value of the former objective after MOMA optimization.

    See Also
    --------
    pfba : parsimonious FBA

    References
    ----------
    .. [1] Segrè, Daniel, Dennis Vitkup, and George M. Church. “Analysis of
           Optimality in Natural and Perturbed Metabolic Networks.”
           Proceedings of the National Academy of Sciences 99, no. 23
           (November 12, 2002): 15112. https://doi.org/10.1073/pnas.232349399.
    .. [2] Becker, Scott A, Adam M Feist, Monica L Mo, Gregory Hannum,
           Bernhard Ø Palsson, and Markus J Herrgard. “Quantitative
           Prediction of Cellular Metabolism with Constraint-Based Models:
           The COBRA Toolbox.” Nature Protocols 2 (March 29, 2007): 727.
    """
    if 'moma_old_objective' in model.solver.variables:
        raise ValueError('model is already adjusted for MOMA')

    # Fall back to default QP solver if current one has no QP capability
    if not linear:
        model.solver = sutil.choose_solver(model, qp=True)

    if solution is None:
        solution = pfba(model)
    prob = model.problem
    v = prob.Variable("moma_old_objective")
    c = prob.Constraint(model.solver.objective.expression - v,
                        lb=0.0, ub=0.0, name="moma_old_objective_constraint")
    to_add = [v, c]
    model.objective = prob.Objective(Zero, direction="min", sloppy=True)
    obj_vars = []
    for r in model.reactions:
        flux = solution.fluxes[r.id]
        if linear:
            components = sutil.add_absolute_expression(
                model, r.flux_expression, name="moma_dist_" + r.id,
                difference=flux, add=False)
            to_add.extend(components)
            obj_vars.append(components.variable)
        else:
            dist = prob.Variable("moma_dist_" + r.id)
            const = prob.Constraint(r.flux_expression - dist, lb=flux, ub=flux,
                                    name="moma_constraint_" + r.id)
            to_add.extend([dist, const])
            obj_vars.append(dist ** 2)
    model.add_cons_vars(to_add)
    if linear:
        model.objective.set_linear_coefficients({v: 1.0 for v in obj_vars})
    else:
        model.objective = prob.Objective(
            add(obj_vars), direction="min", sloppy=True)

def
add_moma
(
model
,
solution
=
,
linear
=
True
)
:
r
if
'moma_old_objective'
in
model
.
solver
.
variables
:
raise
ValueError
(
'model is already adjusted for MOMA'
)
if
not
linear
:
model
.
solver
=
sutil
.
choose_solver
(
model
,
qp
=
True
)
if
solution
is
:
solution
=
pfba
(
model
)
prob
=
model
.
problem
v
=
prob
.
Variable
(
"moma_old_objective"
)
c
=
prob
.
Constraint
(
model
.
solver
.
objective
.
expression
v
,
lb
=
0.0
,
ub
=
0.0
,
name
=
"moma_old_objective_constraint"
)
to_add
=
[
v
,
c
]
model
.
objective
=
prob
.
Objective
(
Zero
,
direction
=
"min"
,
sloppy
=
True
)
obj_vars
=
[
]
for
r
in
model
.
reactions
:
flux
=
solution
.
fluxes
[
r
.
id
]
if
linear
:
components
=
sutil
.
add_absolute_expression
(
model
,
r
.
flux_expression
,
name
=
"moma_dist_"
+
r
.
id
,
difference
=
flux
,
add
=
False
)
to_add
.
extend
(
components
)
obj_vars
.
append
(
components
.
variable
)
else
:
dist
=
prob
.
Variable
(
"moma_dist_"
+
r
.
id
)
const
=
prob
.
Constraint
(
r
.
flux_expression
dist
,
lb
=
flux
,
ub
=
flux
,
name
=
"moma_constraint_"
+
r
.
id
)
to_add
.
extend
(
[
dist
,
const
]
)
obj_vars
.
append
(
dist
**
2
)
model
.
add_cons_vars
(
to_add
)
if
linear
:
model
.
objective
.
set_linear_coefficients
(
{
v
:
1.0
for
v
in
obj_vars
}
)
else
:
model
.
objective
=
prob
.
Objective
(
add
(
obj_vars
)
,
direction
=
"min"
,
sloppy
=
True
)

r Add constraints and objective representing for MOMA .


def _fix_type(value):
    """convert possible types to str, float, and bool"""
    # Because numpy floats can not be pickled to json
    if isinstance(value, string_types):
        return str(value)
    if isinstance(value, float_):
        return float(value)
    if isinstance(value, bool_):
        return bool(value)
    if isinstance(value, set):
        return list(value)
    if isinstance(value, dict):
        return OrderedDict((key, value[key]) for key in sorted(value))
    # handle legacy Formula type
    if value.__class__.__name__ == "Formula":
        return str(value)
    if value is None:
        return ""
    return value

def _fix_type ( value ) : if isinstance ( value , string_types ) : return str ( value ) if isinstance ( value , float_ ) : return float ( value ) if isinstance ( value , bool_ ) : return bool ( value ) if isinstance ( value , set ) : return list ( value ) if isinstance ( value , dict ) : return OrderedDict ( ( key , value [ key ] ) for key in sorted ( value ) ) if value . __class__ . __name__ == "Formula" : return str ( value ) if value is None : return "" return value

convert possible types to str float and bool


def _update_optional(cobra_object, new_dict, optional_attribute_dict,
                     ordered_keys):
    """update new_dict with optional attributes from cobra_object"""
    for key in ordered_keys:
        default = optional_attribute_dict[key]
        value = getattr(cobra_object, key)
        if value is None or value == default:
            continue
        new_dict[key] = _fix_type(value)

def _update_optional ( cobra_object , new_dict , optional_attribute_dict , ordered_keys ) : for key in ordered_keys : default = optional_attribute_dict [ key ] value = getattr ( cobra_object , key ) if value is None or value == default : continue new_dict [ key ] = _fix_type ( value )


def model_to_dict(model, sort=False):
    """Convert model to a dict.

    Parameters
    ----------
    model : cobra.Model
        The model to reformulate as a dict.
    sort : bool, optional
        Whether to sort the metabolites, reactions, and genes or maintain the
        order defined in the model.

    Returns
    -------
    OrderedDict
        A dictionary with elements, 'genes', 'compartments', 'id',
        'metabolites', 'notes' and 'reactions'; where 'metabolites', 'genes'
        and 'metabolites' are in turn lists with dictionaries holding all
        attributes to form the corresponding object.

    See Also
    --------
    cobra.io.model_from_dict
    """
    obj = OrderedDict()
    obj["metabolites"] = list(map(metabolite_to_dict, model.metabolites))
    obj["reactions"] = list(map(reaction_to_dict, model.reactions))
    obj["genes"] = list(map(gene_to_dict, model.genes))
    obj["id"] = model.id
    _update_optional(model, obj, _OPTIONAL_MODEL_ATTRIBUTES,
                     _ORDERED_OPTIONAL_MODEL_KEYS)
    if sort:
        get_id = itemgetter("id")
        obj["metabolites"].sort(key=get_id)
        obj["reactions"].sort(key=get_id)
        obj["genes"].sort(key=get_id)
    return obj

def model_to_dict ( model , sort = False ) : obj = OrderedDict ( ) obj [ "metabolites" ] = list ( map ( metabolite_to_dict , model . metabolites ) ) obj [ "reactions" ] = list ( map ( reaction_to_dict , model . reactions ) ) obj [ "genes" ] = list ( map ( gene_to_dict , model . genes ) ) obj [ "id" ] = model . id _update_optional ( model , obj , _OPTIONAL_MODEL_ATTRIBUTES , _ORDERED_OPTIONAL_MODEL_KEYS ) if sort : get_id = itemgetter ( "id" ) obj [ "metabolites" ] . sort ( key = get_id ) obj [ "reactions" ] . sort ( key = get_id ) obj [ "genes" ] . sort ( key = get_id ) return obj