plot_parallel_betweenness.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. """
  2. ====================
  3. Parallel Betweenness
  4. ====================
  5. Example of parallel implementation of betweenness centrality using the
  6. multiprocessing module from Python Standard Library.
  7. The function betweenness centrality accepts a bunch of nodes and computes
  8. the contribution of those nodes to the betweenness centrality of the whole
  9. network. Here we divide the network in chunks of nodes and we compute their
  10. contribution to the betweenness centrality of the whole network.
  11. This doesn't work in python2.7.13. It does work in 3.6, 3.5, 3.4, and 3.3.
  12. It may be related to this:
  13. https://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-multiprocessing-pool-map
  14. """
  15. from multiprocessing import Pool
  16. import time
  17. import itertools
  18. import matplotlib.pyplot as plt
  19. import networkx as nx
  20. def chunks(l, n):
  21. """Divide a list of nodes `l` in `n` chunks"""
  22. l_c = iter(l)
  23. while 1:
  24. x = tuple(itertools.islice(l_c, n))
  25. if not x:
  26. return
  27. yield x
  28. def _betmap(G_normalized_weight_sources_tuple):
  29. """Pool for multiprocess only accepts functions with one argument.
  30. This function uses a tuple as its only argument. We use a named tuple for
  31. python 3 compatibility, and then unpack it when we send it to
  32. `betweenness_centrality_source`
  33. """
  34. return nx.betweenness_centrality_source(*G_normalized_weight_sources_tuple)
  35. def betweenness_centrality_parallel(G, processes=None):
  36. """Parallel betweenness centrality function"""
  37. p = Pool(processes=processes)
  38. node_divisor = len(p._pool) * 4
  39. node_chunks = list(chunks(G.nodes(), int(G.order() / node_divisor)))
  40. num_chunks = len(node_chunks)
  41. bt_sc = p.map(_betmap,
  42. zip([G] * num_chunks,
  43. [True] * num_chunks,
  44. [None] * num_chunks,
  45. node_chunks))
  46. # Reduce the partial solutions
  47. bt_c = bt_sc[0]
  48. for bt in bt_sc[1:]:
  49. for n in bt:
  50. bt_c[n] += bt[n]
  51. return bt_c
  52. if __name__ == "__main__":
  53. G_ba = nx.barabasi_albert_graph(1000, 3)
  54. G_er = nx.gnp_random_graph(1000, 0.01)
  55. G_ws = nx.connected_watts_strogatz_graph(1000, 4, 0.1)
  56. for G in [G_ba, G_er, G_ws]:
  57. print("")
  58. print("Computing betweenness centrality for:")
  59. print(nx.info(G))
  60. print("\tParallel version")
  61. start = time.time()
  62. bt = betweenness_centrality_parallel(G)
  63. print("\t\tTime: %.4F" % (time.time() - start))
  64. print("\t\tBetweenness centrality for node 0: %.5f" % (bt[0]))
  65. print("\tNon-Parallel version")
  66. start = time.time()
  67. bt = nx.betweenness_centrality(G)
  68. print("\t\tTime: %.4F seconds" % (time.time() - start))
  69. print("\t\tBetweenness centrality for node 0: %.5f" % (bt[0]))
  70. print("")
  71. nx.draw(G_ba)
  72. plt.show()