forked from francescopenna/minimumspanningtree
- Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprim.py
261 lines (222 loc) · 7.77 KB
/
prim.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
importrandom
importmatplotlib.pyplotasplt
importos
importgc
fromtimeimportperf_counter_ns
# VERTEX STRUCTURE FOR PRIM'S ALGORITHM
classvertex:
def__init__(self, name):
INF=999999
# VERTEX NAME
self.Name=str(name)
# VERTEX COST
self.Value=INF
# VERTEX PARENT
self.Parent=None
defreset(self):
INF=999999
# VERTEX COST
self.Value=INF
# VERTEX PARENT
self.Parent=None
classGraph:
def__init__(self, n_ver, n_edges):
self.vertices= []
self.num_edges=n_edges
self.num_vertex=n_ver
self.edges= {}
# CREATE OBJECT VERTEX AND ADD TO VERTICES
forvinrange(1, n_ver+1):
new_vertex=vertex(name=v)
self.vertices.append(new_vertex)
self.edges[new_vertex] = {}
defreset(self):
forvinself.vertices:
v.reset()
defadd_edges(self, list_edges):
foriinlist_edges:
edge=i.split()
ifedge[0] !=edge[1]:
u=self.vertices[int(edge[0])-1]
v=self.vertices[int(edge[1])-1]
w=int(edge[2])
# SINCE GRAPH IS UNDIRECTED, ADD EDGE IN TWO WAYS
self.edges[u][v] =w
self.edges[v][u] =w
defget_weight(self,u,v):
returnself.edges[u][v]
defget_graph(self):
forvinself.vertices:
print("node ",v.Name," connect to ")
foruinself.find_adj(v):
print(" ",u.Name," with weight ",self.get_weight(u,v))
print("")
deffind_vertex(self, v):
foriinself.vertices:
ifi.Name==v:
returni
deffind_adj(self, v):
# find adjacents of a given vertex
returnself.edges[v].keys()
classminHeap:
# Constructor to initialize a heap
def__init__(self):
self.Heap= []
self.Size=0
self.valueToIndex= {}
defextractHeapify(self, idx):
# Update Heap to keep data min atg root
smallest=idx
left=2*idx+1
right=2*idx+2
# if the child is smaller than parent, change indexes
ifleft<len(self.Heap) andself.Heap[left].Value<self.Heap[smallest].Value:
smallest=left
ifright<len(self.Heap) andself.Heap[right].Value<self.Heap[smallest].Value:
smallest=right
# if the smallest index has chnaged swap nodes and heapify again
ifsmallest!=idx:
self.Heap[idx], self.Heap[smallest] =self.Heap[smallest], self.Heap[idx]
self.valueToIndex[self.Heap[smallest]] =smallest
self.valueToIndex[self.Heap[idx]] =idx
self.extractHeapify(smallest)
defextractMin(self):
# Extract the minimum value (in root)
ifself.isEmpty():
return
root=self.Heap[0]
# Substitite the root with last element
self.Heap[0] =self.Heap[len(self.Heap) -1]
self.valueToIndex[self.Heap[0]] =0
self.Heap.pop()
self.valueToIndex[root] =None
# Update heap
self.extractHeapify(0)
returnroot
defextractMin(self):
# Extract the minimum value (in root)
ifself.isEmpty():
return
root=self.Heap[0]
# Substitite the root with last element
self.Heap[0] =self.Heap[len(self.Heap) -1]
self.valueToIndex[self.Heap[0]] =0
self.Heap.pop()
self.valueToIndex[root] =None
# Update heap
self.extractHeapify(0)
returnroot
definsertHeapify(self, idx):
# update heap after insert
parent=int(((idx-1) /2))
# check if the inserted element is smaller than its parent
ifself.Heap[idx].Value<self.Heap[parent].Value:
self.Heap[idx], self.Heap[parent] =self.Heap[parent], self.Heap[idx]
self.valueToIndex[self.Heap[parent]] =parent
self.valueToIndex[self.Heap[idx]] =idx
self.insertHeapify(parent)
definsert(self, v):
# insert node at the end of heap
self.Heap.append(v)
self.valueToIndex[v] =len(self.Heap) -1
self.insertHeapify(self.valueToIndex[v])
return
defupdateKey(self, v):
# VALUE IS ALWAYS DECREASING, MOVE NODE UP THE TREE
idx=self.valueToIndex[v]
#idx = self.Heap.index(v)
parent=int(((idx-1) /2))
ifself.Heap[idx].Value<self.Heap[parent].Value:
self.Heap[idx], self.Heap[parent] =self.Heap[parent], self.Heap[idx]
self.valueToIndex[self.Heap[parent]] =parent
self.valueToIndex[self.Heap[idx]] =idx
self.insertHeapify(parent)
defisEmpty(self):
returnlen(self.Heap) ==0
defisInMinHeap(self, v):
#if v in self.Heap:
returnself.valueToIndex[v] isnotNone
defprint_Heap(self):
print("HEAP: ")
foriinself.Heap:
print("Name: ", i.Name, ", Value: ", i.Value)
defprim(G):
# CHOOSE A STARTING POINT AT RANDOM
start=random.choice(G.vertices)
start.Value=0
A=set()
# INITIALIZE HEAP FOR PRIM WITH NODE VALUES = INFINITY
Q=minHeap()
forverinG.vertices:
Q.insert(ver)
# WHILE EVERY VERTEX IS NOT INCLUDED IN THE TREE
whilenotQ.isEmpty():
# EXTRACT NODE WITH MINIMUM VALUE AND FIND ITS ADJACENTS
u=Q.extractMin()
A.add(u)
u_adj=G.find_adj(u)
forvinu_adj:
u_v_weight=G.get_weight(u,v)
# IF EDGE (u,v) HAS A LOWER COST UPADTE THE VALUE OF v
ifvnotinAandu_v_weight<v.Value:
v.Parent=u
v.Value=u_v_weight
Q.updateKey(v)
# COMPUTING WEIGHT OF THE TREE
A_weight=0
forverinG.vertices:
# IF VERTEX IS NOT THE ROOT
ifver.ParentisnotNone:
ver_parent=ver.Parent
A_weight+=G.get_weight(ver, ver_parent)
returnA_weight
defmeasure_run_times(g, num_calls, num_instances):
sum_times=0.0
foriinrange(num_instances):
gc.disable()
start_time=perf_counter_ns()
forjinrange(num_calls):
g.reset()
prim(g)
end_time=perf_counter_ns()
gc.enable()
sum_times+= (end_time-start_time)/num_calls
avg_time=int(round(sum_times/num_instances))
# return average time in nanoseconds
returnavg_time
if__name__=='__main__':
dir_name='mst_dataset'
num_calls=100
num_instances=1
graph_sizes= []
run_times= []
directory=os.fsencode(dir_name)
forfileinsorted(os.listdir(directory)):
filename=os.fsdecode(file)
iffilename.endswith('.txt'):
f=open(dir_name+'/'+filename)
print("doing the ", filename)
line=f.readline().split()
g=Graph(int(line[0]), int(line[1]))
edges=f.read().splitlines()
g.add_edges(edges)
f.close()
graph_sizes.append(g.num_vertex)
run_times.append(measure_run_times(g, num_calls, num_instances))
withopen('results/prim_results.txt', 'w+') asf:
f.write("Sizes\tTimes")
foriinrange(len(graph_sizes)):
f.write("%s\t%s\n"% (graph_sizes[i], run_times[i]))
plt.plot(graph_sizes, run_times)
plt.legend(['Measured times'])
plt.xlabel('Number of vertices')
plt.ylabel('Run times (ms)')
plt.show()
if__name__=='__main__':
f=open('mst_dataset/input_random_13_80.txt', 'r')
line=f.readline().split()
edge_list=f.read().splitlines()
g=Graph(int(line[0]), int(line[1]))
g.add_edges(edge_list)
A_w=prim(g)
print(A_w)