Example #1
0
def test_dense_matrix(model: "Model") -> None:
    """Test dense stoichiometric matrix creation."""
    S = create_stoichiometric_matrix(model, array_type="dense", dtype=int)
    assert S.dtype == int
    assert np.allclose(S.max(), [59])

    S_df = create_stoichiometric_matrix(model, array_type="DataFrame", dtype=int)
    assert S_df.values.dtype == int
    assert np.all(S_df.columns == [r.id for r in model.reactions])
    assert np.all(S_df.index == [m.id for m in model.metabolites])
    assert np.allclose(S_df.values, S)

    S = create_stoichiometric_matrix(model, array_type="dense", dtype=float)
    solution = model.optimize()
    mass_balance = S.dot(solution.fluxes)
    assert np.allclose(mass_balance, 0)
Example #2
0
    def create_model_files(self, temp_dir):
        """ Write stochiometry data, reaction reversibilities, metabolite, and
        reaction names to temporary files in preparation for calling efmtool

        """

        stoich_mat = create_stoichiometric_matrix(self.model)

        # Stoichiometric Matrix
        np.savetxt(temp_dir + '/stoich.txt', stoich_mat, delimiter='\t')

        # Reaction reversibilities
        np.savetxt(temp_dir + '/revs.txt',
                   np.array([r.reversibility for r in self.model.reactions]),
                   delimiter='\t',
                   fmt='%d',
                   newline='\t')

        # Reaction Names
        with open(temp_dir + '/rnames.txt', 'w') as f:
            f.write('\t'.join(
                ('"{}"'.format(r.id) for r in self.model.reactions)))

        # Metabolite Names
        with open(temp_dir + '/mnames.txt', 'w') as f:
            f.write('\t'.join(
                ('"{}"'.format(m.id) for m in self.model.metabolites)))
Example #3
0
def test_dense_matrix(model):
    S = create_stoichiometric_matrix(model, array_type='dense', dtype=int)
    assert S.dtype == int
    assert np.allclose(S.max(), [59])

    S_df = create_stoichiometric_matrix(
        model, array_type='DataFrame', dtype=int)
    assert S_df.values.dtype == int
    assert np.all(S_df.columns == [r.id for r in model.reactions])
    assert np.all(S_df.index == [m.id for m in model.metabolites])
    assert np.allclose(S_df.values, S)

    S = create_stoichiometric_matrix(model, array_type='dense', dtype=float)
    solution = model.optimize()
    mass_balance = S.dot(solution.fluxes)
    assert np.allclose(mass_balance, 0)
Example #4
0
    def test_sparse_matrix(self, model):
        sparse_types = ['dok', 'lil']

        solution = model.optimize()
        for sparse_type in sparse_types:
            S = create_stoichiometric_matrix(model, array_type=sparse_type)
            mass_balance = S.dot(solution.fluxes)
            assert numpy.allclose(mass_balance, 0)
Example #5
0
def test_sparse_matrix(model):
    sparse_types = ['dok', 'lil']

    solution = model.optimize()
    for sparse_type in sparse_types:
        S = create_stoichiometric_matrix(model, array_type=sparse_type)
        mass_balance = S.dot(solution.fluxes)
        assert np.allclose(mass_balance, 0)
Example #6
0
    def test_dense_matrix(self, model):
        S = create_stoichiometric_matrix(model, array_type='dense', dtype=int)
        assert S.dtype == int
        assert numpy.allclose(S.max(), [59])

        S_df = create_stoichiometric_matrix(model,
                                            array_type='DataFrame',
                                            dtype=int)
        assert S_df.values.dtype == int
        assert numpy.all(S_df.columns == [r.id for r in model.reactions])
        assert numpy.all(S_df.index == [m.id for m in model.metabolites])
        assert numpy.allclose(S_df.values, S)

        S = create_stoichiometric_matrix(model,
                                         array_type='dense',
                                         dtype=float)
        solution = model.optimize()
        mass_balance = S.dot(solution.fluxes)
        assert numpy.allclose(mass_balance, 0)
Example #7
0
def test_sparse_matrix(model):
    """Test sparse stoichiometric matrix creation."""
    pytest.importorskip("scipy")
    sparse_types = ["dok", "lil"]

    solution = model.optimize()
    for sparse_type in sparse_types:
        S = create_stoichiometric_matrix(model, array_type=sparse_type)
        mass_balance = S.dot(solution.fluxes)
        assert np.allclose(mass_balance, 0)
