|
26 | 26 | "metadata": {}, |
27 | 27 | "source": [ |
28 | 28 | "Let's say you want to travel from Delhi(DEL), India to London(LCY), UK via flights that have various routes with different stops, namely, Frankfurt(FRA), Zurich(ZRH), Amsterdam(AMS), Geneva(GVA) and Dublin(DUB). Now, you want to find the shortest path as you are in a hurry and want to get to London as soon as possible.<br> \n", |
29 | | - "An important thing to know is that any subpath from C -> E of the shortest path A -> E is also the shortest path from node C to node E. That means not only we'll get the shortest path from Delhi to London but also to other stops from Delhi.\n", |
| 29 | + "An important thing to know is that any subpath from C $\\rightarrow$ E of the shortest path A $\\rightarrow$ E is also the shortest path from node C to node E. That means not only one will get the shortest path from Delhi to London but also to other stops from Delhi.\n", |
30 | 30 | "\n", |
31 | 31 | "<b>ASSUMPTIONS</b>\n", |
32 | 32 | "- Distance taken is imaginary.\n", |
|
84 | 84 | "## Dijkstra's Algorithm\n", |
85 | 85 | "\n", |
86 | 86 | "Dijkstra's algorithm is used to find the shortest path between nodes or commonly from one source node to every other node in the graph, where edge weight represents the cost/ distance between 2 nodes in the case of a weighted graph. It can work with both directed and undirected graphs, but <b>it is not suitable for graphs with NEGATIVE edges.</b><br>\n", |
87 | | - "Time complexity of Dijkstra's algorithm is $O(V^{2})$, but with minimum priority queue, it comes down to $O(V + E log V)$\n", |
| 87 | + "Time complexity of Dijkstra's algorithm is $O(\\ V^{2})$, but with minimum priority queue, it comes down to $O(\\ V + E\\text{ log } V\\ )$\n", |
88 | 88 | "\n", |
89 | 89 | "### Algorithm\n", |
90 | 90 | "\n", |
91 | 91 | "1. Convert your problem into a graph equivalent.\n", |
92 | 92 | "2. Create a list of unvisited vertices. \n", |
93 | | - "3. Assign the starting point as source node with distance(cost)= 0 and other node's distance as infinity.\n", |
| 93 | + "3. Assign the starting point as source node with <b>distance(cost)= 0</b> and other node's distance as infinity.\n", |
94 | 94 | "4. For every unvisited neighbour, calculate the minimum distance from the current node.\n", |
95 | 95 | "5. The new distance is calculated as `minimum(current distance, distance of previous node + edge weight)`\n", |
96 | 96 | "6. When all the neighbours have been visited, remove the node from the unvisited list and select the next node with the minimum distance.\n", |
|
102 | 102 | "cell_type": "markdown", |
103 | 103 | "metadata": {}, |
104 | 104 | "source": [ |
105 | | - "Let's look at the example of the directed graph we were talking about. But, before moving forward, here are some things you should keep in mind. In the following graphs, edge weight defines the distance between 2 nodes, black edge represents unvisited edges, red represents edges that are being traversed, and green represents visited edges. Let's begin!!" |
| 105 | + "Let's look at the example of the directed graph mentioned above. But, before moving forward, here are some things one should keep in mind. In the following graphs, edge weight defines the distance between 2 nodes, black edge represents unvisited edges, red represents edges that are being traversed, and green represents visited edges. Let's begin!!" |
106 | 106 | ] |
107 | 107 | }, |
108 | 108 | { |
109 | 109 | "cell_type": "markdown", |
110 | 110 | "metadata": {}, |
111 | 111 | "source": [ |
112 | 112 | "According to Dijkstra's algorithm,\n", |
113 | | - "- First, we'll assign all stops(nodes) infinite values except the source node (DEL in our case as our path starts from Delhi), which is assigned a value of 0. This is because we are assuming that we are not aware of the distance one needs to cover to reach other nodes and hence assign it the maximum value possible. (fig. 1)\n", |
114 | | - "- Dijkstra is based on the greedy approach, which means we'll select the node with the minimum distance, which is DEL having a distance of 0 units, and this approach is being followed in the whole process.\n", |
115 | | - "- The next step is to start traversing the neighbours of DEL and update the distance of all neighbouring nodes as you can see in fig. 2. While updating the distance, always keep in mind that the updated distance should be `minimum(current distance, distance of previous node + edge weight)`. Like, \n", |
| 113 | + "- First, assign all stops(nodes) infinite values except the source node (DEL in this case as the path starts from Delhi), which is assigned a value of 0. This is because the distance one needs to cover to reach other nodes is assumed to be unknown and, hence maximum value possible is being assigned. (fig. 1)\n", |
| 114 | + "- Dijkstra is based on the greedy approach, which means one needs to select the node with the minimum distance, which is DEL having a distance of 0 units, and this approach is being followed in the whole process.\n", |
| 115 | + "- The next step is to start traversing the neighbours of DEL and update the distance of all neighbouring nodes as shown in fig. 2. While updating the distance, always keep in mind that the updated distance should be `minimum(current distance, distance of previous node + edge weight)`. Like, \n", |
116 | 116 | " - DUB : `min(infinity, 7) = 7`\n", |
117 | 117 | " - FRA : `min(infinity, 6) = 6`\n", |
118 | 118 | " - ZRH : `min(infinity, 5) = 5`" |
|
122 | 122 | "cell_type": "markdown", |
123 | 123 | "metadata": {}, |
124 | 124 | "source": [ |
125 | | - "" |
| 125 | + "" |
126 | 126 | ] |
127 | 127 | }, |
128 | 128 | { |
|
141 | 141 | "cell_type": "markdown", |
142 | 142 | "metadata": {}, |
143 | 143 | "source": [ |
144 | | - "" |
| 144 | + "" |
145 | 145 | ] |
146 | 146 | }, |
147 | 147 | { |
148 | 148 | "cell_type": "markdown", |
149 | 149 | "metadata": {}, |
150 | 150 | "source": [ |
151 | | - "- Here, we have 2 nodes with minimum distance (7 units), AMS and DUB. So, let's update their neighbours one by one.(fig. 5)\n", |
| 151 | + "- Here, 2 nodes are left with minimum distance (7 units), AMS and DUB. So, let's update their neighbours one by one.(fig. 5)\n", |
152 | 152 | " - DUB :\n", |
153 | 153 | " - AMS : `min(7, 7+2) = 7`\n", |
154 | 154 | " - LCY : `min(9, 7+4) = 9`\n", |
|
157 | 157 | "- Among the last 2 nodes, our destination is LCY. So, last update is for GVA's neighbour.\n", |
158 | 158 | " - LCY : `min(9, 8+1) = 9`\n", |
159 | 159 | " \n", |
160 | | - "Figure 6 shows us the final graph with shortest distance to each node from DEL(source node) and it comes out that the shortest distance to LCY from DEL is 9 units which have 2 paths:<br>\n", |
| 160 | + "Figure 6 shows the final graph with shortest distance to each node from DEL(source node) and it comes out that the shortest distance to LCY from DEL is 9 units which have 2 paths:<br>\n", |
161 | 161 | "- (DEL -> FRA -> LCY) <br>\n", |
162 | 162 | "- (DEL -> ZRH -> GVA -> LCY)\n", |
163 | 163 | "\n", |
164 | | - "So, now we know that one can take any of these paths to reach as soon as possible. But, in case there are more than one path like in this situation, <b>dijkstra's algorithm returns the shortest path with minimum number of edges. </b>" |
| 164 | + "So, one can take any of these paths to reach as soon as possible. But, in case there are more than one path like in this situation, <b>dijkstra's algorithm returns the shortest path with minimum number of edges. </b>" |
165 | 165 | ] |
166 | 166 | }, |
167 | 167 | { |
168 | 168 | "cell_type": "markdown", |
169 | 169 | "metadata": {}, |
170 | 170 | "source": [ |
171 | | - "" |
| 171 | + "" |
172 | 172 | ] |
173 | 173 | }, |
174 | 174 | { |
|
182 | 182 | "cell_type": "markdown", |
183 | 183 | "metadata": {}, |
184 | 184 | "source": [ |
185 | | - "In our example the number of nodes were less and it wasn't that complicated, but, in real life problems, there can be a lot of nodes and thus, it is needed to maintain proper record. Let's see our example in NetworkX implementation." |
| 185 | + "In the previous example the number of nodes were less and it wasn't that complicated, but, in real life problems, there can be a lot of nodes and thus, it is needed to maintain proper record. Let's see the example in NetworkX implementation." |
186 | 186 | ] |
187 | 187 | }, |
188 | 188 | { |
|
205 | 205 | "from itertools import count\n", |
206 | 206 | "\n", |
207 | 207 | "'''\n", |
208 | | - "So, we already have our graph 'flight_path' with all nodes and edges. Now, before implementing the algorithm, \n", |
209 | | - "we first need to make the data available in the proper format to access.\n", |
| 208 | + "So, the graph 'flight_path' is already defined with all nodes and edges. Now, before implementing the algorithm, \n", |
| 209 | + "one first needs to make the data available in the proper format to access.\n", |
210 | 210 | "\n", |
211 | | - "The first thing to do is to have a dictionary with every node as keys and (connecting node, weight) as values so that we can \n", |
| 211 | + "The first thing to do is to have a dictionary with every node as keys and (connecting node, weight) as values so that one can\n", |
212 | 212 | "traverse easily.\n", |
213 | 213 | "'''\n", |
214 | 214 | "flight_succ = flight_path._succ if flight_path.is_directed() else flight_path._adj\n", |
|
220 | 220 | "weight = _weight_function(flight_path, \"weight\")\n", |
221 | 221 | "\n", |
222 | 222 | "'''\n", |
223 | | - "The next step is to define various dictionaries so that we can store and track all nodes path.\n", |
| 223 | + "The next step is to define various dictionaries to store and track all nodes path.\n", |
224 | 224 | "'''\n", |
225 | 225 | "dist = {} # dictionary of final distances\n", |
226 | 226 | "seen = {} # dictionary of visited nodes with recent shortest distance\n", |
|
241 | 241 | "push(fringe, (0, next(c), source))\n", |
242 | 242 | "\n", |
243 | 243 | "'''\n", |
244 | | - "It's time to start traversing our graph starting from source node.\n", |
| 244 | + "It's time to start traversing the graph starting from source node.\n", |
245 | 245 | "'''\n", |
246 | 246 | "\n", |
247 | 247 | "while fringe: \n", |
|
252 | 252 | " if v == target: \n", |
253 | 253 | " break\n", |
254 | 254 | " \n", |
255 | | - " # Now, we are traversing the neighbours of the node\n", |
| 255 | + " # traversing the neighbours of the node\n", |
256 | 256 | " for u, e in flight_succ[v].items(): \n", |
257 | 257 | " distance = weight(v, u, e)\n", |
258 | 258 | " \n", |
|
262 | 262 | " vu_dist = dist[v] + distance \n", |
263 | 263 | " \n", |
264 | 264 | " '''\n", |
265 | | - " If u is already in dist then there can be 2 cases, either our graph has negative cycle or we might\n", |
266 | | - " have found another shortest path to u.\n", |
| 265 | + " If u is already in dist then there can be 2 cases, either the graph has negative cycle or there might\n", |
| 266 | + " be another shortest path to u.\n", |
267 | 267 | " '''\n", |
268 | 268 | " if u in dist:\n", |
269 | 269 | " u_dist = dist[u]\n", |
|
277 | 277 | " if paths is not None:\n", |
278 | 278 | " paths[u] = paths[v] + [u]\n", |
279 | 279 | "\n", |
280 | | - "# printing the distance and path from our source node 'DEL' to target node 'LCY' \n", |
| 280 | + "# printing the distance and path from the source node 'DEL' to target node 'LCY' \n", |
281 | 281 | "print(dist[target], paths[target])" |
282 | 282 | ] |
283 | 283 | }, |
|
287 | 287 | "source": [ |
288 | 288 | "Don't worry, you don't need to write all this code again and again. NetworkX got you covered!! So, NetworkX provides a lot of functions with the help of which one can actually find the [shortest path](https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html) based on their needs. \n", |
289 | 289 | "\n", |
290 | | - "All functions using dijkstra's algorithm are similar, but, for our example the most suitable is [single_source_dijkstra()](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.single_source_dijkstra.html#networkx.algorithms.shortest_paths.weighted.single_source_dijkstra). It comes out that this function actually give us the same output as we calculated in our example." |
| 290 | + "All functions using dijkstra's algorithm are similar, but, for this example the most suitable is [single_source_dijkstra()](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.single_source_dijkstra.html#networkx.algorithms.shortest_paths.weighted.single_source_dijkstra). It comes out that this function actually gives the same output as the one calculated in the above example." |
291 | 291 | ] |
292 | 292 | }, |
293 | 293 | { |
|
319 | 319 | "It is used as a part of applications to find the shortest path if required. There are other factors as well which are considered in every application while implementing Dijkstra's algorithm. Like,\n", |
320 | 320 | "- In special drones or robots for delivery service, it is used as a part to identify the shortest path possible.\n", |
321 | 321 | "- One of the most common use case is Google Maps. It helps to find the best route possible in shortest time.\n", |
322 | | - "- In social media applications, for smaller graphs it can be used effectively to suggest you \"people you may know\" section.\n", |
323 | | - "- As our example, it can be used in a software which calculates and informs the estimate arrival time, best route etc. of a flight to a user.\n", |
| 322 | + "- In social media applications, for smaller graphs it can be used effectively to suggest the \"people you may know\" section.\n", |
| 323 | + "- As the above example, it can be used in a software which calculates and informs the estimate arrival time, best route etc. of a flight to a user.\n", |
324 | 324 | "- It is used in IP routing to find Open shortest Path First.\n", |
325 | 325 | "- It is used in the telephone network." |
326 | 326 | ] |
|
340 | 340 | "- It cannot handle negative weights which leads to acyclic graphs and most often cannot obtain the right shortest path.\n", |
341 | 341 | "- It is a greedy algorithm that means it is possible for the algorithm to select the current best option which can make the algorithm get sidetracked following a potential path that doesn’t exist, simply because the edges along it form a short path." |
342 | 342 | ] |
| 343 | + }, |
| 344 | + { |
| 345 | + "cell_type": "markdown", |
| 346 | + "metadata": {}, |
| 347 | + "source": [ |
| 348 | + "#### Reference\n", |
| 349 | + "\n", |
| 350 | + "Shivani Sanan, Leena jain, Bharti Kappor (2013). (IJAIEM) \"Shortest Path Algorithm\" <br>\n", |
| 351 | + "https://www.ijaiem.org/volume2issue7/IJAIEM-2013-07-23-079.pdf" |
| 352 | + ] |
343 | 353 | } |
344 | 354 | ], |
345 | 355 | "metadata": { |
|
0 commit comments