def allot_consistent_stoichiometry(graph, factors): """ @param graph: L{BipartiteMetabolicNetwork <pyMetabolism.graph_view.BipartiteMetabolicNetwork>} @param factors: An iterable of desired stoichiometric factors. May contain a specific factor multiple times to bias towards selection of that factor. @rtype: L{BipartiteMetabolicNetwork <pyMetabolism.graph_view.BipartiteMetabolicNetwork>} with consistent stoichiometric factors. """ options = OptionsManager() logger = logging.getLogger("%s.allot_consistent_stoichiometry"\ % options.main_logger_name) def populate_network(graph, factors): for e in graph.edges_iter(): graph[e[0]][e[1]]["factor"] = random.choice(factors) count = 0 while (True): count += 1 logger.info("Attempt number %d", count) populate_network(graph, factors) matrix = StoichiometricMatrix() matrix.make_new_from_network(graph) (yes, result) = verify_consistency(matrix) if yes: logger.info("Success!") break
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 random_fba(graph, num_inputs, num_outputs): """ @param graph: BipartiteMetabolicNetwork @param num_inputs: Sequence of integers for a number of compound sources on the same set of sink compounds @param num_outputs: Size of the sink vector """ options = OptionsManager() logger = logging.getLogger("%s.random_fba" % options.main_logger_name) assert num_outputs > 0 if not num_inputs: raise PyMetabolismError("No sources specified for random FBA!") for input in num_inputs: assert input > 0 inputs = list() potential_inputs = list() outputs = list() results = list() cmpds = list(graph.compounds) for comp in graph.compounds: if len(outputs) < num_outputs and graph.out_degree(comp) == 0: outputs.append(comp) cmpds.remove(comp) elif graph.in_degree(comp) == 0: potential_inputs.append(comp) cmpds.remove(comp) # if necessary fill up 'outputs' with random compounds # they should not be source compounds, thus we remove references count = num_outputs - len(outputs) while (count > 0): comp = random.choice(cmpds) outputs.append(comp) cmpds.remove(comp) count -= 1 logger.info("%d biomass compounds.", len(outputs)) # perform FBA for varying numbers of source compounds matrix = StoichiometricMatrix() matrix.make_new_from_network(graph) # add biomass reaction biomass = Reaction("Biomass", tuple(outputs), (), [-1.]*num_outputs) # equality constraints b_eq = numpy.zeros(matrix.num_compounds) # start with the largest number of inputs, then reduce num_inputs.sort(reverse=True) maxi = num_inputs[0] for comp in potential_inputs: if len(inputs) < maxi: inputs.append(comp) # similarly to 'outputs', 'inputs' is filled up count = maxi - len(inputs) while (count > 0): comp = random.choice(cmpds) inputs.append(comp) cmpds.remove(comp) count -= 1 for num in num_inputs: system = numpy.array(matrix, dtype=float, copy=True) system.add_reaction(biomass) logger.info("%d uptake compounds.", num) input_rxns = list() # adjust source numbers while len(inputs) > num: comp = random.choice(inputs) inputs.remove(comp) transp = list() for comp in inputs: rxn = Reaction("Transport_%s" % comp.identifier,\ (), (comp), (1.), reversible=True) system.add_reaction(rxn) transp.append(rxn) # objective function objective = numpy.zeros(system.num_reactions) objective[system.reaction_map[biomass]] = 1. # equality constraints A_eq = system # prepare flux balance analysis linear programming problem # boundaries lb = numpy.zeros(system.num_reactions) for rxn in system.reactions: if rxn.reversible: lb[system.reaction_map[rxn]] = -numpy.inf ub = numpy.empty(system.num_reactions) ub.fill(numpy.inf) # constrain transport reactions for rxn in transp: ub[system.reaction_map[rxn]] = 1. lb[system.reaction_map[rxn]] = -1. problem = openopt.LP(f=objective, Aeq=A_eq, beq=b_eq, lb=lb, ub=ub) result = problem.maximize(options.solver, iprint=-10) logger.debug(result.xf) for rxn in graph.reactions: if rxn == biomass: logger.info("%s : %G", rxn.identifier, result.xf[system.reaction_map[rxn]]) elif rxn in transp: logger.info("%s : %G", rxn.identifier, result.xf[system.reaction_map[rxn]]) else: logger.info("%s : %G", rxn.identifier, result.xf[system.reaction_map[rxn]]) results.append((result.isFeasible, result.xf)) return results