Skip to content

Commit

Permalink
Merge pull request #14 from Schefflera-Arboricola/main
Browse files Browse the repository at this point in the history
parallel implementation for all_pairs_bellman_ford_path
  • Loading branch information
MridulS authored Dec 5, 2023
2 parents cbca705 + aaa36b7 commit 362044c
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 16 deletions.
1 change: 1 addition & 0 deletions nx_parallel/algorithms/shortest_paths/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .weighted import *
71 changes: 71 additions & 0 deletions nx_parallel/algorithms/shortest_paths/weighted.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from joblib import Parallel, delayed
from networkx.algorithms.shortest_paths.weighted import single_source_bellman_ford_path

import nx_parallel as nxp

__all__ = ["all_pairs_bellman_ford_path"]


def all_pairs_bellman_ford_path(G, weight="weight"):
"""Compute shortest paths between all nodes in a weighted graph.
Parameters
----------
G : NetworkX graph
weight : string or function (default="weight")
If this is a string, then edge weights will be accessed via the
edge attribute with this key (that is, the weight of the edge
joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
such edge attribute exists, the weight of the edge is assumed to
be one.
If this is a function, the weight of an edge is the value
returned by the function. The function must accept exactly three
positional arguments: the two endpoints of an edge and the
dictionary of edge attributes for that edge. The function must
return a number.
Returns
-------
paths : iterator
(source, dictionary) iterator with dictionary keyed by target and
shortest path as the key value.
Notes
-----
Edge weight attributes must be numerical.
Distances are calculated as sums of weighted edges traversed.
Examples
--------
>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_weighted_edges_from([(1, 0, 1), (1, 2, 1), (2, 0, 3)])
>>> path = dict(nx.all_pairs_bellman_ford_path(G))
>>> path[0][2]
[0, 1, 2]
>>> parallel_path = dict(nx.all_pairs_bellman_ford_path(G, backend="parallel"))
>>> parallel_path[0][2]
[0, 1, 2]
>>> import nx_parallel as nxp
>>> parallel_path_ = dict(nx.all_pairs_bellman_ford_path(nxp.ParallelGraph(G)))
>>> parallel_path_
{1: {1: [1], 0: [1, 0], 2: [1, 2]}, 0: {0: [0], 1: [0, 1], 2: [0, 1, 2]}, 2: {2: [2], 1: [2, 1], 0: [2, 1, 0]}}
"""

def _calculate_shortest_paths_subset(source):
return (source, single_source_bellman_ford_path(G, source, weight=weight))

if hasattr(G, "graph_object"):
G = G.graph_object

nodes = G.nodes

total_cores = nxp.cpu_count()

paths = Parallel(n_jobs=total_cores, return_as="generator")(
delayed(_calculate_shortest_paths_subset)(source) for source in nodes
)
return paths
9 changes: 6 additions & 3 deletions nx_parallel/interface.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from nx_parallel.algorithms.centrality.betweenness import betweenness_centrality
from nx_parallel.algorithms.efficiency_measures import (
local_efficiency,
)
from nx_parallel.algorithms.shortest_paths.weighted import all_pairs_bellman_ford_path
from nx_parallel.algorithms.efficiency_measures import local_efficiency
from nx_parallel.algorithms.isolate import number_of_isolates
from nx_parallel.algorithms.tournament import (
is_reachable,
Expand All @@ -24,6 +23,7 @@ def is_multigraph(self):
def is_directed(self):
return self.graph_object.is_directed()


class Dispatcher:
# =============================

Expand All @@ -43,6 +43,9 @@ class Dispatcher:
# Efficiency
local_efficiency = local_efficiency

# Shortest Paths : all pairs shortest paths(bellman_ford)
all_pairs_bellman_ford_path = all_pairs_bellman_ford_path

# =============================

@staticmethod
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions timing/timing_comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ local_efficiency

tournament is_reachable
![alt text](heatmap_is_reachable_timing.png)

all_pairs_bellman_ford_path
![alt text](heatmap_all_pairs_bellman_ford_path_timing.png)
33 changes: 20 additions & 13 deletions timing/timing_individual_function.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import time
import random
import types

import networkx as nx
import pandas as pd
Expand All @@ -11,34 +13,39 @@
heatmapDF = pd.DataFrame()
number_of_nodes_list = [10, 50, 100, 300, 500]
pList = [1, 0.8, 0.6, 0.4, 0.2]
currFun = nx.betweenness_centrality
for i in range(0, len(pList)):
p = pList[i]
for j in range(0, len(number_of_nodes_list)):
num = number_of_nodes_list[j]

currFun = nx.all_pairs_bellman_ford_path
for p in pList:
for num in number_of_nodes_list:
# create original and parallel graphs
G = nx.fast_gnp_random_graph(num, p, directed=False)
G = nx.fast_gnp_random_graph(num, p, seed=42, directed=False)

# for weighted graphs
random.seed(42)
for u, v in G.edges():
G[u][v]["weight"] = random.random()

H = nx_parallel.ParallelGraph(G)

# time both versions and update heatmapDF
t1 = time.time()
c = currFun(H)
if type(c) == types.GeneratorType:
d = dict(c)
t2 = time.time()
parallelTime = t2 - t1
t1 = time.time()
c = currFun(G)
if type(c) == types.GeneratorType:
d = dict(c)
t2 = time.time()
stdTime = t2 - t1
timesFaster = stdTime / parallelTime
heatmapDF.at[j, i] = timesFaster
heatmapDF.at[num, p] = timesFaster
print("Finished " + str(currFun))

# Code to create for row of heatmap specifically for tournaments
# for i in range(0, len(pList)):
# p = pList[i]
# for j in range(0, len(number_of_nodes_list)):
# num = number_of_nodes_list[j]
# for p in pList:
# for num in number_of_nodes_list):
# G = nx.tournament.random_tournament(num)
# H = nx_parallel.ParallelDiGraph(G)
# t1 = time.time()
Expand All @@ -50,7 +57,7 @@
# t2 = time.time()
# stdTime = t2-t1
# timesFaster = stdTime/parallelTime
# heatmapDF.at[j, 3] = timesFaster
# heatmapDF.at[num, 3] = timesFaster

# plotting the heatmap with numbers and a green color scheme
plt.figure(figsize=(20, 4))
Expand Down

0 comments on commit 362044c

Please sign in to comment.