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