-
Notifications
You must be signed in to change notification settings - Fork 0
/
parallel_branching.py
126 lines (107 loc) · 3.7 KB
/
parallel_branching.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import random
import time
import networkx as nx
import ast
from mpi4py import MPI
import sys
#init stuff
filename = sys.argv[1] +'_graph_' + sys.argv[2] + '.txt'
G = nx.Graph()
visited = set()
original_node = 1
done = False
busy_threads = 0
#end of init stuff
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
def build_graph():
with open(filename, 'r') as f:
nodes_line = f.readline()
edges_line = f.readline()
nodes = [int(n) for n in nodes_line.split()]
edges = ast.literal_eval(edges_line)
G.add_nodes_from(nodes)
G.add_edges_from(edges)
def check_neighbours(node, current_path=None):
global visited
global busy_threads
global done
neighbours = list(nx.all_neighbors(G, node))
if current_path == None:
current_path = []
visited.add(node)
current_path.append(node)
#to count how many neighbours have been passed off to other processes.
#this is used so that the root node can keep exploring the graph itself
#and continue passing off branches to other processes until it runs out
#of processes
neighbour_iterator = 0
# print "Root sees visited as", visited
# print "Root sees current path as", current_path
for n in neighbours:
if n not in visited:
if (busy_threads < size - 1) and neighbour_iterator < len(neighbours)-1:
busy_threads += 1
print "Sending job to thread", busy_threads
comm.send(current_path, dest=busy_threads, tag=2)
comm.send(n, dest=busy_threads, tag=3)
neighbour_iterator += 1
elif (check_neighbours(n, current_path)): #if there's no more branches or threads to distribute...do it yourself
return True
if len(current_path) == nx.number_of_nodes(G) and original_node in neighbours:
return True
current_path.remove(node)
visited.remove(node) #backtracking
if done:
print "Process",rank,"exiting"
Finalize()
return False
def child_explore(node, current_path):
global done
neighbours = list(nx.all_neighbors(G, node))
# print "Child starting node", node
current_path.append(node)
for node in current_path:
visited.add(node) #this will include the current node since it just got appended
# print "Child", rank, "is seeing visited as", visited
# print "Child", rank, "is seeing current path as", current_path
for n in neighbours:
if n not in visited:
if (child_explore(n, current_path)):
return True
if len(current_path) == nx.number_of_nodes(G) and original_node in neighbours:
# comm.barrier()
return True
current_path.remove(node)
visited.remove(node) #backtracking
# comm.barrier()
if done:
print "Process",rank,"exiting"
Finalize()
return False
def main():
if rank == 0:
build_graph()
for i in range(1, comm.Get_size()):
comm.send(G.nodes(), dest=i, tag=0)
comm.send(G.edges(), dest=i, tag=1)
if check_neighbours(original_node):
print "Root returns true!"
return True
else:
G.add_nodes_from(comm.recv(source=0, tag=0))
G.add_edges_from(comm.recv(source=0, tag=1))
current_path = comm.recv(source=0, tag=2) #blocking wait
starting_node = comm.recv(source=0, tag=3) #blocking wait
if child_explore(starting_node, current_path):
print "Child", rank, "returns true!"
return True
timeStart = time.time()
test = main()
timeEnd = time.time() - timeStart
print timeEnd
print "Process",rank,"has gotten out somehow..."
if test:
comm.Abort()
MPI.Finalize()