How to Implement Johnson’s Algorithm in Python

In this tutorial, we will learn how to program “How to Implement Johnson’s Algorithm in Python.” The main objective is to understand how to implement Johnson’s Algorithm. This tutorial will guide you step by step through the process of implementing Johnson’s Algorithm. By the end of this tutorial, you will have a solid understanding of how Johnson’s Algorithm works in Python, helping you strengthen your problem-solving abilities and improve your overall coding skills in data structure implementation.

This topic is straightforward and easy to understand. By simply following the instructions provided, you will be able to complete it with ease. The program will guide you step by step through the process of implementing Johnson’s Algorithm. So, let’s dive into the coding process and start implementing the solution to gain a deeper understanding of graph algorithms in Python.

Getting Started:

First you will have to download & install the Python IDLE's, here's the link for the Integrated Development And Learning Environment for Python https://www.python.org/downloads/.

Creating Main Function

This is the main function of the application. The following code will display a simple GUI in terminal console that will display program. To do this, simply copy and paste these blocks of code into the IDLE text editor.
  1. class Graph:
  2.     def __init__(self):
  3.         self.vertices = {}
  4.  
  5.     def add_vertex(self, key):
  6.         vertex = Vertex(key)
  7.         self.vertices[key] = vertex
  8.  
  9.     def get_vertex(self, key):
  10.         return self.vertices[key]
  11.  
  12.     def __contains__(self, key):
  13.         return key in self.vertices
  14.  
  15.     def add_edge(self, src_key, dest_key, weight=1):
  16.         self.vertices[src_key].add_neighbour(self.vertices[dest_key], weight)
  17.  
  18.     def does_edge_exist(self, src_key, dest_key):
  19.         return self.vertices[src_key].does_it_point_to(self.vertices[dest_key])
  20.  
  21.     def __len__(self):
  22.         return len(self.vertices)
  23.  
  24.     def __iter__(self):
  25.         return iter(self.vertices.values())
  26.  
  27.  
  28. class Vertex:
  29.     def __init__(self, key):
  30.         self.key = key
  31.         self.points_to = {}
  32.  
  33.     def get_key(self):
  34.         return self.key
  35.  
  36.     def add_neighbour(self, dest, weight):
  37.         self.points_to[dest] = weight
  38.  
  39.     def get_neighbours(self):
  40.         return self.points_to.keys()
  41.  
  42.     def get_weight(self, dest):
  43.         return self.points_to[dest]
  44.  
  45.     def set_weight(self, dest, weight):
  46.         self.points_to[dest] = weight
  47.  
  48.     def does_it_point_to(self, dest):
  49.         return dest in self.points_to
  50.  
  51.  
  52. def bellman_ford(g, source):
  53.     distance = dict.fromkeys(g, float('inf'))
  54.     distance[source] = 0
  55.  
  56.     for _ in range(len(g) - 1):
  57.         for v in g:
  58.             for n in v.get_neighbours():
  59.                 distance[n] = min(distance[n], distance[v] + v.get_weight(n))
  60.  
  61.     return distance
  62.  
  63.  
  64. def dijkstra(g, source):
  65.     unvisited = set(g)
  66.     distance = dict.fromkeys(g, float('inf'))
  67.     distance[source] = 0
  68.  
  69.     while unvisited:
  70.         closest = min(unvisited, key=lambda v: distance[v])
  71.         unvisited.remove(closest)
  72.  
  73.         for neighbour in closest.get_neighbours():
  74.             if neighbour in unvisited:
  75.                 new_distance = distance[closest] + closest.get_weight(neighbour)
  76.                 if distance[neighbour] > new_distance:
  77.                     distance[neighbour] = new_distance
  78.  
  79.     return distance
  80.  
  81.  
  82. def johnson(g):
  83.  
  84.     g.add_vertex('q')
  85.  
  86.     for v in g:
  87.         if v.get_key() != 'q':
  88.             g.add_edge('q', v.get_key(), 0)
  89.  
  90.     bell_dist = bellman_ford(g, g.get_vertex('q'))
  91.  
  92.     for v in g:
  93.         for n in v.get_neighbours():
  94.             w = v.get_weight(n)
  95.             v.set_weight(n, w + bell_dist[v] - bell_dist[n])
  96.  
  97.     del g.vertices['q']
  98.  
  99.     distance = {}
  100.  
  101.     for v in g:
  102.         distance[v] = dijkstra(g, v)
  103.  
  104.     for v in g:
  105.         for w in g:
  106.             distance[v][w] += bell_dist[w] - bell_dist[v]
  107.  
  108.     return distance
  109.  
  110.  
  111. # MAIN PROGRAM
  112. while True:
  113.  
  114.     print("\n================= Implement Johnson’s Algorithm =================\n")
  115.  
  116.     g = Graph()
  117.  
  118.     print("Menu")
  119.     print("add vertex <key>")
  120.     print("add edge <src> <dest> <weight>")
  121.     print("johnson")
  122.     print("display")
  123.     print("quit")
  124.  
  125.     while True:
  126.  
  127.         do = input("\nWhat would you like to do? ").split()
  128.  
  129.         if len(do) == 0:
  130.             continue
  131.  
  132.         operation = do[0]
  133.  
  134.         if operation == "add":
  135.  
  136.             suboperation = do[1]
  137.  
  138.             if suboperation == "vertex":
  139.                 key = int(do[2])
  140.  
  141.                 if key not in g:
  142.                     g.add_vertex(key)
  143.                 else:
  144.                     print("Vertex already exists.")
  145.  
  146.             elif suboperation == "edge":
  147.  
  148.                 src = int(do[2])
  149.                 dest = int(do[3])
  150.                 weight = int(do[4])
  151.  
  152.                 if src not in g:
  153.                     print(f"Vertex {src} does not exist.")
  154.                 elif dest not in g:
  155.                     print(f"Vertex {dest} does not exist.")
  156.                 else:
  157.                     if not g.does_edge_exist(src, dest):
  158.                         g.add_edge(src, dest, weight)
  159.                     else:
  160.                         print("Edge already exists.")
  161.  
  162.         elif operation == "johnson":
  163.  
  164.             distance = johnson(g)
  165.  
  166.             print("\nShortest distances:")
  167.             for start in g:
  168.                 for end in g:
  169.                     print(f"{start.get_key()} to {end.get_key()} distance {distance[start][end]}")
  170.  
  171.         elif operation == "display":
  172.  
  173.             print("Vertices:", end=" ")
  174.             for v in g:
  175.                 print(v.get_key(), end=" ")
  176.             print()
  177.  
  178.             print("Edges:")
  179.             for v in g:
  180.                 for dest in v.get_neighbours():
  181.                     w = v.get_weight(dest)
  182.                     print(f"(src={v.get_key()}, dest={dest.get_key()}, weight={w})")
  183.  
  184.         elif operation == "quit":
  185.             break
  186.  
  187.         else:
  188.             print("Invalid command.")
  189.  
  190.     # Try Again Option
  191.     opt = input("\nDo you want to try again? (yes/no): ").strip().lower()
  192.  
  193.     if opt == "no":
  194.         print("Exiting program...")
  195.         break
  196.     elif opt != "yes":
  197.         print("Invalid choice. Exiting program...")
  198.         break
This program demonstrates how to implement Johnson’s Algorithm in Python to compute the shortest paths between all pairs of vertices in a weighted directed graph. The program defines `Graph` and `Vertex` classes to manage vertices, edges, and weights, allowing users to build a graph interactively by adding vertices and edges through a menu-driven interface. Johnson’s Algorithm works by first adding a temporary vertex and running the Bellman-Ford algorithm to compute vertex potentials and detect negative edge weights. These values are then used to reweight the graph edges so that all weights become non-negative. After reweighting, the program runs Dijkstra’s algorithm from each vertex to calculate the shortest paths efficiently. Finally, the distances are adjusted back to their original values and displayed as the shortest distance between every pair of vertices. The program also includes options to display the graph structure and repeat the process until the user chooses to exit.

Output:

There you have it we successfully created How to Implement Johnson’s Algorithm in Python. I hope that this simple tutorial help you to what you are looking for. For more updates and tutorials just kindly visit this site. Enjoy Coding!

More Tutorials for Python Language

Python Tutorials