Example #8
0
 def __init__(self, model, thinning, seed=None):
     self.model = model
     self.thinning = thinning
     self.n_samples = 0
     self.S = create_stoichiometric_matrix(model, array_type='dense')
     self.NS = nullspace(self.S)
     self.bounds = np.array([[r.lower_bound, r.upper_bound]
                            for r in model.reactions]).T
     self.fixed = np.diff(self.bounds, axis=0).flatten() < 2 * BTOL
     self.warmup = None
     if seed is None:
         self._seed = int(time())
     else:
         self._seed = seed
     # Avoid overflow
     self._seed = self._seed % np.iinfo(np.int32).max
def prob_vertex(model):
    #the probability of a steadystate random walk through hyperedges on hypergraph G(V,E) visiting vertex vi

    # Create stoichiometric matrix
    S = create_stoichiometric_matrix(model, array_type='DataFrame')

    #Create hypergraph incidence matrix
    H = np.zeros(S.shape)
    H[S != 0] = 1

    #Vertex degree
    d = H.sum(axis=1)

    #Probability of a steadystate random walk visiting vertex v
    Pg = d / d.sum()

    return Pg
def makeHypergraph(model):

    S = create_stoichiometric_matrix(model, array_type='DataFrame')
    H = DirectedHypergraph()

    for i in range(len(S.columns)):
        nodes_df = S.iloc[:, i][S.iloc[:, i] != 0]

        edge_name = nodes_df.name
        head_nodes = set(nodes_df[nodes_df > 0].index)
        tail_nodes = set(nodes_df[nodes_df < 0].index)

        H.add_hyperedge(head_nodes, tail_nodes, {'reaction': edge_name})

        if model.reactions.get_by_id(edge_name).reversibility:

            H.add_hyperedge(tail_nodes, head_nodes,
                            {'reaction': edge_name + '_rev'})

    return H
Example #11
0
def create_mat_dict(model):
    """create a dict mapping model attributes to arrays"""
    rxns = model.reactions
    mets = model.metabolites
    mat = OrderedDict()
    mat["mets"] = _cell([met_id for met_id in create_mat_metabolite_id(model)])
    mat["metNames"] = _cell(mets.list_attr("name"))
    mat["metFormulas"] = _cell([str(m.formula) for m in mets])
    try:
        mat["metCharge"] = array(mets.list_attr("charge")) * 1.
    except TypeError:
        # can't have any None entries for charge, or this will fail
        pass
    mat["genes"] = _cell(model.genes.list_attr("id"))
    # make a matrix for rxnGeneMat
    # reactions are rows, genes are columns
    rxn_gene = scipy_sparse.dok_matrix((len(model.reactions),
                                        len(model.genes)))
    if min(rxn_gene.shape) > 0:
        for i, reaction in enumerate(model.reactions):
            for gene in reaction.genes:
                rxn_gene[i, model.genes.index(gene)] = 1
        mat["rxnGeneMat"] = rxn_gene
    mat["grRules"] = _cell(rxns.list_attr("gene_reaction_rule"))
    mat["rxns"] = _cell(rxns.list_attr("id"))
    mat["rxnNames"] = _cell(rxns.list_attr("name"))
    mat["subSystems"] = _cell(rxns.list_attr("subsystem"))
    mat["csense"] = "".join((
        met._constraint_sense for met in model.metabolites))
    stoich_mat = create_stoichiometric_matrix(model)
    mat["S"] = stoich_mat if stoich_mat is not None else [[]]
    # multiply by 1 to convert to float, working around scipy bug
    # https://github.com/scipy/scipy/issues/4537
    mat["lb"] = array(rxns.list_attr("lower_bound")) * 1.
    mat["ub"] = array(rxns.list_attr("upper_bound")) * 1.
    mat["b"] = array(mets.list_attr("_bound")) * 1.
    mat["c"] = array(rxns.list_attr("objective_coefficient")) * 1.
    mat["rev"] = array(rxns.list_attr("reversibility")) * 1
    mat["description"] = str(model.id)
    return mat
