Skip to content

Commit 360eb0d

Browse files
author
Hamid Gasmi
committed
#170 is completed 2 ways: 1.DP + BFS and 2.DP + Topological Sort
1 parent 64862d8 commit 360eb0d

File tree

3 files changed

+138
-32
lines changed

3 files changed

+138
-32
lines changed

6-dynamic-programming-applications-in-machine-learning-and-genomics/1-sequence-alignment-1/longest_path_dag_bfs.py

+22-21
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from collections import namedtuple
44

55
Edge = namedtuple('Edge', ['v_no', 'w'])
6-
Vertice_Dist = namedtuple('Vertice_Dist', ['prev', 'dist'])
6+
Vertex_Distance = namedtuple('Vertex_Distance', ['predecessor', 'dist'])
77

88
class Directed_Acyclic_Graph:
99
def __init__(self, source, sink, edges):
@@ -19,7 +19,7 @@ def build_adjacency_list(self, edges):
1919
self.adjacency_list = [[] for _ in range(self.vertices_count)]
2020

2121
self.is_valid_source = True
22-
self.is_valid_sink = False
22+
self.is_valid_sink = True
2323
for edge in edges:
2424
u = int(edge.split("->")[0]) + self.v_no_label_gap
2525
v = int(edge.split("->")[1].split(":")[0]) + self.v_no_label_gap
@@ -28,13 +28,10 @@ def build_adjacency_list(self, edges):
2828
self.adjacency_list[u].append(Edge(v, w))
2929

3030
self.is_valid_source &= (v != 0)
31-
self.is_valid_sink |= (v == self.vertices_count - 1)
32-
33-
self.is_valid_source &= (len(self.adjacency_list[0]) > 0)
34-
self.is_valid_sink &= len(self.adjacency_list[self.vertices_count - 1]) == 0
35-
36-
#print(self.adjacency_list)
3731

32+
self.is_valid_source &= (len(edges) == 0 or len(self.adjacency_list[0]) > 0)
33+
self.is_valid_sink = len(self.adjacency_list[self.vertices_count - 1]) == 0
34+
3835
def explore_path(self, u, visited, cycle):
3936

4037
visited[u] = True
@@ -65,7 +62,15 @@ def check_dag_dfs(self):
6562
if self.explore_path(v, visited, cycle):
6663
self.is_valid_dag = False
6764
break
68-
65+
def longest_path_backtrack(self, u, max_distance):
66+
67+
longest_path = []
68+
while u != -1:
69+
longest_path.append(str(u - self.v_no_label_gap))
70+
u = max_distance[u].predecessor
71+
72+
return longest_path[::-1]
73+
6974
def longest_path_bfs(self, source, sink):
7075
self.longest_path_len = 0
7176
self.longest_path = []
@@ -77,28 +82,24 @@ def longest_path_bfs(self, source, sink):
7782
if not self.is_valid_dag:
7883
return
7984

80-
longest_path = [Vertice_Dist(-1, - sys.maxsize - 1) for _ in range(self.vertices_count)]
81-
longest_path[0] = Vertice_Dist(-1, 0)
85+
max_distance = [Vertex_Distance(-1, - sys.maxsize - 1) for _ in range(self.vertices_count)]
86+
max_distance[0] = Vertex_Distance(-1, 0)
8287

8388
q = Queue()
8489
q.put(0)
8590

8691
while not q.empty():
8792
u = q.get()
8893
for e in self.adjacency_list[u]:
89-
candidate_distance = longest_path[u].dist + e.w
90-
if longest_path[e.v_no].dist < candidate_distance:
91-
longest_path[e.v_no] = Vertice_Dist(u, candidate_distance)
94+
candidate_distance = max_distance[u].dist + e.w
95+
if max_distance[e.v_no].dist < candidate_distance:
96+
max_distance[e.v_no] = Vertex_Distance(u, candidate_distance)
9297

9398
q.put(e.v_no)
9499

95-
u = self.vertices_count - 1
96-
self.longest_path_len = longest_path[u].dist
97-
98-
while u != -1:
99-
self.longest_path.append(str(u - self.v_no_label_gap))
100-
u = longest_path[u].prev
101-
self.longest_path = self.longest_path[::-1]
100+
sink_vertex = self.vertices_count - 1
101+
self.longest_path_len = max_distance[sink_vertex].dist
102+
self.longest_path = self.longest_path_backtrack(sink_vertex, max_distance)
102103

