def random_metabolic_network(compounds, reactions, reversible, p, seed=None): """ Creates a bipartite graph that models metabolism according to the principles of an Erdos-Renyi-like random graph. @param compounds: Integer specifying the number of compounds. @param reactions: Integer, specifying the number of reactions. @param p: Probability for an edge to be set (on average this is the density of the graph). @rtype: L{BipartiteMetabolicNetwork <pyMetabolism.graph_view.BipartiteMetabolicNetwork>} @raise ValueError: If either compounds or reactions are not integers. """ if seed: random.seed(seed) options = OptionsManager() logger = logging.getLogger("%s.random_metabolic_network"\ % (options.main_logger_name)) graph = BipartiteMetabolicNetwork(name="random model") for i in xrange(compounds): graph.add_compound(Compound("%s%d" % (options.compound_prefix, i))) # choose a number of reactions as reversible reversibles = random.sample(xrange(reactions), reversible) reversibles.sort() for i in xrange(reactions): if len(reversibles) > 0 and i == reversibles[0]: del reversibles[0] graph.add_reaction(Reaction("%s%d" % (options.reaction_prefix, i),\ (), (), (), reversible=True)) else: graph.add_reaction(Reaction("%s%d" % (options.reaction_prefix, i),\ (), (), (), reversible=False)) for src in graph.compounds: for tar in graph.reactions: if random.random() < p: logger.debug("Adding edge %s-%s.", src.identifier,\ tar.identifier) graph.add_edge(src, tar, factor=0) # a conditional case here (elif not if) because we cannot determine # substrates and products from bidirectional edges elif random.random() < p: logger.debug("Adding edge %s-%s.", tar.identifier,\ src.identifier) graph.add_edge(tar, src, factor=0) prune_network(graph, logger) return graph
def balance_multiple_reactions(graph, factors, rxns, mass_vector, lower, upper, logger): options = OptionsManager() sub = BipartiteMetabolicNetwork() for rxn in rxns: msg = "%s:\n" % rxn.identifier sub.add_reaction(rxn) for cmpd in graph.predecessors(rxn): coefficient = random.choice(factors) msg += " -%d%s" % (coefficient, cmpd) sub.add_compound(cmpd) sub.add_edge(cmpd, rxn, factor=coefficient) graph[cmpd][rxn]["factor"] = coefficient for cmpd in graph.successors(rxn): coefficient = random.choice(factors) msg += " +%d%s" % (coefficient, cmpd) sub.add_compound(cmpd) sub.add_edge(rxn, cmpd, factor=coefficient) graph[rxn][cmpd]["factor"] = coefficient msg += " = 0\n" logger.debug(msg) matrix = StoichiometricMatrix() matrix.make_new_from_network(sub) # objective function objective = numpy.ones(matrix.num_compounds) # equality constraints A_eq = numpy.array(numpy.transpose(matrix.matrix), dtype=float, copy=False) b_eq = numpy.zeros(matrix.num_reactions) # lower boundary lb = numpy.empty(matrix.num_compounds) for (i, comp) in enumerate(matrix.compounds): if mass_vector[comp] != 0.: lb[i] = mass_vector[comp] else: lb[i] = lower # upper boundary ub = numpy.empty(matrix.num_compounds) for (i, comp) in enumerate(matrix.compounds): if mass_vector[comp] != 0.: ub[i] = mass_vector[comp] else: ub[i] = upper # starting guess start = numpy.empty(matrix.num_compounds) logger.debug(A_eq) for (i, comp) in enumerate(matrix.compounds): start[i] = 1. / float(sub.in_degree(comp) + sub.out_degree(comp)) problem = openopt.LP(f=objective, Aeq=A_eq, beq=b_eq, lb=lb, ub=ub, x0=start) result = problem.solve(options.solver, iprint=-10) if not result.isFeasible: raise PyMetabolismError("Unable to balance reaction system.") for (i, comp) in enumerate(matrix.compounds): if mass_vector[comp] == 0.: mass_vector[comp] = result.xf[i] logger.debug(result.xf)
def scale_free_metabolic_network(compounds, reactions, reversible, m, n): """ Uses a Barabasi-Alberts-like preferential attachment algorithm. Adopted from the networkx implementation. @param m: How many compounds a new reaction node links to @param n: How many reactions a new compound node links to """ options = OptionsManager() logger = logging.getLogger("%s.scale_free_metabolic_network"\ % (options.main_logger_name)) graph = BipartiteMetabolicNetwork(name="scale-free model") # target nodes for reactions rxn_targets = [] for i in xrange(m): comp = Compound("%s%d" % (options.compound_prefix, i)) graph.add_compound(comp) rxn_targets.append(comp) # logger.debug("Targets for reactions: %s", rxn_targets) # target nodes for compounds comp_targets = [] # biased lists for preferential attachment repeated_cmpds = [] repeated_rxns = [] # choose a number of reactions as reversible reversibles = random.sample(xrange(reactions), reversible) reversibles.sort() for i in xrange(n): if len(reversibles) > 0 and i == reversibles[0]: del reversibles[0] rxn = Reaction("%s%d" % (options.reaction_prefix, i),\ (), (), (), reversible=True) else: rxn = Reaction("%s%d" % (options.reaction_prefix, i),\ (), (), (), reversible=False) graph.add_reaction(rxn) comp_targets.append(rxn) for comp in rxn_targets: if random.random() < 0.5: logger.debug("Adding edge %s -> %s.", rxn.identifier,\ comp.identifier) graph.add_edge(rxn, comp, factor=0) else: logger.debug("Adding edge %s -> %s.", comp.identifier,\ rxn.identifier) graph.add_edge(comp, rxn, factor=0) repeated_cmpds.extend(rxn_targets) repeated_rxns.extend([rxn] * m) # logger.debug("Targets for compounds: %s", comp_targets) # current vertices being added current_rxn = n current_comp = m # to prevent reactions from consuming and producing the same compound new_targets = list() rm_targets = list() while (current_comp < compounds or current_rxn < reactions): if current_comp < compounds: source = Compound("%s%d" % (options.compound_prefix, current_comp)) graph.add_compound(source) for rxn in comp_targets: if random.random() < 0.5: logger.debug("Adding edge %s -> %s.", source.identifier,\ rxn.identifier) graph.add_edge(source, rxn, factor=0) else: logger.debug("Adding edge %s -> %s.", rxn.identifier,\ source.identifier) graph.add_edge(rxn, source, factor=0) repeated_rxns.extend(comp_targets) repeated_cmpds.extend([source] * n) comp_targets = set() while len(comp_targets) < n: rxn = random.choice(repeated_rxns) comp_targets.add(rxn) current_comp += 1 if current_rxn < reactions: if len(reversibles) > 0 and current_rxn == reversibles[0]: del reversibles[0] source = Reaction("%s%d" % (options.reaction_prefix,\ current_rxn), (), (), (), reversible=True) else: source = Reaction("%s%d" % (options.reaction_prefix,\ current_rxn), (), (), (), reversible=False) graph.add_reaction(source) new_targets = list() rm_targets = list() for comp in rxn_targets: # same compound may not be in substrates and products if (comp in graph.predecessors(source)) or (comp in graph.successors(source)): cmpd = random.choice(repeated_cmpds) while cmpd in graph.predecessors(source) or cmpd in graph.successors(source) or cmpd in new_targets or cmpd in rxn_targets: cmpd = random.choice(repeated_cmpds) new_targets.append(cmpd) rm_targets.append(comp) continue if random.random() < 0.5: logger.debug("Adding edge %s -> %s.", source.identifier,\ comp.identifier) graph.add_edge(source, comp, factor=0) else: logger.debug("Adding edge %s -> %s.", comp.identifier,\ source.identifier) graph.add_edge(comp, source, factor=0) for comp in rm_targets: rxn_targets.remove(comp) for comp in new_targets: rxn_targets.add(comp) if random.random() < 0.5: logger.debug("Adding edge %s -> %s.", source.identifier,\ comp.identifier) graph.add_edge(source, comp, factor=0) else: logger.debug("Adding edge %s -> %s.", comp.identifier,\ source.identifier) graph.add_edge(comp, source, factor=0) repeated_cmpds.extend(rxn_targets) repeated_rxns.extend([source] * m) rxn_targets = set() while len(rxn_targets) < m: comp = random.choice(repeated_cmpds) rxn_targets.add(comp) current_rxn += 1 prune_network(graph, logger) return graph