Example #12
0
def create_mat_dict(model):
    """create a dict mapping model attributes to arrays"""
    rxns = model.reactions
    mets = model.metabolites
    mat = OrderedDict()
    mat["mets"] = _cell([met_id for met_id in create_mat_metabolite_id(model)])
    mat["metNames"] = _cell(mets.list_attr("name"))
    mat["metFormulas"] = _cell([str(m.formula) for m in mets])
    try:
        mat["metCharge"] = array(mets.list_attr("charge")) * 1.
    except TypeError:
        # can't have any None entries for charge, or this will fail
        pass
    mat["genes"] = _cell(model.genes.list_attr("id"))
    # make a matrix for rxnGeneMat
    # reactions are rows, genes are columns
    rxn_gene = scipy_sparse.dok_matrix(
        (len(model.reactions), len(model.genes)))
    if min(rxn_gene.shape) > 0:
        for i, reaction in enumerate(model.reactions):
            for gene in reaction.genes:
                rxn_gene[i, model.genes.index(gene)] = 1
        mat["rxnGeneMat"] = rxn_gene
    mat["grRules"] = _cell(rxns.list_attr("gene_reaction_rule"))
    mat["rxns"] = _cell(rxns.list_attr("id"))
    mat["rxnNames"] = _cell(rxns.list_attr("name"))
    mat["subSystems"] = _cell(rxns.list_attr("subsystem"))
    mat["csense"] = "".join(
        (met._constraint_sense for met in model.metabolites))
    stoich_mat = create_stoichiometric_matrix(model)
    mat["S"] = stoich_mat if stoich_mat is not None else [[]]
    # multiply by 1 to convert to float, working around scipy bug
    # https://github.com/scipy/scipy/issues/4537
    mat["lb"] = array(rxns.list_attr("lower_bound")) * 1.
    mat["ub"] = array(rxns.list_attr("upper_bound")) * 1.
    mat["b"] = array(mets.list_attr("_bound")) * 1.
    mat["c"] = array(rxns.list_attr("objective_coefficient")) * 1.
    mat["rev"] = array(rxns.list_attr("reversibility")) * 1
    mat["description"] = str(model.id)
    return mat
Example #13
0
 def test_with_core_model(self, core_model):
     s = create_stoichiometric_matrix(core_model)
     ns = nullspace(s)
     assert round(abs(np.abs(s.dot(ns)).max() - 0), 10) == 0
Example #14
0
import hashlib
_ = 123456789  # just a wrong number, please ignore
###### Stop ignoring

# Some stuff you can/should use ...
# feel free to import additional things from those packages already imported
# or the Python Standard Library (https://docs.python.org/3/library/)
# (if it helps) but do not import other 3rd party packages.
import numpy as np
from cobra.io import read_sbml_model
from cobra.util import create_stoichiometric_matrix

# Read model (central metabolism model of Escherichia coli)
model = read_sbml_model('e_coli_core.xml')
# Create stoichiometric matrix
S = create_stoichiometric_matrix(model)

# 1. Binarize S

# replace _ with a binary representation of S.
# S_bin should only contain floating point numbers (either 0. or 1.)

S_bin = _


###### Don't touch
def test_binary_stoichiometry_matrix():
    assert hashlib.md5(S_bin).digest(
    ) == b'\xcd\xd3\x04N\x9e\xaf\x1f\xc5\xcb9\x9f\xaaa\x00\x06['

Example #15
0
    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)
        feasibility = feasibility.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 < feasibility_tol) & (lb_error > -bounds_tol) &
                 (ub_error > -bounds_tol))
        codes = np.repeat("", valid.shape[0]).astype(np.dtype((str, 3)))
        codes[valid] = "v"
        codes[lb_error <= -bounds_tol] = np.char.add(
            codes[lb_error <= -bounds_tol], "l")
        codes[ub_error <= -bounds_tol] = np.char.add(
            codes[ub_error <= -bounds_tol], "u")
        codes[feasibility > feasibility_tol] = np.char.add(
            codes[feasibility > feasibility_tol], "e")
        return codes
Example #16
0
    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