103104
def longest_path_to_str(self):
104105

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
0
2+
49
3+
0->4:7
4+
4->16:8
5+
16->25:11
6+
25->49:13
7+
40->44:17
8+
1->13:17
9+
29->32:4
10+
2->29:5
11+
32->36:3
12+
23->25:15
13+
3->20:20
14+
40->49:20
15+
13->41:15
16+
13->15:12
17+
15->49:15
18+
7->26:18
19+
6->36:15
20+
32->49:20
21+
3->38:13
22+
33->34:2
23+
10->16:13
24+
2->27:20
25+
21->29:2
26+
22->41:19
27+
14->42:18
28+
34->37:12
29+
8->46:5
30+
42->46:15
31+
5->29:18
32+
28->45:8
33+
19->35:6
34+
33->37:18
35+
15->16:1
36+
29->33:10
37+
0->28:8
38+
47->49:1
39+
28->32:11
40+
3->18:8
41+
40->47:7
42+
32->42:8
43+
29->42:18
44+
24->36:3
45+
10->31:3
46+
32->37:7
47+
47->48:10
48+
26->45:2
49+
45->48:16
50+
40->48:4
51+
41->48:18
52+
19->30:15
53+
32->47:4
54+
6->25:15
55+
32->43:12
56+
5->32:13
57+
4->37:5
58+
21->44:19
59+
23->44:4
60+
19->25:4
61+
37->43:1
62+
26->31:5
63+
9->41:19
64+
8->10:11
65+
48->49:17
66+
20->29:5
67+
12->45:12
68+
11->22:11
69+
40->43:19
70+
19->40:3
71+
13->31:16
72+
12->38:14
73+
35->43:7
74+
18->24:4
75+
23->26:18
76+
17->26:13
77+
15->20:10
78+
8->15:12
79+
31->47:19
80+
16->31:5
81+
38->43:11
82+
39->44:20
83+
28->34:6
84+
18->22:1
85+
30->36:5
86+
30->34:5
87+
22->31:12
88+
16->26:4
89+
35->48:20
90+
18->49:9
91+
0->1:13
92+
1->2:5
93+
2->3:7
94+
3->5:6
95+
5->6:14
96+
6->7:15
97+
7->8:12
98+
8->9:8
99+
9->11:12
100+
11->12:8
101+
12->14:11
102+
14->17:11
103+
17->19:17
104+
19->21:4
105+
21->23:4
106+
23->39:7

6-dynamic-programming-applications-in-machine-learning-and-genomics/1-sequence-alignment-1/longest_path_dag_topological_order.py

+10-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from collections import namedtuple
33

44
Edge = namedtuple('Edge', ['v_no', 'w'])
5-
Vertice_Dist = namedtuple('Vertice_Dist', ['prev', 'dist'])
5+
Vertex_Distance = namedtuple('Vertex_Distance', ['predecessor', 'dist'])
66

77
class Directed_Acyclic_Graph:
88
def __init__(self, source, sink, edges):
@@ -20,7 +20,7 @@ def build_adjacency_list(self, edges):
2020
self.adjacency_list = [[] for _ in range(self.vertices_count)]
2121

2222
self.is_valid_source = True
23-
self.is_valid_sink = False
23+
self.is_valid_sink = True
2424
for edge in edges:
2525
u = int(edge.split("->")[0]) + self.v_no_label_gap
2626
v = int(edge.split("->")[1].split(":")[0]) + self.v_no_label_gap
@@ -29,11 +29,10 @@ def build_adjacency_list(self, edges):
2929
self.adjacency_list[u].append(Edge(v, w))
3030

3131
self.is_valid_source &= (v != 0)
32-
self.is_valid_sink |= (v == self.vertices_count - 1)
33-
34-
self.is_valid_source &= (len(self.adjacency_list[0]) > 0)
35-
self.is_valid_sink &= len(self.adjacency_list[self.vertices_count - 1]) == 0
36-
32+
33+
self.is_valid_source &= (len(edges) == 0 or len(self.adjacency_list[0]) > 0)
34+
self.is_valid_sink = len(self.adjacency_list[self.vertices_count - 1]) == 0
35+
3736
def check_cycke_vertex(self, u, visited, cycle):
3837

3938
visited[u] = True
@@ -89,7 +88,7 @@ def longest_path_backtrack(self, u, max_distance):
8988
longest_path = []
9089
while u != -1:
9190
longest_path.append(str(u - self.v_no_label_gap))
92-
u = max_distance[u].prev
91+
u = max_distance[u].predecessor
9392

9493
return longest_path[::-1]
9594

@@ -105,16 +104,16 @@ def compute_longest_path(self):
105104
if not self.is_valid_dag:
106105
return
107106

108-
max_distance = [Vertice_Dist(-1, - sys.maxsize - 1) for _ in range(self.vertices_count)]
109-
max_distance[0] = Vertice_Dist(-1, 0)
107+
max_distance = [Vertex_Distance(-1, - sys.maxsize - 1) for _ in range(self.vertices_count)]
108+
max_distance[0] = Vertex_Distance(-1, 0)
110109

111110
topo_sort = self.sort_topologically_dfs()
112111
for u in topo_sort:
113112
for e in self.adjacency_list[u]:
114113
v = e.v_no
115114
candidate_distance = max_distance[u].dist + e.w
116115
if max_distance[v].dist < candidate_distance:
117-
max_distance[v] = Vertice_Dist(u, candidate_distance)
116+
max_distance[v] = Vertex_Distance(u, candidate_distance)
118117

119118
sink_vertex = self.vertices_count - 1
120119
self.longest_path_len = max_distance[sink_vertex].dist

0 commit comments

Comments
 (0)