Example #17
0
def add_loopless(model, zero_cutoff=None):
    """Modify a model so all feasible flux distributions are loopless.

    In most cases you probably want to use the much faster `loopless_solution`.
    May be used in cases where you want to add complex constraints and
    objecives (for instance quadratic objectives) to the model afterwards
    or use an approximation of Gibbs free energy directions in you model.
    Adds variables and constraints to a model which will disallow flux
    distributions with loops. The used formulation is described in [1]_.
    This function *will* modify your model.

    Parameters
    ----------
    model : cobra.Model
        The model to which to add the constraints.
    zero_cutoff : positive float, optional
        Cutoff used for null space. Coefficients with an absolute value smaller
        than `zero_cutoff` are considered to be zero (default model.tolerance).

    Returns
    -------
    Nothing

    References
    ----------
    .. [1] Elimination of thermodynamically infeasible loops in steady-state
       metabolic models. Schellenberger J, Lewis NE, Palsson BO. Biophys J.
       2011 Feb 2;100(3):544-53. doi: 10.1016/j.bpj.2010.12.3707. Erratum
       in: Biophys J. 2011 Mar 2;100(5):1381.
    """
    zero_cutoff = normalize_cutoff(model, zero_cutoff)

    internal = [i for i, r in enumerate(model.reactions) if not r.boundary]
    s_int = create_stoichiometric_matrix(model)[:, numpy.array(internal)]
    n_int = nullspace(s_int).T
    max_bound = max(max(abs(b) for b in r.bounds) for r in model.reactions)
    prob = model.problem

    # Add indicator variables and new constraints
    to_add = []
    for i in internal:
        rxn = model.reactions[i]
        # indicator variable a_i
        indicator = prob.Variable("indicator_" + rxn.id, type="binary")
        # -M*(1 - a_i) <= v_i <= M*a_i
        on_off_constraint = prob.Constraint(
            rxn.flux_expression - max_bound * indicator,
            lb=-max_bound, ub=0, name="on_off_" + rxn.id)
        # -(max_bound + 1) * a_i + 1 <= G_i <= -(max_bound + 1) * a_i + 1000
        delta_g = prob.Variable("delta_g_" + rxn.id)
        delta_g_range = prob.Constraint(
            delta_g + (max_bound + 1) * indicator,
            lb=1, ub=max_bound, name="delta_g_range_" + rxn.id)
        to_add.extend([indicator, on_off_constraint, delta_g, delta_g_range])

    model.add_cons_vars(to_add)

    # Add nullspace constraints for G_i
    for i, row in enumerate(n_int):
        name = "nullspace_constraint_" + str(i)
        nullspace_constraint = prob.Constraint(Zero, lb=0, ub=0, name=name)
        model.add_cons_vars([nullspace_constraint])
        coefs = {model.variables[
                 "delta_g_" + model.reactions[ridx].id]: row[i]
                 for i, ridx in enumerate(internal) if
                 abs(row[i]) > zero_cutoff}
        model.constraints[name].set_linear_coefficients(coefs)
Example #18
0
def add_loopless(model, zero_cutoff=1e-12):
    """Modify a model so all feasible flux distributions are loopless.

    In most cases you probably want to use the much faster `loopless_solution`.
    May be used in cases where you want to add complex constraints and
    objecives (for instance quadratic objectives) to the model afterwards
    or use an approximation of Gibbs free energy directions in you model.
    Adds variables and constraints to a model which will disallow flux
    distributions with loops. The used formulation is described in [1]_.
    This function *will* modify your model.

    Parameters
    ----------
    model : cobra.Model
        The model to which to add the constraints.
    zero_cutoff : positive float, optional
        Cutoff used for null space. Coefficients with an absolute value smaller
        than `zero_cutoff` are considered to be zero.

    Returns
    -------
    Nothing

    References
    ----------
    .. [1] Elimination of thermodynamically infeasible loops in steady-state
       metabolic models. Schellenberger J, Lewis NE, Palsson BO. Biophys J.
       2011 Feb 2;100(3):544-53. doi: 10.1016/j.bpj.2010.12.3707. Erratum
       in: Biophys J. 2011 Mar 2;100(5):1381.
    """
    internal = [i for i, r in enumerate(model.reactions) if not r.boundary]
    s_int = create_stoichiometric_matrix(model)[:, numpy.array(internal)]
    n_int = nullspace(s_int).T
    max_bound = max(max(abs(b) for b in r.bounds) for r in model.reactions)
    prob = model.problem

    # Add indicator variables and new constraints
    to_add = []
    for i in internal:
        rxn = model.reactions[i]
        # indicator variable a_i
        indicator = prob.Variable("indicator_" + rxn.id, type="binary")
        # -M*(1 - a_i) <= v_i <= M*a_i
        on_off_constraint = prob.Constraint(
            rxn.flux_expression - max_bound * indicator,
            lb=-max_bound, ub=0, name="on_off_" + rxn.id)
        # -(max_bound + 1) * a_i + 1 <= G_i <= -(max_bound + 1) * a_i + 1000
        delta_g = prob.Variable("delta_g_" + rxn.id)
        delta_g_range = prob.Constraint(
            delta_g + (max_bound + 1) * indicator,
            lb=1, ub=max_bound, name="delta_g_range_" + rxn.id)
        to_add.extend([indicator, on_off_constraint, delta_g, delta_g_range])

    model.add_cons_vars(to_add)

    # Add nullspace constraints for G_i
    for i, row in enumerate(n_int):
        name = "nullspace_constraint_" + str(i)
        nullspace_constraint = prob.Constraint(Zero, lb=0, ub=0, name=name)
        model.add_cons_vars([nullspace_constraint])
        coefs = {model.variables[
                 "delta_g_" + model.reactions[ridx].id]: row[i]
                 for i, ridx in enumerate(internal) if
                 abs(row[i]) > zero_cutoff}
        model.constraints[name].set_linear_coefficients(coefs)
Example #19
0
 def test_with_core_model(self, core_model):
     s = create_stoichiometric_matrix(core_model)
     ns = nullspace(s)
     assert round(abs(np.abs(s.dot(ns)).max() - 0), 10) == 0