├── DFS ├── input.txt ├── README.md └── dfs_visual.py ├── Assignment Problem ├── input.txt ├── README.md └── assignment_prob_hungarian.py ├── BFS ├── input.txt ├── README.md └── bfs.py ├── Topological Sort ├── input.txt ├── topological_sort.py └── README.md ├── K Centers Problem ├── input.txt ├── k_centers_problem.py └── README.md ├── Kruskal's ├── input.txt ├── README.md └── kruskals_quick_union.py ├── Prim's ├── input.txt ├── prims.py └── README.md ├── Travelling Salesman Problem ├── input.txt ├── README.md └── tsp_christofides.py ├── BellmanFord ├── input.txt └── BellmanFord.py ├── Dijsktra's ├── input.txt ├── dijsktras.py └── README.md ├── Egocentric Network ├── input.txt ├── egocentric_network_1.py ├── egocentric_network_1_5.py └── egocentric_network_2.py ├── Graph Coloring ├── input.txt ├── graph_coloring.py └── README.md ├── Greedy BFS ├── heuristics.txt ├── input.txt ├── greedy_bfs.py └── README.md ├── A_star_search ├── heuristics.txt ├── input.txt ├── a_star_search.py └── README.md ├── setup.sh └── README.md /DFS/input.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 0 5 0 5 3 | 5 0 5 0 4 | 0 5 0 5 5 | 5 0 5 0 6 | 0 7 | -------------------------------------------------------------------------------- /Assignment Problem/input.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 9 2 7 8 3 | 6 4 3 7 4 | 5 8 1 8 5 | 7 6 9 4 -------------------------------------------------------------------------------- /BFS/input.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 0 5 10 5 3 | 0 0 5 0 4 | 0 10 0 0 5 | 0 0 10 0 6 | 0 7 | -------------------------------------------------------------------------------- /Topological Sort/input.txt: -------------------------------------------------------------------------------- 1 | 6 2 | 1 2 3 | 1 3 4 | 2 3 5 | 2 4 6 | 3 4 7 | 3 5 8 | -------------------------------------------------------------------------------- /K Centers Problem/input.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 0 10 7 6 3 | 10 0 8 5 4 | 7 8 0 12 5 | 6 5 12 0 6 | 2 -------------------------------------------------------------------------------- /Kruskal's/input.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 0 2 7 -1 -1 3 | 2 0 3 8 5 4 | 7 3 0 1 -1 5 | -1 8 1 0 4 6 | -1 5 -1 4 0 -------------------------------------------------------------------------------- /Prim's/input.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 0 2 7 -1 -1 3 | 2 0 3 8 5 4 | 7 3 0 1 -1 5 | -1 8 1 0 4 6 | -1 5 -1 4 0 -------------------------------------------------------------------------------- /Travelling Salesman Problem/input.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 0 10 8 9 7 3 | 10 0 10 5 6 4 | 8 10 0 8 9 5 | 9 5 8 0 6 6 | 7 6 9 6 0 -------------------------------------------------------------------------------- /BellmanFord/input.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 0 2 7 -1 -1 3 | -1 0 3 8 5 4 | -1 2 0 1 -1 5 | -1 -1 -1 0 4 6 | -1 -1 -1 5 0 7 | 0 8 | -------------------------------------------------------------------------------- /Dijsktra's/input.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 0 2 7 -1 -1 3 | -1 0 3 8 5 4 | -1 2 0 1 -1 5 | -1 -1 -1 0 4 6 | -1 -1 -1 5 0 7 | 0 8 | 9 | -------------------------------------------------------------------------------- /Egocentric Network/input.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 11 3 | 1 2 4 | 1 4 5 | 1 3 6 | 3 9 7 | 3 6 8 | 6 8 9 | 8 9 10 | 6 9 11 | 4 6 12 | 4 5 13 | 5 7 14 | 9 -------------------------------------------------------------------------------- /Graph Coloring/input.txt: -------------------------------------------------------------------------------- 1 | 16 2 | 0 7 3 | 0 1 4 | 1 3 5 | 3 2 6 | 3 8 7 | 3 10 8 | 7 8 9 | 7 9 10 | 7 10 11 | 7 6 12 | 8 9 13 | 9 10 14 | 6 5 15 | 10 4 16 | 5 4 17 | 6 10 -------------------------------------------------------------------------------- /Greedy BFS/heuristics.txt: -------------------------------------------------------------------------------- 1 | Arad 366 2 | Bucharest 0 3 | Craiova 160 4 | Dobreta 242 5 | Eforie 161 6 | Fagaras 178 7 | Giurgiu 77 8 | Hirsova 151 9 | Iasi 226 10 | Lugoj 244 11 | Mehadia 241 12 | Neamt 234 13 | Oradea 380 14 | Pitesti 98 15 | Rimnicu_Vilcea 193 16 | Sibiu 253 17 | Timisoara 329 18 | Urziceni 80 19 | Vaslui 199 20 | Zerind 374 -------------------------------------------------------------------------------- /A_star_search/heuristics.txt: -------------------------------------------------------------------------------- 1 | Arad 366 2 | Bucharest 0 3 | Craiova 160 4 | Dobreta 242 5 | Eforie 161 6 | Fagaras 178 7 | Giurgiu 77 8 | Hirsova 151 9 | Iasi 226 10 | Lugoj 244 11 | Mehadia 241 12 | Neamt 234 13 | Oradea 380 14 | Pitesti 98 15 | Rimnicu_Vilcea 193 16 | Sibiu 253 17 | Timisoara 329 18 | Urziceni 80 19 | Vaslui 199 20 | Zerind 374 -------------------------------------------------------------------------------- /A_star_search/input.txt: -------------------------------------------------------------------------------- 1 | 23 2 | Arad Sibiu 140 3 | Arad Timisoara 118 4 | Arad Zerind 75 5 | Bucharest Fagaras 211 6 | Bucharest Giurgiu 90 7 | Bucharest Pitesti 101 8 | Bucharest Urziceni 85 9 | Craiova Dobreta 120 10 | Craiova Pitesti 138 11 | Craiova Rimnicu_Vilcea 146 12 | Dobreta Mehadia 75 13 | Eforie Hirsova 86 14 | Fagaras Sibiu 99 15 | Hirsova Urziceni 98 16 | Iasi Neamt 87 17 | Iasi Vaslui 92 18 | Lugoj Mehadia 70 19 | Lugoj Timisoara 111 20 | Oradea Zerind 71 21 | Oradea Sibiu 151 22 | Pitesti Rimnicu_Vilcea 97 23 | Rimnicu_Vilcea Sibiu 80 24 | Urziceni Vaslui 142 25 | Arad 26 | Bucharest -------------------------------------------------------------------------------- /Greedy BFS/input.txt: -------------------------------------------------------------------------------- 1 | 23 2 | Arad Sibiu 140 3 | Arad Timisoara 118 4 | Arad Zerind 75 5 | Bucharest Fagaras 211 6 | Bucharest Giurgiu 90 7 | Bucharest Pitesti 101 8 | Bucharest Urziceni 85 9 | Craiova Dobreta 120 10 | Craiova Pitesti 138 11 | Craiova Rimnicu_Vilcea 146 12 | Dobreta Mehadia 75 13 | Eforie Hirsova 86 14 | Fagaras Sibiu 99 15 | Hirsova Urziceni 98 16 | Iasi Neamt 87 17 | Iasi Vaslui 92 18 | Lugoj Mehadia 70 19 | Lugoj Timisoara 111 20 | Oradea Zerind 71 21 | Oradea Sibiu 151 22 | Pitesti Rimnicu_Vilcea 97 23 | Rimnicu_Vilcea Sibiu 80 24 | Urziceni Vaslui 142 25 | Arad 26 | Bucharest -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $(uname -s) == "Linux" ]; then 3 | declare -a distributions=("Manjaro" "Ubuntu" "Arch"); 4 | declare -a distpackagemgrs=("1" "0" "1"); 5 | declare -a packagemgr=("apt-get" "pacman"); 6 | 7 | dist_count=${#distributions[*]} 8 | usable_mgr="-1" 9 | 10 | dist_name=$(lsb_release -a); 11 | 12 | for (( i=0; i<=$(( $dist_count -1 )); i++ )) 13 | do 14 | if [ $(echo "$dist_name" | grep -c "${distributions[$i]}") -gt 0 ]; then 15 | usable_mgr=${distpackagemgrs[$i]} 16 | echo "Found Distribution ${distributions[$i]}, will use ${packagemgr[usable_mgr]}" 17 | fi 18 | done 19 | 20 | if [ $usable_mgr == "-1" ]; then 21 | echo "Err: Linux distibution unknown, will use apt-get" 22 | usable_mgr="0" 23 | fi 24 | 25 | case $usable_mgr in 26 | "0") 27 | echo "-- apt-get install --" 28 | sudo apt-get install python2.7-dev python-pip -y 29 | 30 | ;; 31 | "1") 32 | echo "-- pacman installation --" 33 | sudo pacman -S python2 python-pip -y 34 | 35 | ;; 36 | esac 37 | fi 38 | 39 | if [ $(uname -s) == "Darwin" ]; then 40 | sudo easy_install pip 41 | 42 | fi 43 | 44 | sudo pip2 install matplotlib 45 | sudo pip2 install networkx 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /DFS/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of DFS traversal using networkx library 2 | 3 | ### INPUT ### 4 | 5 | Graph is first drawn from the weighted matrix input from the user. 6 | Input is taken from the file 7 | #### input.txt #### 8 | 9 | Sample input 10 | ``` 11 | 4 12 | 0 5 0 5 13 | 5 0 5 0 14 | 0 5 0 5 15 | 5 0 5 0 16 | 0 17 | 18 | ``` 19 | First line contains the number of nodes,say n.(Nodes are numbered as 0,1,2,...(n-1) ) 20 | Followed by n*n weighted matrix. Disconnected egdes are represented by negative weight. 21 | Last line contains the source node.(i.e, the node from which the DFS should begin) 22 | 23 | Visualization of the input graph- 24 | ![1](https://user-images.githubusercontent.com/22571531/27984144-547decd6-63eb-11e7-9ddc-487d976b0fec.png) 25 | 26 | ### DFS traversal ### 27 | 28 | Recursive DFS is performed, resulting DFS forests are stored in a stack. 29 | 30 | ### Visulization of DFS path ### 31 | 32 | The stack is then used to mark the DFS traversed edges with a different colour(Here, Red. So, as to distinguish itself from the rest). 33 | Visualization of the result- 34 | ![2](https://user-images.githubusercontent.com/22571531/27984145-593846ae-63eb-11e7-91bc-4c69ba5ba12a.png) 35 | 36 | ### Complexity ### 37 | 38 | Time: 0(m+n) 39 | where m - number of edges 40 | n - number of nodes 41 | 42 | -------------------------------------------------------------------------------- /BFS/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of BFS traversal using networkx library 2 | 3 | ### INPUT ### 4 | 5 | 6 | Input is taken from the file 7 | #### input.txt #### 8 | 9 | Sample input 10 | ``` 11 | 4 12 | 0 5 10 5 13 | 0 0 5 0 14 | 0 10 0 0 15 | 0 0 10 0 16 | 0 17 | 18 | 19 | ``` 20 | First line contains the number of nodes,say n.(Nodes are numbered as 0,1,2,...(n-1) ) 21 | Followed by n*n weighted matrix. Disconnected egdes are represented by negative weight. 22 | Last line contains the source node.(i.e, the node from which the BFS should begin) 23 | 24 | 25 | ### Draw Graph ### 26 | 27 | 28 | Graph is first drawn from the weighted matrix input from the user with weights shown. Edges are marked with black. 29 | visualization of the input graph- 30 | ![1](https://user-images.githubusercontent.com/22571531/27984139-48d91928-63eb-11e7-9634-fed45cec799a.png) 31 | 32 | 33 | ### BFS traversal ### 34 | 35 | Iterative BFS is performed, using a queue. Each time an edge is encountered, 36 | it is marked with red on the graph through the line - 37 | ``` 38 | nx.draw_networkx_edges(G,pos,edgelist=[(curr_node,i)],width=2.5,alpha=0.6,edge_color='r') 39 | 40 | ``` 41 | Visualization of the result- 42 | ![2](https://user-images.githubusercontent.com/22571531/27984141-4d665e42-63eb-11e7-97e6-49f28ff1552e.png) 43 | 44 | ### Complexity ### 45 | 46 | Time: 0(m+n) 47 | where m - number of edges 48 | n - number of nodes 49 | 50 | 51 | -------------------------------------------------------------------------------- /BFS/bfs.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | 6 | #BFS traversal 7 | def BFS(G, source, pos): 8 | visited = [False]*(len(G.nodes())) 9 | queue = [] #a queue for BFS traversal 10 | queue.append(source) 11 | visited[source] = True 12 | while queue: 13 | curr_node = queue.pop(0) 14 | for i in G[curr_node]: #iterates through all the possible vertices adjacent to the curr_node 15 | if visited[i] == False: 16 | queue.append(i) 17 | visited[i] = True 18 | # nx.draw_networkx_edges(G, pos, edgelist = [(curr_node,i)], width = 2.5, alpha = 0.6, edge_color = 'r') 19 | return 20 | 21 | 22 | 23 | #takes input from the file and creates a weighted graph 24 | def CreateGraph(): 25 | G = nx.DiGraph() 26 | f = open('input.txt') 27 | n = int(f.readline()) 28 | wtMatrix = [] 29 | for i in range(n): 30 | list1 = list(map(int, (f.readline()).split())) 31 | wtMatrix.append(list1) 32 | source = int(f.readline()) #source vertex from where BFS has to start 33 | #Adds egdes along with their weights to the graph 34 | for i in range(n): 35 | for j in range(len(wtMatrix[i])): 36 | if wtMatrix[i][j] > 0: 37 | G.add_edge(i, j, length = wtMatrix[i][j]) 38 | return G, source 39 | 40 | 41 | 42 | #draws the graph and displays the weights on the edges 43 | def DrawGraph(G): 44 | pos = nx.spring_layout(G) 45 | nx.draw(G, pos, with_labels = True) #with_labels=true is to show the node number in the output graph 46 | edge_labels = dict([((u,v,), d['length']) for u, v, d in G.edges(data = True)]) 47 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, label_pos = 0.3, font_size = 11) #prints weight on all the edges 48 | return pos 49 | 50 | 51 | 52 | #main function 53 | if __name__== "__main__": 54 | G,source = CreateGraph() 55 | pos = DrawGraph(G) 56 | BFS(G, source, pos) 57 | plt.show() 58 | 59 | -------------------------------------------------------------------------------- /Topological Sort/topological_sort.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def topologicalSort(G,pos): 6 | zero_indeg_list = [] 7 | sorted_list = [] 8 | visited = [False]*len(G.nodes()) 9 | while len(G.nodes())!=0: 10 | for node in G.nodes(): 11 | if visited[node-1] == False: 12 | if G.in_degree(node) == 0: 13 | visited[node-1] = True 14 | zero_indeg_list.append(node) 15 | for node in zero_indeg_list: 16 | sorted_list.append(node) 17 | G.remove_node(node) 18 | zero_indeg_list.remove(node) 19 | return sorted_list 20 | 21 | 22 | #takes input from the file and creates a directed graph 23 | def CreateResultGraph(sorted_list): 24 | D = nx.DiGraph() 25 | for i in range(len(sorted_list)-1): 26 | D.add_edge(sorted_list[i], sorted_list[i+1]) 27 | pos = nx.spring_layout(D) 28 | val_map = {} 29 | val_map[sorted_list[0]] = 'green' 30 | val_map[sorted_list[len(sorted_list)-1]] = 'red' 31 | values = [val_map.get(node, 'blue') for node in D.nodes()] 32 | nx.draw(D, pos, with_labels = True, node_color =values) 33 | 34 | 35 | #takes input from the file and creates a directed graph 36 | def CreateGraph(): 37 | G = nx.DiGraph() 38 | f = open('input.txt') 39 | n = int(f.readline()) 40 | for i in range(n): 41 | adj_list = map(int, (f.readline()).split()) 42 | G.add_edge(adj_list[0], adj_list[1]) 43 | return G 44 | 45 | 46 | 47 | #draws the graph 48 | def DrawGraph(G): 49 | pos = nx.spring_layout(G) 50 | nx.draw(G, pos, with_labels = True, node_color ='blue') #with_labels=true is to show the node number in the output graph 51 | return pos 52 | 53 | 54 | 55 | #main function 56 | if __name__== "__main__": 57 | G = CreateGraph() 58 | plt.figure(1) 59 | pos = DrawGraph(G) 60 | plt.figure(2) 61 | sorted_list = topologicalSort(G,pos) 62 | CreateResultGraph(sorted_list) 63 | plt.show() 64 | 65 | -------------------------------------------------------------------------------- /Assignment Problem/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Assignment Problem using networkx library 2 | 3 | ### INPUT ### 4 | 5 | 6 | Input is taken from the file 7 | #### input.txt #### 8 | 9 | Sample input 10 | ``` 11 | 4 12 | 9 2 7 8 13 | 6 4 3 7 14 | 5 8 1 8 15 | 7 6 9 4 16 | 17 | ``` 18 | First line contains n, the number of people which is the same as the number of jobs. 19 | Followed by n*n weighted profit matrix. 20 | 21 | 22 | ### Draw Graph ### 23 | 24 | 25 | A bipartite graph is to be drawn. Person and Job - are the 2 sets of nodes. Since, person is connected to every possible job and a job has connection from every person. 26 | 27 | ![1](https://user-images.githubusercontent.com/22571531/27514223-5fa03ec4-59a1-11e7-9bdc-8d9c17afc030.png) 28 | 29 | 30 | ### Assignment Problem ### 31 | 32 | Assignment Problem is a combinatorial optimization problem. It consists of finding a maximum weight matching (or minimum weight perfect matching) in a weighted bipartite graph. 33 | 34 | Here, we have n people and n jobs that need to be done. Given profit matrix, we need to assign exactly one person to each job and exactly one job to each person in such a way that the total profit of the assignment in maximized. 35 | (It is a linear assignment problem, since number of people and jobs are equal.) 36 | 37 | Hungarian algorithm is one of the most effient methods that solves the linear assignment problem in polynomial time(with a time complexity of O(n^3)). 38 | 39 | The code here,is an implementation of Hungarian algorithm. 40 | The resultant graph for the sample input with maximum weight matching (denoted by red edges): 41 | 42 | ![2](https://user-images.githubusercontent.com/22571531/27514224-645f8028-59a1-11e7-92b0-5f0d7f0b8b02.png) 43 | 44 | #### Complexity #### 45 | 46 | Time: O(n^3) 47 | n - number of people( = number of jobs) 48 | -------------------------------------------------------------------------------- /Graph Coloring/graph_coloring.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | #implementation of welsh_powell algorithm 6 | def welsh_powell(G): 7 | #sorting the nodes based on it's valency 8 | node_list = sorted(G.nodes(), key =lambda x:G.neighbors(x)) 9 | col_val = {} #dictionary to store the colors assigned to each node 10 | col_val[node_list[0]] = 0 #assign the first color to the first node 11 | # Assign colors to remaining N-1 nodes 12 | for node in node_list[1:]: 13 | available = [True] * len(G.nodes()) #boolean list[i] contains false if the node color 'i' is not available 14 | 15 | #iterates through all the adjacent nodes and marks it's color as unavailable, if it's color has been set already 16 | for adj_node in G.neighbors(node): 17 | if adj_node in col_val.keys(): 18 | col = col_val[adj_node] 19 | available[col] = False 20 | clr = 0 21 | for clr in range(len(available)): 22 | if available[clr] == True: 23 | break 24 | col_val[node] = clr 25 | print col_val 26 | return col_val 27 | 28 | 29 | 30 | 31 | 32 | #takes input from the file and creates a undirected graph 33 | def CreateGraph(): 34 | G = nx.Graph() 35 | f = open('input.txt') 36 | n = int(f.readline()) 37 | for i in range(n): 38 | graph_edge_list = f.readline().split() 39 | G.add_edge(graph_edge_list[0], graph_edge_list[1]) 40 | return G 41 | 42 | 43 | #draws the graph and displays the weights on the edges 44 | def DrawGraph(G,col_val): 45 | pos = nx.spring_layout(G) 46 | values = [col_val.get(node, 'blue') for node in G.nodes()] 47 | nx.draw(G, pos, with_labels = True, node_color = values, edge_color = 'black' ,width = 1, alpha = 0.7) #with_labels=true is to show the node number in the output graph 48 | 49 | 50 | 51 | 52 | #main function 53 | if __name__ == "__main__": 54 | G = CreateGraph() 55 | col_val = welsh_powell(G) 56 | DrawGraph(G,col_val) 57 | plt.show() -------------------------------------------------------------------------------- /K Centers Problem/k_centers_problem.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import operator 4 | 5 | 6 | 7 | def k_centers(G, n): 8 | centers = [] 9 | cities = G.nodes() 10 | #add an arbitrary node, here, the first node,to the centers list 11 | centers.append((G.nodes())[0]) 12 | cities.remove(centers[0]) 13 | n = n-1 #since we have already added one center 14 | #choose n-1 centers 15 | while n!= 0: 16 | city_dict = {} 17 | for cty in cities: 18 | min_dist = float("inf") 19 | for c in centers: 20 | min_dist = min(min_dist,G[cty][c]['length']) 21 | city_dict[cty] = min_dist 22 | #print city_dict 23 | new_center = max(city_dict, key = lambda i: city_dict[i]) 24 | #print new_center 25 | centers.append(new_center) 26 | cities.remove(new_center) 27 | n = n-1 28 | #print centers 29 | return centers 30 | 31 | 32 | 33 | #takes input from the file and creates a weighted undirected graph 34 | def CreateGraph(): 35 | G = nx.Graph() 36 | f = open('input.txt') 37 | n = int(f.readline()) #n denotes the number of cities 38 | wtMatrix = [] 39 | for i in range(n): 40 | list1 = map(int, (f.readline()).split()) 41 | wtMatrix.append(list1) 42 | #Adds egdes along with their weights to the graph 43 | for i in range(n) : 44 | for j in range(n)[i:] : 45 | G.add_edge(i, j, length = wtMatrix[i][j]) 46 | noc = int(f.readline()) #noc,here,denotes the number of centers 47 | return G, noc 48 | 49 | 50 | 51 | #draws the graph and displays the weights on the edges 52 | def DrawGraph(G, centers): 53 | pos = nx.spring_layout(G) 54 | color_map = ['blue'] * len(G.nodes()) 55 | #all the center nodes are marked with 'red' 56 | for c in centers: 57 | color_map[c] = 'red' 58 | nx.draw(G, pos, node_color = color_map, with_labels = True) #with_labels=true is to show the node number in the output graph 59 | edge_labels = nx.get_edge_attributes(G, 'length') 60 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, font_size = 11) #prints weight on all the edges 61 | 62 | 63 | 64 | #main function 65 | if __name__ == "__main__": 66 | G,n = CreateGraph() 67 | centers = k_centers(G, n) 68 | DrawGraph(G, centers) 69 | plt.show() 70 | 71 | -------------------------------------------------------------------------------- /Egocentric Network/egocentric_network_1.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def EgocentricNetwork(G,v): 6 | egocentric_network_edge_list = [] 7 | egocentric_network_node_list = [v] 8 | for i in G.neighbors(v): 9 | egocentric_network_node_list.append(i) 10 | egocentric_network_edge_list.append((v,i)) 11 | return egocentric_network_edge_list,egocentric_network_node_list 12 | 13 | 14 | 15 | #takes input from the file and creates a graph 16 | def CreateGraph(): 17 | G = nx.Graph() 18 | f = open('input.txt') 19 | n = int(f.readline()) 20 | for i in range(n): 21 | G.add_node(i+1) 22 | no_of_edges = int(f.readline()) 23 | for i in range(no_of_edges): 24 | graph_edge_list = f.readline().split() 25 | G.add_edge(int(graph_edge_list[0]), int(graph_edge_list[1])) 26 | vert = int(f.readline()) 27 | return G, vert 28 | 29 | 30 | 31 | #draws the graph and displays the weights on the edges 32 | def DrawGraph(G,egocentric_network_edge_list,egocentric_network_node_list, vert): 33 | pos = nx.spring_layout(G) 34 | nx.draw(G, pos, with_labels = True, node_color = 'blue', alpha = 0.8) #with_labels=true is to show the node number in the output graph 35 | nx.draw_networkx_edges(G, pos, edgelist = egocentric_network_edge_list , width = 2.5, alpha = 0.8, edge_color = 'red') 36 | nx.draw_networkx_nodes(G,pos, nodelist = egocentric_network_node_list, node_color = 'red', alpha = 0.5) 37 | nx.draw_networkx_nodes(G,pos,nodelist=[vert],node_color='green',node_size=500,alpha=0.8) 38 | return pos 39 | 40 | 41 | def CentralityMeasures(G): 42 | # Betweenness centrality 43 | bet_cen = nx.betweenness_centrality(G) 44 | # Closeness centrality 45 | clo_cen = nx.closeness_centrality(G) 46 | # Eigenvector centrality 47 | eig_cen = nx.eigenvector_centrality(G) 48 | # Degree centrality 49 | deg_cen = nx.degree_centrality(G) 50 | #print bet_cen, clo_cen, eig_cen 51 | print "# Betweenness centrality:" + str(bet_cen) 52 | print "# Closeness centrality:" + str(clo_cen) 53 | print "# Eigenvector centrality:" + str(eig_cen) 54 | print "# Degree centrality:" + str(deg_cen) 55 | 56 | 57 | #main function 58 | 59 | if __name__== "__main__": 60 | G,vert = CreateGraph() 61 | egocentric_network_edge_list,egocentric_network_node_list = EgocentricNetwork(G,vert) 62 | DrawGraph(G,egocentric_network_edge_list,egocentric_network_node_list, vert) 63 | CentralityMeasures(G) 64 | plt.show() 65 | 66 | -------------------------------------------------------------------------------- /K Centers Problem/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of K - Centers Problem using networkx library 2 | 3 | ### K - Center ### 4 | 5 | K - Center problem (also known as Metric K - Center problem) is a NP - Hard Problem where given n cities, one needs to choose k (k<=n) centers, such that maximum distance of a city to the center is minimized. 6 | 7 | In layman terms,say we need to bulid k warehouses given a map of n connected cities. The best way to build a warehouse, is by keeping in mind that, it must be closest to the cities. In other words, the maximum distance of a city to the warehouse must be minimal. 8 | 9 | 10 | Greedy approach: 11 | 12 | Here, is an illustration of the simple greedy algorithm which has an approximation factor of 2. It works on the basic idea of choosing the city which is farthest from the current set of centers. 13 | 14 | Step 1: Pick an arbitrary center,c1. 15 | Step 2: For every remaining cities C1,C2,.. CN-1, compute minimum distnace from the centers chosen already. 16 | Step 3: Pick the new center with the highest distance from already chosen centers, that is max((dist(c1, C1), dist(c1,C2), ... dist(c1, CN-1)). 17 | Step 4: Continue this till all the k centers are found. 18 | 19 | 20 | 21 | #### Working #### 22 | 23 | For the sample input below: 24 | 25 | ``` 26 | 4 27 | 0 10 7 6 28 | 10 0 8 5 29 | 7 8 0 12 30 | 6 5 12 0 31 | 3 32 | ``` 33 | Visualization of the input graph: 34 | 35 | ![1](https://user-images.githubusercontent.com/22571531/28249724-dcc08a16-6a78-11e7-8fbe-21905190307e.png) 36 | 37 | Visualization of the result : 38 | 39 | Here, the red colored nodes denote the centers. 40 | ![2](https://user-images.githubusercontent.com/22571531/28249726-e1255e42-6a78-11e7-9dd2-13b4751c2939.png) 41 | 42 | #### Complexity #### 43 | 44 | Time: O(n*k) 45 | n - number of Cities 46 | k - number of Centers 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Graph Coloring/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Graph Coloring Problem using networkx library 2 | 3 | ### Graph Coloring ### 4 | 5 | Graph Coloring Problem is an NP complete problem where "colors" are assigned to elements of a graph(edge ,node or face) subject to certain constraints. 6 | 7 | This is an illustration of Vertex Coloring problem. The problem is that, given an undirected graph, assign colors to each node such that no two ajacent nodes have the same color. It also involves minimization of the number of colors used. 8 | 9 | Basic approach: 10 | 11 | Step 1: Assign first color to the first vertex 12 | Step 2: For each of the remaining vertices, color the vertex with the lowest numbered color which has not yet been used for any of its neighbouring vertices. 13 | 14 | The above approach is a Greedy approach. It doesn't guarantee to use minimum number of color's each time. One way to improve this is by ordering the vertices in the decreasing order of their valency. And apply node coloring in that order. By doing so, the node with maximum color conflicts will be resolved first, and hence works better. This is Welsh - Powell algorithm. 15 | 16 | 17 | #### Working #### 18 | 19 | For the sample input below: 20 | 21 | ``` 22 | 16 23 | 0 7 24 | 0 1 25 | 1 3 26 | 3 2 27 | 3 8 28 | 3 10 29 | 7 8 30 | 7 9 31 | 7 10 32 | 7 6 33 | 8 9 34 | 9 10 35 | 6 5 36 | 10 4 37 | 5 4 38 | 6 10 39 | ``` 40 | Visualization of the input graph: 41 | 42 | ![1](https://user-images.githubusercontent.com/22571531/28072420-93b63840-6670-11e7-8178-45c47e8fddfe.png) 43 | 44 | 45 | Visualization of the result after node coloring. 46 | Following 4 colors have been used: 47 | Blue : 0, 3, 5 48 | Purple : 1, 2, 4, 6, 9 49 | Green : 7 50 | Yellow : 8, 10 51 | 52 | ![2](https://user-images.githubusercontent.com/22571531/28072424-9638f80a-6670-11e7-99ba-7b83ab92193c.png) 53 | 54 | #### Complexity #### 55 | 56 | Time: O(N^2 + E) 57 | N - number of Nodes 58 | E - number of Edges 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Visualization-of-popular-algorithms-in-Python 2 | 3 | ### Description 4 | 5 | The project aims to create visual outputs for popular graph algorithms like DFS,BFS and NP-HARD problems like Travelling Salesman Problem and Graph colouring problems using NetworkX graph library of Python. It is not just limited to getting a visual output, but the algorithms will be optimised to its best by using heuristics for non-polynomial time algorithms. The project aims to create a better understanding of the working of the algorithms, in-depth understanding of the application of heuristics to improve the computation time and usage of the later to our advantage in optimising the algorithm. It could be used by analysts as well as students and teachers, as a teaching aid. It could definitely serve all the applications of Np-hard problems like- School scheduling, Tourist Itineraries, etc. 6 | 7 | ### Motivation 8 | 9 | DFS,BFS and NP-Hard algorithms have been there for years now and it has been coded out in every programming language as well. This project aims in visulization of them, to create a better understanding. Solving most of the above mentioned algorithm using brute force-technique might give the optimal solution, however, as the problem size increases, the search for an optimal solution will no longer be worth the effort. Hence, by involving heuristics, we aim to improve the time complexity while arriving at a good solution( need not be optimal always). (Heuristics is used, to predict how close the end of path is to a solution, so that the paths which are judged to be closer to a solution are extended first.) 10 | 11 | It includes: 12 | ### 1. DFS: 13 | [DFS](/DFS) 14 | ### 2. BFS: 15 | [BFS](/BFS) 16 | ### 3. Dijsktra's: 17 | [Dijsktra's](/Dijsktra's) 18 | ### 4. Prim's: 19 | [Prim's](/Prim's) 20 | ### 5. Kruskal's: 21 | [Kruskal's](/Kruskal's) 22 | ### 6. Assignment Problem: 23 | [Assignment Problem](/Assignment%20Problem) 24 | ### 7. Travelling Salesman Problem: 25 | [Travelling Salesman Problem](/Travelling%20Salesman%20Problem) 26 | ### 8. Greedy Best First Search: 27 | [Greedy BFS](/Greedy%20BFS) 28 | ### 9. A* Search: 29 | [A* Search](/A_star_search) 30 | ### 10. Topological Sort: 31 | [Topological Sort](/Topological%20Sort) 32 | ### 11. Graph Coloring Problem: 33 | [Graph-Coloring Problem](/Graph%20Coloring) 34 | ### 12. K Centers Problem: 35 | [K Centers Problem](/K%20Centers%20Problem) 36 | ### 13. Egocentric Network: 37 | [Egocentric Network](/Egocentric%20Network) 38 | ### 14. Bellman-Ford algorithm: 39 | [Bellman Ford](/BellmanFord) 40 | -------------------------------------------------------------------------------- /BellmanFord/BellmanFord.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import sys 4 | 5 | inf = float('inf') 6 | 7 | #function that performs Bellman-Ford algorithm on the graph G,with source vertex as source 8 | def bellmanFord(G, source, pos): 9 | V = len(G.nodes()) # V denotes the number of vertices in G 10 | dist = [] # dist[i] will hold the shortest distance from source to i 11 | parent = [None]*V # parent[i] will hold the node from which i is reached to, in the shortest path from source 12 | 13 | for i in range(V): 14 | dist.append(inf) 15 | 16 | parent[source] = -1; #source is itself the root, and hence has no parent 17 | dist[source] = 0; 18 | 19 | for i in range(V-1): 20 | for u, v, d in G.edges(data = True): # Relaxation is the most important step in Bellman-Ford. It is what increases the accuracy of the distance to any given vertex. Relaxation works by continuously shortening the calculated distance between vertices comparing that distance with other known distances. 21 | if dist[u] + d['length'] < dist[v]: #Relaxation Equation 22 | dist[v] = d['length'] + dist[u] 23 | parent[v] = u 24 | 25 | #marking the shortest path from source to each of the vertex with red, using parent[] 26 | for v in range(V): 27 | if parent[v] != -1: #ignore the parent of root node 28 | if (parent[v], v) in G.edges(): 29 | nx.draw_networkx_edges(G, pos, edgelist = [(parent[v], v)], width = 2.5, alpha = 0.6, edge_color = 'r') 30 | return 31 | 32 | #takes input from the file and creates a weighted graph 33 | def createGraph(): 34 | G = nx.DiGraph() 35 | f = open('input.txt') 36 | n = int(f.readline()) 37 | wtMatrix = [] 38 | for i in range(n): 39 | list1 = map(int, (f.readline()).split()) 40 | wtMatrix.append(list1) 41 | source = int(f.readline()) #source vertex for BellmanFord algo 42 | #Adds egdes along with their weights to the graph 43 | for i in range(n) : 44 | for j in range(n) : 45 | if wtMatrix[i][j] > 0 : 46 | G.add_edge(i, j, length = wtMatrix[i][j]) 47 | return G, source 48 | 49 | 50 | #draws the graph and displays the weights on the edges 51 | def DrawGraph(G): 52 | pos = nx.spring_layout(G) 53 | nx.draw(G, pos, with_labels = True) #with_labels=true is to show the node number in the output graph 54 | edge_labels = dict([((u, v), d['length']) for u, v, d in G.edges(data = True)]) 55 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, label_pos = 0.3, font_size = 11) #prints weight on all the edges 56 | return pos 57 | 58 | #main function 59 | if __name__ == "__main__": 60 | G, source = createGraph() 61 | pos = DrawGraph(G) 62 | bellmanFord(G, source, pos) 63 | plt.show() 64 | -------------------------------------------------------------------------------- /DFS/dfs_visual.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | 6 | #utility fucntion used by DFS which does recursive depth first search 7 | def DFSUtil(G, v, visited, sl): 8 | visited[v] = True 9 | sl.append(v) 10 | for i in G[v]: 11 | if visited[i] == False: 12 | DFSUtil(G, i, visited, sl) 13 | return sl 14 | 15 | 16 | 17 | #DFS traversal 18 | def DFS(G, source): 19 | visited = [False]*(len(G.nodes())) 20 | sl = [] #a list that stores dfs forest starting with source node 21 | dfs_stk = [] #A nested list that stores all the DFS Forest's 22 | dfs_stk.append(DFSUtil(G, source, visited, sl)) 23 | for i in range(len(G.nodes())): 24 | if visited[i] == False: 25 | sl = [] 26 | dfs_stk.append(DFSUtil(G, i, visited, sl)) 27 | return dfs_stk 28 | 29 | 30 | 31 | #takes input from the file and creates a weighted graph 32 | def CreateGraph(): 33 | G = nx.DiGraph() 34 | f = open('input.txt') 35 | n = int(f.readline()) 36 | wtMatrix = [] 37 | for i in range(n): 38 | list1 = map(int,(f.readline()).split()) 39 | wtMatrix.append(list1) 40 | source = int(f.readline()) #source vertex from where DFS has to start 41 | #Adds egdes along with their weights to the graph 42 | for i in range(n): 43 | for j in range(n): 44 | if wtMatrix[i][j] > 0: 45 | G.add_edge(i, j, length = wtMatrix[i][j]) 46 | return G,source 47 | 48 | 49 | 50 | #marks all edges traversed through DFS with red 51 | def DrawDFSPath(G, dfs_stk): 52 | pos = nx.spring_layout(G) 53 | nx.draw(G, pos, with_labels = True) #with_labels=true is to show the node number in the output graph 54 | edge_labels = dict([((u,v,), d['length']) for u, v, d in G.edges(data = True)]) 55 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, label_pos = 0.3, font_size = 11) #prints weight on all the edges 56 | for i in dfs_stk: 57 | #if there is more than one node in the dfs-forest, then print the corresponding edges 58 | if len(i) > 1: 59 | for j in i[ :(len(i)-1)]: 60 | if i[i.index(j)+1] in G[j]: 61 | nx.draw_networkx_edges(G, pos, edgelist = [(j,i[i.index(j)+1])], width = 2.5, alpha = 0.6, edge_color = 'r') 62 | else: 63 | #if in case the path was reversed because all the possible neighbours were visited, we need to find the adj node to it. 64 | for k in i[1::-1]: 65 | if k in G[j]: 66 | nx.draw_networkx_edges(G, pos, edgelist = [(j,k)], width = 2.5, alpha = 0.6, edge_color = 'r') 67 | break 68 | 69 | 70 | 71 | #main function 72 | if __name__ == "__main__": 73 | G, source = CreateGraph() 74 | dfs_stk = DFS(G, source) 75 | DrawDFSPath(G, dfs_stk) 76 | plt.show() 77 | 78 | 79 | -------------------------------------------------------------------------------- /Egocentric Network/egocentric_network_1_5.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import itertools 4 | 5 | 6 | def EgocentricNetwork(G,v): 7 | 8 | egocentric_network_edge_list = [] 9 | egocentric_network_node_list = [v] 10 | for i in G.neighbors(v): 11 | egocentric_network_node_list.append(i) 12 | egocentric_network_edge_list.append((v,i)) 13 | egocentric_network_node_list.sort() 14 | egocentric_network_edge_list = list(tuple(sorted(p)) for p in egocentric_network_edge_list) 15 | 16 | for i in list(itertools.combinations(egocentric_network_node_list, 2)): #generates all possible pairs of nodes 17 | if i in G.edges() and i not in egocentric_network_edge_list: 18 | egocentric_network_edge_list.append(i) 19 | 20 | return egocentric_network_edge_list,egocentric_network_node_list 21 | 22 | 23 | 24 | #takes input from the file and creates a graph 25 | def CreateGraph(): 26 | G = nx.Graph() 27 | f = open('input.txt') 28 | n = int(f.readline()) 29 | for i in range(n): 30 | G.add_node(i+1) 31 | no_of_edges = int(f.readline()) 32 | for i in range(no_of_edges): 33 | graph_edge_list = f.readline().split() 34 | G.add_edge(int(graph_edge_list[0]), int(graph_edge_list[1])) 35 | vert = int(f.readline()) 36 | return G, vert 37 | 38 | 39 | 40 | #draws the graph and displays the weights on the edges 41 | def DrawGraph(G, egocentric_network_edge_list, egocentric_network_node_list, vert): 42 | pos = nx.spring_layout(G) 43 | nx.draw(G, pos, with_labels = True, node_color = 'blue', alpha = 0.8) #with_labels=true is to show the node number in the output graph 44 | nx.draw_networkx_edges(G, pos, edgelist = egocentric_network_edge_list , width = 2.5, alpha = 0.8, edge_color = 'red') 45 | nx.draw_networkx_nodes(G,pos, nodelist = egocentric_network_node_list, node_color = 'red', alpha = 0.5) 46 | nx.draw_networkx_nodes(G,pos,nodelist=[vert],node_color='green',node_size=500,alpha=0.8) 47 | return pos 48 | 49 | 50 | def CentralityMeasures(G): 51 | # Betweenness centrality 52 | bet_cen = nx.betweenness_centrality(G) 53 | # Closeness centrality 54 | clo_cen = nx.closeness_centrality(G) 55 | # Eigenvector centrality 56 | eig_cen = nx.eigenvector_centrality(G) 57 | # Degree centrality 58 | deg_cen = nx.degree_centrality(G) 59 | #print bet_cen, clo_cen, eig_cen 60 | print "# Betweenness centrality:" + str(bet_cen) 61 | print "# Closeness centrality:" + str(clo_cen) 62 | print "# Eigenvector centrality:" + str(eig_cen) 63 | print "# Degree centrality:" + str(deg_cen) 64 | 65 | 66 | #main function 67 | if __name__== "__main__": 68 | G, vert = CreateGraph() 69 | egocentric_network_edge_list,egocentric_network_node_list = EgocentricNetwork(G, vert) 70 | DrawGraph(G,egocentric_network_edge_list, egocentric_network_node_list, vert) 71 | CentralityMeasures(G) 72 | plt.show() 73 | 74 | -------------------------------------------------------------------------------- /Topological Sort/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Topological sort algorithm using networkx library 2 | 3 | ### Topological sort ### 4 | 5 | Topological sort of a directed graph is a linear ordering of its vertices such that for every directed edge uv from vertex u to vertex v, u comes before v in the ordering. For instance, the vertices of the graph may represent tasks to be performed, and the edges may represent constraints that one task must be performed before another; in this application, a topological ordering is just a valid sequence for the tasks. 6 | PS: Topological sorting is possible only if the graph is a directed acyclic graph. 7 | 8 | Two commom approaches for topological sort: 9 | 1. Kahn's algorithm 10 | 2. Depth - first search 11 | 12 | The code here is an implementation of Kahn's algorithm. 13 | 14 | #### Kahn's algorithm #### 15 | 16 | This is computationally simpler compared to DFS approach. 17 | 18 | Step 1: Find all the nodes in the graph with in-degree as 0 and add them into a queue 19 | Step 2: Remove the nodes from the queue one by one, append it to the sorted_list and simulatneously update the graph(remove the node from the graph, resulting which, in-degree of nodes which had edges directed from the reomved node decreases by one). 20 | Step 3: If there are anymore nodes left in the graph, go back to step 1 21 | 22 | This method is optimal but modifies the graph. For the algorithm to not modify the original graph, you'll need to maintain a boolean array visited[] - to keep track to the visited nodes and indegree[] to store the in-degree of the graph nodes. 23 | 24 | #### Working #### 25 | 26 | Consider the sample input below: 27 | 28 | ``` 29 | 6 30 | 1 2 31 | 1 3 32 | 2 3 33 | 2 4 34 | 3 4 35 | 3 5 36 | ``` 37 | Visualization of the input graph: 38 | 39 | ![1](https://user-images.githubusercontent.com/22571531/27983933-e09f086c-63e6-11e7-9830-b63a48b829b6.png) 40 | 41 | 42 | Node 1 is the only node with in-degree as 0. 43 | Remove it from the graph, and append it to the sorted_list. 44 | sorted_list = [1] 45 | 46 | Now, Node 2 has an in-degree of 0. Remove it from the graph, and append it to the sorted list. 47 | sorted_list = [1,2] 48 | 49 | Next, Node 3 has an in-degree of 0. 50 | sorted_list = [1,2 3] 51 | 52 | Next, Node 4 and Node 5, both have an in-degree of 0. 53 | sorted_list = [1,2,3,4,5] 54 | Note that: [1,2,3,5,4] is also the right order. 55 | 56 | Visualization of the topologically sorted order. 57 | Green node - denotes the starting node. 58 | Red node - denotes the final node. 59 | 60 | ![2](https://user-images.githubusercontent.com/22571531/27983935-e5d92286-63e6-11e7-92f3-e45c9bbb6039.png) 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Prim's/prims.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import sys 4 | 5 | 6 | #utility function that returns the minimum egde weight node 7 | def minDistance(dist, mstSet, V): 8 | min = sys.maxsize #assigning largest numeric value to min 9 | for v in range(V): 10 | if mstSet[v] == False and dist[v] < min: 11 | min = dist[v] 12 | min_index = v 13 | return min_index 14 | 15 | 16 | 17 | #function that performs prims algorithm on the graph G 18 | def prims(G, pos): 19 | V = len(G.nodes()) # V denotes the number of vertices in G 20 | dist = [] # dist[i] will hold the minimum weight edge value of node i to be included in MST 21 | parent = [None]*V # parent[i] will hold the vertex connected to i, in the MST edge 22 | mstSet = [] # mstSet[i] will hold true if vertex i is included in the MST 23 | #initially, for every node, dist[] is set to maximum value and mstSet[] is set to False 24 | for i in range(V): 25 | dist.append(sys.maxsize) 26 | mstSet.append(False) 27 | dist[0] = 0 28 | parent[0]= -1 #starting vertex is itself the root, and hence has no parent 29 | for count in range(V-1): 30 | u = minDistance(dist, mstSet, V) #pick the minimum distance vertex from the set of vertices 31 | mstSet[u] = True 32 | #update the vertices adjacent to the picked vertex 33 | for v in range(V): 34 | if (u, v) in G.edges(): 35 | if mstSet[v] == False and G[u][v]['length'] < dist[v]: 36 | dist[v] = G[u][v]['length'] 37 | parent[v] = u 38 | for X in range(V): 39 | if parent[X] != -1: #ignore the parent of the starting node 40 | if (parent[X], X) in G.edges(): 41 | nx.draw_networkx_edges(G, pos, edgelist = [(parent[X], X)], width = 2.5, alpha = 0.6, edge_color = 'r') 42 | return 43 | 44 | 45 | 46 | #takes input from the file and creates a weighted graph 47 | def CreateGraph(): 48 | G = nx.Graph() 49 | f = open('input.txt') 50 | n = int(f.readline()) 51 | wtMatrix = [] 52 | for i in range(n): 53 | list1 = map(int, (f.readline()).split()) 54 | wtMatrix.append(list1) 55 | #Adds egdes along with their weights to the graph 56 | for i in range(n) : 57 | for j in range(n)[i:] : 58 | if wtMatrix[i][j] > 0 : 59 | G.add_edge(i, j, length = wtMatrix[i][j]) 60 | return G 61 | 62 | 63 | 64 | #draws the graph and displays the weights on the edges 65 | def DrawGraph(G): 66 | pos = nx.spring_layout(G) 67 | nx.draw(G, pos, with_labels = True) #with_labels=true is to show the node number in the output graph 68 | edge_labels = nx.get_edge_attributes(G,'length') 69 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, font_size = 11) #prints weight on all the edges 70 | return pos 71 | 72 | 73 | 74 | #main function 75 | if __name__ == "__main__": 76 | G = CreateGraph() 77 | pos = DrawGraph(G) 78 | prims(G, pos) 79 | plt.show() 80 | 81 | -------------------------------------------------------------------------------- /Kruskal's/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Kruskal's algorithm using networkx library 2 | 3 | ### INPUT ### 4 | 5 | 6 | Input is taken from the file 7 | #### input.txt #### 8 | 9 | Sample input 10 | ``` 11 | 5 12 | 0 2 7 -1 -1 13 | 2 0 3 8 5 14 | 7 3 0 1 -1 15 | -1 8 1 0 4 16 | -1 5 -1 4 0 17 | 18 | ``` 19 | First line contains the number of nodes,say n.(Nodes are numbered as 0,1,2,...(n-1) ) 20 | Followed by n*n weighted matrix. Disconnected edges are represented by negative weight. 21 | 22 | ### Draw Graph ### 23 | 24 | 25 | Graph is first drawn from the weighted matrix input from the user with weights shown. Edges are marked with black. 26 | 27 | 28 | 29 | ### Kruskal's algorithm ### 30 | 31 | Kruskal's algorithm is a greedy algorithm that finds a minimum spanning tree for a weighted undirected garph. 32 | 33 | The algorithm operates by adding the egdes one by one in the order of their increasing lengths, so as to form a tree. Egdes are rejected if it's addition to the tree, forms a cycle. This continues till we have V-1 egdes in the tree. (V stands for the number of vertices). 34 | 35 | To understand this better, consider the above input. 36 | 37 | The graph, initially. 38 | 39 | ![1](https://user-images.githubusercontent.com/22571531/27430044-b959f994-5764-11e7-9b3e-aa0c10dc98e9.png) 40 | 41 | 42 | #### After the first iteration: #### 43 | 44 | The smallest edge is of length 1, connecting Node 2 and Node 3. Since it is the first edge, it is added directly to the tree. 45 | 46 | 47 | ![2](https://user-images.githubusercontent.com/22571531/27430048-bcf86eb4-5764-11e7-8f03-397f601338b2.png) 48 | 49 | 50 | #### After the second iteration: #### 51 | 52 | Next smallest edge is of length 2, connecting Node 0 and Node 1. Since it's addition doesn't result in a cycle, it is added to the tree. 53 | 54 | 55 | ![3](https://user-images.githubusercontent.com/22571531/27430058-c0a1da78-5764-11e7-8a0a-a29ab5442d80.png) 56 | 57 | #### After the third iteration: #### 58 | 59 | Next smallest edge is of length 3, connecting Node 1 and Node 2. Since it's addition doesn't result in a cycle, it is added to the tree. 60 | 61 | ![4](https://user-images.githubusercontent.com/22571531/27430069-c607466a-5764-11e7-9a2e-7d60e5d50254.png) 62 | 63 | #### After the fourth iteration: #### 64 | 65 | Next smallest edge is of length 4, connecting Node 3 and Node 4. Since it's addition doesn't result in a cycle, it is added to the tree. 66 | 67 | Now we have 4 edges, hence we stop the iteration. 68 | Final graph, with red edges denoting the minimum spanning tree. 69 | 70 | ![5](https://user-images.githubusercontent.com/22571531/27430080-ce205b20-5764-11e7-8bca-20f452d8b20d.png) 71 | 72 | #### Complexity #### 73 | 74 | Time: O(V^2) 75 | V - Number of vertices -------------------------------------------------------------------------------- /Dijsktra's/dijsktras.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import sys 4 | 5 | 6 | 7 | #utility function that returns the minimum distance node 8 | def minDistance(dist, sptSet, V): 9 | min = sys.maxsize #assigning largest numeric value to min 10 | for v in range(V): 11 | if sptSet[v] == False and dist[v] <= min: 12 | min = dist[v] 13 | min_index = v 14 | return min_index 15 | 16 | 17 | 18 | #function that performs dijsktras algorithm on the graph G,with source vertex as source 19 | def dijsktras(G, source, pos): 20 | V = len(G.nodes()) # V denotes the number of vertices in G 21 | dist = [] # dist[i] will hold the shortest distance from source to i 22 | parent = [None]*V # parent[i] will hold the node from which i is reached to, in the shortest path from source 23 | sptSet = [] # sptSet[i] will hold true if vertex i is included in shortest path tree 24 | #initially, for every node, dist[] is set to maximum value and sptSet[] is set to False 25 | for i in range(V): 26 | dist.append(sys.maxsize) 27 | sptSet.append(False) 28 | dist[source] = 0 29 | parent[source]= -1 #source is itself the root, and hence has no parent 30 | for count in range(V-1): 31 | u = minDistance(dist, sptSet, V) #pick the minimum distance vectex from the set of vertices 32 | sptSet[u] = True 33 | #update the vertices adjacent to the picked vertex 34 | for v in range(V): 35 | if (u, v) in G.edges(): 36 | if sptSet[v] == False and dist[u] != sys.maxsize and dist[u] + G[u][v]['length'] < dist[v]: 37 | dist[v] = dist[u] + G[u][v]['length'] 38 | parent[v] = u 39 | #marking the shortest path from source to each of the vertex with red, using parent[] 40 | for X in range(V): 41 | if parent[X] != -1: #ignore the parent of root node 42 | if (parent[X], X) in G.edges(): 43 | nx.draw_networkx_edges(G, pos, edgelist = [(parent[X], X)], width = 2.5, alpha = 0.6, edge_color = 'r') 44 | return 45 | 46 | 47 | 48 | #takes input from the file and creates a weighted graph 49 | def CreateGraph(): 50 | G = nx.DiGraph() 51 | f = open('input.txt') 52 | n = int(f.readline()) 53 | wtMatrix = [] 54 | for i in range(n): 55 | list1 = map(int, (f.readline()).split()) 56 | wtMatrix.append(list1) 57 | source = int(f.readline()) #source vertex for dijsktra's algo 58 | #Adds egdes along with their weights to the graph 59 | for i in range(n) : 60 | for j in range(n) : 61 | if wtMatrix[i][j] > 0 : 62 | G.add_edge(i, j, length = wtMatrix[i][j]) 63 | return G, source 64 | 65 | 66 | 67 | #draws the graph and displays the weights on the edges 68 | def DrawGraph(G): 69 | pos = nx.spring_layout(G) 70 | nx.draw(G, pos, with_labels = True) #with_labels=true is to show the node number in the output graph 71 | edge_labels = dict([((u, v), d['length']) for u, v, d in G.edges(data = True)]) 72 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, label_pos = 0.3, font_size = 11) #prints weight on all the edges 73 | return pos 74 | 75 | 76 | 77 | #main function 78 | if __name__ == "__main__": 79 | G,source = CreateGraph() 80 | pos = DrawGraph(G) 81 | dijsktras(G, source, pos) 82 | plt.show() 83 | 84 | -------------------------------------------------------------------------------- /Greedy BFS/greedy_bfs.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import Queue as Q 4 | 5 | 6 | 7 | def getPriorityQueue(list): 8 | q = Q.PriorityQueue() 9 | for node in list: 10 | q.put(Ordered_Node(heuristics[node],node)) 11 | return q,len(list) 12 | 13 | 14 | 15 | def greedyBFSUtil(G, v, visited, final_path, dest, goal): 16 | if goal == 1: 17 | return goal 18 | visited[v] = True 19 | final_path.append(v) 20 | if v == dest: 21 | goal = 1 22 | else: 23 | pq_list = [] 24 | pq,size = getPriorityQueue(G[v]) 25 | for i in range(size): 26 | pq_list.append(pq.get().description) 27 | for i in pq_list: 28 | if goal != 1: 29 | #print "current city:", i 30 | if visited[i] == False : 31 | goal = greedyBFSUtil(G, i, visited, final_path, dest, goal) 32 | return goal 33 | 34 | 35 | 36 | def greedyBFS(G, source, dest, heuristics, pos): 37 | visited = {} 38 | for node in G.nodes(): 39 | visited[node] = False 40 | final_path = [] 41 | goal = greedyBFSUtil(G, source, visited, final_path, dest, 0) 42 | prev = -1 43 | for var in final_path: 44 | if prev != -1: 45 | curr = var 46 | nx.draw_networkx_edges(G, pos, edgelist = [(prev,curr)], width = 2.5, alpha = 0.8, edge_color = 'black') 47 | prev = curr 48 | else: 49 | prev = var 50 | return 51 | 52 | 53 | 54 | class Ordered_Node(object): 55 | def __init__(self, priority, description): 56 | self.priority = priority 57 | self.description = description 58 | return 59 | def __cmp__(self, other): 60 | return cmp(self.priority, other.priority) 61 | 62 | def getHeuristics(G): 63 | heuristics = {} 64 | f = open('heuristics.txt') 65 | for i in G.nodes(): 66 | node_heuristic_val = f.readline().split() 67 | heuristics[node_heuristic_val[0]] = node_heuristic_val[1] 68 | return heuristics 69 | 70 | 71 | 72 | #takes input from the file and creates a weighted graph 73 | def CreateGraph(): 74 | G = nx.Graph() 75 | f = open('input.txt') 76 | n = int(f.readline()) 77 | for i in range(n): 78 | graph_edge_list = f.readline().split() 79 | G.add_edge(graph_edge_list[0], graph_edge_list[1], length = graph_edge_list[2]) 80 | source, dest= f.read().splitlines() 81 | return G, source, dest 82 | 83 | 84 | 85 | def DrawPath(G, source, dest): 86 | pos = nx.spring_layout(G) 87 | val_map = {} 88 | val_map[source] = 'green' 89 | val_map[dest] = 'red' 90 | values = [val_map.get(node, 'blue') for node in G.nodes()] 91 | nx.draw(G, pos, with_labels = True, node_color = values, edge_color = 'b' ,width = 1, alpha = 0.7) #with_labels=true is to show the node number in the output graph 92 | edge_labels = dict([((u, v,), d['length']) for u, v, d in G.edges(data = True)]) 93 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, label_pos = 0.5, font_size = 11) #prints weight on all the edges 94 | return pos 95 | 96 | 97 | 98 | #main function 99 | if __name__ == "__main__": 100 | G, source,dest = CreateGraph() 101 | heuristics = getHeuristics(G) 102 | pos = DrawPath(G, source, dest) 103 | greedyBFS(G, source, dest, heuristics, pos) 104 | plt.show() 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /A_star_search/a_star_search.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import Queue as Q 4 | 5 | 6 | 7 | def getPriorityQueue(G, v): 8 | q = Q.PriorityQueue() 9 | for node in G[v]: 10 | q.put(Ordered_Node(float(heuristics[node])+float(G[node][v]['length']),node)) 11 | return q,len(G[v]) 12 | 13 | 14 | 15 | def aStarSearchUtil(G, v, visited, final_path, dest, goal): 16 | if goal == 1: 17 | return goal 18 | visited[v] = True 19 | final_path.append(v) 20 | if v == dest: 21 | goal = 1 22 | else: 23 | pq_list = [] 24 | pq,size = getPriorityQueue(G, v) 25 | for i in range(size): 26 | pq_list.append(pq.get().description) 27 | for i in pq_list: 28 | if goal != 1: 29 | #print "current city:", i 30 | if visited[i] == False : 31 | goal = aStarSearchUtil(G, i, visited, final_path, dest, goal) 32 | return goal 33 | 34 | 35 | 36 | def aStarSearch(G, source, dest, heuristics, pos): 37 | visited = {} 38 | for node in G.nodes(): 39 | visited[node] = False 40 | final_path = [] 41 | goal = aStarSearchUtil(G, source, visited, final_path, dest, 0) 42 | prev = -1 43 | for var in final_path: 44 | if prev != -1: 45 | curr = var 46 | nx.draw_networkx_edges(G, pos, edgelist = [(prev,curr)], width = 2.5, alpha = 0.8, edge_color = 'black') 47 | prev = curr 48 | else: 49 | prev = var 50 | return 51 | 52 | 53 | 54 | class Ordered_Node(object): 55 | def __init__(self, priority, description): 56 | self.priority = priority 57 | self.description = description 58 | return 59 | def __cmp__(self, other): 60 | return cmp(self.priority, other.priority) 61 | 62 | def getHeuristics(G): 63 | heuristics = {} 64 | f = open('heuristics.txt') 65 | for i in G.nodes(): 66 | node_heuristic_val = f.readline().split() 67 | heuristics[node_heuristic_val[0]] = node_heuristic_val[1] 68 | return heuristics 69 | 70 | 71 | 72 | #takes input from the file and creates a weighted graph 73 | def CreateGraph(): 74 | G = nx.Graph() 75 | f = open('input.txt') 76 | n = int(f.readline()) 77 | for i in range(n): 78 | graph_edge_list = f.readline().split() 79 | G.add_edge(graph_edge_list[0], graph_edge_list[1], length = graph_edge_list[2]) 80 | source, dest= f.read().splitlines() 81 | return G, source, dest 82 | 83 | 84 | 85 | def DrawPath(G, source, dest): 86 | pos = nx.spring_layout(G) 87 | val_map = {} 88 | val_map[source] = 'green' 89 | val_map[dest] = 'red' 90 | values = [val_map.get(node, 'blue') for node in G.nodes()] 91 | nx.draw(G, pos, with_labels = True, node_color = values, edge_color = 'b' ,width = 1, alpha = 0.7) #with_labels=true is to show the node number in the output graph 92 | edge_labels = dict([((u, v,), d['length']) for u, v, d in G.edges(data = True)]) 93 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, label_pos = 0.5, font_size = 11) #prints weight on all the edges 94 | return pos 95 | 96 | 97 | 98 | #main function 99 | if __name__ == "__main__": 100 | G, source,dest = CreateGraph() 101 | heuristics = getHeuristics(G) 102 | pos = DrawPath(G, source, dest) 103 | aStarSearch(G, source, dest, heuristics, pos) 104 | plt.show() 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /A_star_search/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of A* Search using networkx library 2 | 3 | ### A* Search ### 4 | 5 | A* search( pronounced as "A star") is a search algorithm which explores a graph by expanding the that node which minimizes steps from the source(like in BFS) as well as approximate steps to the goal(like in greedy bfs). Hence, this algorithm is thorough and fast as it combines the strengths of both BFS and Greedy BFS. 6 | A* algorithm is proven to give the optimal solution to a problem. 7 | 8 | What is the evaluation function here? 9 | 10 | Evaluation function-f is the criterion based on which the next node is chosen. 11 | f is the sum of 2 parameters: 12 | 1. cost of path from source to the given node 13 | 2. approximate cost of reaching the goal from the given node (heuristic function) 14 | So, at each step, the node is chosen such that sum of the above 2 parameters, that is, f is minimal. 15 | 16 | ### Algorithm 17 | 18 | Starting from source city, we choose the next city such that it is in the shortest path from the source (based on the cost of the route from source) as well as the closest to the Goal city(based on the heuristics function) amongst all it's neighbours. We terminate, once we've reached the goal city. 19 | 20 | 21 | 22 | Let us understand this better through an example. 23 | 24 | ![Romania map](https://user-images.githubusercontent.com/22571531/27821959-ac69755a-60c1-11e7-8286-951cd1c0437f.png) 25 | 26 | Source: Artificial Intelligence A Modern Approach 27 | by Stuart J. Russell and Peter Norvig 28 | 29 | Given here is the map of Romania with cities and distance between them. We need to find the shortest route from Arad to Bucharest. 30 | 31 | The heurestics that we are using here is the straight-line distance from the city to the goal(Here, Bucharest). Note that, this straight line distance is obtained only by knowing the map coordinates of the 2 cities. 32 | 33 | 34 | #### Input 35 | 36 | Input is taken from the file 37 | ``` 38 | input.txt 39 | ``` 40 | 41 | Each line in the input is of the form 42 | ``` 43 | city1 city2 dist 44 | ``` 45 | It denotes each element of the adjacency list. That is, dist is the distance between city1 and city2. An undireced graph is drawn depicting the map of Romania. 46 | Starting city: Arad 47 | Goal city: Bucharest 48 | 49 | Heuristics is loaded from the file 50 | ``` 51 | heuristics.txt 52 | ``` 53 | Each line is of the form 54 | ``` 55 | city h 56 | ``` 57 | 'h' stands for the heuristics value(here, the straight line distnace) from the city 'city' to goal city(here, Bucharest) 58 | 59 | #### Working: 60 | 61 | 62 | Here, Arad is the starting city. The first node to be expanded from Arad will be Sibiu, because it has a smaller value of f (140+253=393) than either Zerind (75+374=449_)or Timisoara(118 + 329 =447). The next node to be expanded will be Rimnicu_Vilcia, because it has a smaller f compared to other possible nodes. Similary, Pitesti is expanded next and finally Bucharest is reached. 63 | 64 | Here, is the resultant graph. 65 | Green coloured node denotes the starting city(Here, Arad). 66 | Red coloured node denotes the goal city(Here, Bucharest). 67 | Edges marked with black is the route from Arad to Bucharest generated by the A* search algorithm. 68 | ![final-route](https://user-images.githubusercontent.com/22571531/27867257-c85c0e94-61b6-11e7-8b08-c2b1972e67b3.png) 69 | 70 | #### Complexity #### 71 | 72 | Time: O(b^d) 73 | b - Branching factor, the average number of successors per state 74 | d - depth of the shortest path -------------------------------------------------------------------------------- /Dijsktra's/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Dijsktra's algorithm using networkx library 2 | 3 | ### INPUT ### 4 | 5 | 6 | Input is taken from the file 7 | #### input.txt #### 8 | 9 | Sample input 10 | ``` 11 | 5 12 | 0 2 7 -1 -1 13 | -1 0 3 8 5 14 | -1 2 0 1 -1 15 | -1 -1 -1 0 4 16 | -1 -1 -1 5 0 17 | 0 18 | 19 | 20 | ``` 21 | First line contains the number of nodes,say n.(Nodes are numbered as 0,1,2,...(n-1) ) 22 | Followed by n*n weighted matrix. Disconnected egdes are represented by negative weight. 23 | Last line contains the source node.(i.e, the node from which the rest of the nodes should be reached) 24 | 25 | ### Draw Graph ### 26 | 27 | 28 | Graph is first drawn from the weighted matrix input from the user with weights shown. Edges are marked with black. 29 | 30 | 31 | 32 | ### Dijsktras algorithm ### 33 | 34 | DDijkstra's algorithm is an algorithm for finding the shortest paths between nodes in a graph. 35 | 36 | Here, given the source node, the algorithm finds the shortest path from the source node to each of the remaining nodes. 37 | 38 | To understand this better, consider the above input. 39 | Source node is 0. 40 | 41 | The graph, initially. 42 | 43 | ![1](https://user-images.githubusercontent.com/22571531/27195526-ca5dd872-5224-11e7-9b34-e669c7082a6e.png) 44 | 45 | We use the following 3 lists: 46 | 47 | #### dist #### 48 | dist[i] will hold the shortest distance from source to i. 49 | #### parent #### 50 | parent[i] will hold the node from which node i is reached to, in the shortest path from source. 51 | #### sptSet #### 52 | sptSet[i] will hold true if vertex i is included in shortest path tree. 53 | 54 | #### Initial values: #### 55 | ``` 56 | dist = [0, inf ,inf, inf, inf] 57 | parent = [-1, None, None, None] 58 | sptSet = [True, False, False, False, False] 59 | ``` 60 | 61 | #### After the first iteration: #### 62 | 63 | Node 1 and Node 2 can be reached directly from source node,i.e, 0 with a distance of 2 and 7 respectively. Hence they are updated accordingly. 64 | 65 | ``` 66 | dist = [0, 2, 7, inf, inf] 67 | parent = [-1, 0, 0, None, None] 68 | sptSet = [True, False, False, False, False] 69 | ``` 70 | 71 | Minimum most distance of those where sptSet[i] == False, is node 1. 72 | Hence, the node is now included in the shorted path tree, hence sptSet[1] is set to True. 73 | 74 | ![2](https://user-images.githubusercontent.com/22571531/27195530-cd783296-5224-11e7-87f5-a404a94fed84.png) 75 | 76 | 77 | #### After the second iteration: #### 78 | 79 | ``` 80 | dist = [0, 2, 5, 10, 7] 81 | parent = [-1, 0, 1, 1, 1] 82 | sptSet = [True, True, False, False, False] 83 | ``` 84 | 85 | ![3](https://user-images.githubusercontent.com/22571531/27195531-d081e824-5224-11e7-8993-81f2dc43c30f.png) 86 | 87 | #### After the third iteration: #### 88 | 89 | ``` 90 | dist = [0, 2, 5, 6, 7] 91 | parent = [-1, 0, 1, 2, 1] 92 | sptSet = [True, True, True, False, False] 93 | ``` 94 | 95 | ![4](https://user-images.githubusercontent.com/22571531/27195536-d310f896-5224-11e7-8a75-eb5e883bc37b.png) 96 | 97 | #### After the fourth iteration: #### 98 | 99 | ``` 100 | dist = [0, 2, 5, 6, 7] 101 | parent = [-1, 0, 1, 2, 1] 102 | sptSet = [True, True, True, True, False] 103 | ``` 104 | 105 | Here, the red edges denote the shortest path from source node to the rest of the nodes. 106 | 107 | ![5](https://user-images.githubusercontent.com/22571531/27195545-d8cfdf68-5224-11e7-8ee9-1b2d38e1d6ad.png) 108 | 109 | #### Complexity #### 110 | Time : O(V^2) 111 | V - number of Vertices 112 | -------------------------------------------------------------------------------- /Egocentric Network/egocentric_network_2.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import itertools 4 | 5 | 6 | def EgocentricNetwork(G,v): 7 | 8 | egocentric_network_edge_list = [] 9 | egocentric_network_node_list = [v] 10 | for i in G.neighbors(v): 11 | egocentric_network_node_list.append(i) 12 | egocentric_network_edge_list.append((v,i)) 13 | egocentric_network_node_list.sort() 14 | egocentric_network_edge_list = list(tuple(sorted(p)) for p in egocentric_network_edge_list) 15 | 16 | for i in list(itertools.combinations(egocentric_network_node_list, 2)): #generates all possible pairs of nodes 17 | if i in G.edges() and i not in egocentric_network_edge_list: 18 | egocentric_network_edge_list.append(i) 19 | 20 | 21 | temp = [] 22 | temp.extend(egocentric_network_node_list) 23 | 24 | for i in temp:#print i," ",G.neighbors(i) 25 | for j in G.neighbors(i): 26 | if j not in egocentric_network_node_list: 27 | egocentric_network_node_list.append(j) 28 | if (j,i) in G.edges() and (j,i) not in egocentric_network_edge_list: 29 | egocentric_network_edge_list.append((j,i)) 30 | elif (i,j) in G.edges() and (i,j) not in egocentric_network_edge_list: 31 | egocentric_network_edge_list.append((i,j)) 32 | print egocentric_network_edge_list 33 | print egocentric_network_node_list 34 | return egocentric_network_edge_list,egocentric_network_node_list 35 | 36 | 37 | 38 | #takes input from the file and creates a graph 39 | def CreateGraph(): 40 | G = nx.Graph() 41 | f = open('input.txt') 42 | n = int(f.readline()) 43 | for i in range(n): 44 | G.add_node(i+1) 45 | no_of_edges = int(f.readline()) 46 | for i in range(no_of_edges): 47 | graph_edge_list = f.readline().split() 48 | G.add_edge(int(graph_edge_list[0]), int(graph_edge_list[1])) 49 | vert = int(f.readline()) 50 | return G, vert 51 | 52 | 53 | 54 | #draws the graph and displays the weights on the edges 55 | def DrawGraph(G,egocentric_network_edge_list,egocentric_network_node_list): 56 | pos = nx.spring_layout(G) 57 | nx.draw(G, pos, with_labels = True, node_color = 'blue', alpha = 0.2) #with_labels=true is to show the node number in the output graph 58 | nx.draw_networkx_edges(G, pos, edgelist = egocentric_network_edge_list , width = 2.5, alpha = 0.8, edge_color = 'blue') 59 | nx.draw_networkx_nodes(G,pos, nodelist = egocentric_network_node_list, node_color = 'blue', alpha = 0.5) 60 | return pos 61 | 62 | 63 | def DrawGraph(G, egocentric_network_edge_list, egocentric_network_node_list, vert): 64 | pos = nx.spring_layout(G) 65 | nx.draw(G, pos, with_labels = True, node_color = 'blue', alpha = 0.8) #with_labels=true is to show the node number in the output graph 66 | nx.draw_networkx_edges(G, pos, edgelist = egocentric_network_edge_list , width = 2.5, alpha = 0.8, edge_color = 'red') 67 | nx.draw_networkx_nodes(G,pos, nodelist = egocentric_network_node_list, node_color = 'red', alpha = 0.5) 68 | nx.draw_networkx_nodes(G,pos,nodelist=[vert],node_color='green',node_size=500,alpha=0.8) 69 | return pos 70 | 71 | 72 | def CentralityMeasures(G): 73 | # Betweenness centrality 74 | bet_cen = nx.betweenness_centrality(G) 75 | # Closeness centrality 76 | clo_cen = nx.closeness_centrality(G) 77 | # Eigenvector centrality 78 | eig_cen = nx.eigenvector_centrality(G) 79 | # Degree centrality 80 | deg_cen = nx.degree_centrality(G) 81 | #print bet_cen, clo_cen, eig_cen 82 | print "# Betweenness centrality:" + str(bet_cen) 83 | print "# Closeness centrality:" + str(clo_cen) 84 | print "# Eigenvector centrality:" + str(eig_cen) 85 | print "# Degree centrality:" + str(deg_cen) 86 | 87 | 88 | #main function 89 | if __name__== "__main__": 90 | G,vert = CreateGraph() 91 | egocentric_network_edge_list,egocentric_network_node_list = EgocentricNetwork(G,vert) 92 | DrawGraph(G,egocentric_network_edge_list,egocentric_network_node_list, vert) 93 | CentralityMeasures(G) 94 | plt.show() 95 | 96 | -------------------------------------------------------------------------------- /Kruskal's/kruskals_quick_union.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import sys 4 | 5 | 6 | 7 | # A utility function that return the smallest unprocessed edge 8 | def getMin(G, mstFlag): 9 | min = sys.maxsize # assigning largest numeric value to min 10 | for i in [(u, v, edata['length']) for u, v, edata in G.edges( data = True) if 'length' in edata ]: 11 | if mstFlag[i] == False and i[2] < min: 12 | min = i[2] 13 | min_edge = i 14 | return min_edge 15 | 16 | 17 | 18 | # A utility function to find root or origin of the node i in MST 19 | def findRoot(parent, i): 20 | if parent[i] == i: 21 | return i 22 | return findRoot(parent, parent[i]) 23 | 24 | 25 | 26 | # A function that does union of set x and y based on the order 27 | def union(parent, order, x, y): 28 | xRoot = findRoot(parent, x) 29 | yRoot = findRoot(parent, y) 30 | # Attach smaller order tree under root of high order tree 31 | if order[xRoot] < order[yRoot]: 32 | parent[xRoot] = yRoot 33 | elif order[xRoot] > order[yRoot]: 34 | parent[yRoot] = xRoot 35 | # If orders are same, then make any one as root and increment its order by one 36 | else : 37 | parent[yRoot] = xRoot 38 | order[xRoot] += 1 39 | 40 | 41 | 42 | # function that performs Kruskals algorithm on the graph G 43 | def kruskals(G, pos): 44 | eLen = len(G.edges()) # eLen denotes the number of edges in G 45 | vLen = len(G.nodes()) # vLen denotes the number of vertices in G 46 | mst = [] # mst contains the MST edges 47 | mstFlag = {} # mstFlag[i] will hold true if the edge i has been processed for MST 48 | for i in [ (u, v, edata['length']) for u, v, edata in G.edges(data = True) if 'length' in edata ]: 49 | mstFlag[i] = False 50 | 51 | parent = [None] * vLen # parent[i] will hold the vertex connected to i, in the MST 52 | order = [None] * vLen # order[i] will hold the order of appearance of the node in the MST 53 | for v in range(vLen): 54 | parent[v] = v 55 | order[v] = 0 56 | while len(mst) < vLen - 1 : 57 | curr_edge = getMin(G, mstFlag) # pick the smallest egde from the set of edges 58 | mstFlag[curr_edge] = True # update the flag for the current edge 59 | y = findRoot(parent, curr_edge[1]) 60 | x = findRoot(parent, curr_edge[0]) 61 | # adds the edge to MST, if including it doesn't form a cycle 62 | if x != y: 63 | mst.append(curr_edge) 64 | union(parent, order, x, y) 65 | # Else discard the edge 66 | # marks the MST edges with red 67 | for X in mst: 68 | if (X[0], X[1]) in G.edges(): 69 | nx.draw_networkx_edges(G, pos, edgelist = [(X[0], X[1])], width = 2.5, alpha = 0.6, edge_color = 'r') 70 | return 71 | 72 | 73 | 74 | # takes input from the file and creates a weighted graph 75 | def CreateGraph(): 76 | G = nx.Graph() 77 | f = open('input.txt') 78 | n = int(f.readline()) 79 | wtMatrix = [] 80 | for i in range(n): 81 | list1 = map(int, (f.readline()).split()) 82 | wtMatrix.append(list1) 83 | # Adds egdes along with their weights to the graph 84 | for i in range(n) : 85 | for j in range(n)[i:] : 86 | if wtMatrix[i][j] > 0 : 87 | G.add_edge(i, j, length = wtMatrix[i][j]) 88 | return G 89 | 90 | 91 | 92 | # draws the graph and displays the weights on the edges 93 | def DrawGraph(G): 94 | pos = nx.spring_layout(G) 95 | nx.draw(G, pos, with_labels = True) # with_labels=true is to show the node number in the output graph 96 | edge_labels = nx.get_edge_attributes(G, 'length') 97 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, font_size = 11) # prints weight on all the edges 98 | return pos 99 | 100 | 101 | 102 | # main function 103 | if __name__ == "__main__": 104 | G = CreateGraph() 105 | pos = DrawGraph(G) 106 | kruskals(G, pos) 107 | plt.show() 108 | 109 | -------------------------------------------------------------------------------- /Prim's/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Prim's algorithm using networkx library 2 | 3 | ### INPUT ### 4 | 5 | 6 | Input is taken from the file 7 | #### input.txt #### 8 | 9 | Sample input 10 | ``` 11 | 5 12 | 0 2 7 -1 -1 13 | 2 0 3 8 5 14 | 7 3 0 1 -1 15 | -1 8 1 0 4 16 | -1 5 -1 4 0 17 | 18 | ``` 19 | First line contains the number of nodes,say n.(Nodes are numbered as 0,1,2,...(n-1) ) 20 | Followed by n*n weighted matrix. Disconnected egdes are represented by negative weight. 21 | 22 | ### Draw Graph ### 23 | 24 | 25 | Graph is first drawn from the weighted matrix input from the user with weights shown. Edges are marked with black. 26 | 27 | 28 | 29 | ### Prim's algorithm ### 30 | 31 | Prim's algorithm is a greedy algorithm that finds a minimum spanning tree for 32 | a weighted undirected garph. 33 | 34 | Here, starting from an arbitrary node, the algorithm operates by building this tree one vertex at a time. At each step, smallest egde connection (also known as cut) from the tree to another vertex is added to the resulting tree. 35 | 36 | To understand this better, consider the above input. 37 | Let the arbitrary starting node be 0. 38 | 39 | The graph, initially. 40 | 41 | ![1](https://user-images.githubusercontent.com/22571531/27369441-88710056-5675-11e7-8b11-251a2992b38b.png) 42 | 43 | We use the following 3 lists: 44 | 45 | #### dist #### 46 | dist[i] will hold the minimum weight edge value of node i to be included in MST(Minimum Spanning Tree). 47 | #### parent #### 48 | parent[i] will hold the vertex connected to i, in the MST edge. 49 | #### mstSet #### 50 | mstSet[i] will hold true if vertex i is included in the MST. 51 | 52 | #### Initial values: #### 53 | ``` 54 | dist = [0, inf ,inf, inf, inf] 55 | parent = [-1, None, None, None] 56 | mstSet = [True, False, False, False, False] 57 | ``` 58 | 59 | #### After the first iteration: #### 60 | 61 | Node 1 and Node 2 form an edge with the starting node,i.e, 0 with a distance of 2 and 7 respectively. Hence they are updated accordingly. 62 | 63 | ``` 64 | dist = [0, 2, 7, inf, inf] 65 | parent = [-1, 0, 0, None, None] 66 | mstSet = [True, False, False, False, False] 67 | ``` 68 | 69 | Minimum most edge value of the nodes which are not included in the MST yet, i.e, where mstSet[i] == False, is node 1. 70 | The node is now included in the MST, and thus, mstSet[1] is set to True. 71 | 72 | ![2](https://user-images.githubusercontent.com/22571531/27369443-8aded584-5675-11e7-9a35-a34dd3b4ba40.png) 73 | 74 | 75 | #### After the second iteration: #### 76 | 77 | ``` 78 | dist = [0, 2, 3, 8, 5] 79 | parent = [-1, 0, 1, 1, 1] 80 | mstSet = [True, True, False, False, False] 81 | ``` 82 | 83 | ![3](https://user-images.githubusercontent.com/22571531/27369444-8d5e5a6e-5675-11e7-9e82-d44277d59257.png) 84 | 85 | #### After the third iteration: #### 86 | 87 | ``` 88 | dist = [0, 2, 3, 1, 5] 89 | parent = [-1, 0, 1, 2, 1] 90 | mstSet = [True, True, True, False, False] 91 | ``` 92 | 93 | ![4](https://user-images.githubusercontent.com/22571531/27369448-917e86be-5675-11e7-8ecf-6d92d4e34782.png) 94 | 95 | #### After the fourth iteration: #### 96 | 97 | ``` 98 | dist = [0, 2, 3, 1, 4] 99 | parent = [-1, 0, 1, 2, 3] 100 | mstSet = [True, True, True, True, False] 101 | ``` 102 | 103 | Here, the red edges denote the Minimum Spanning Tree 104 | 105 | ![5](https://user-images.githubusercontent.com/22571531/27369450-947b6710-5675-11e7-81e3-0aff0dd4d224.png) 106 | 107 | #### Complexity #### 108 | 109 | Time: O(V^2) 110 | V - Number of vertices 111 | -------------------------------------------------------------------------------- /Greedy BFS/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Visualisation of Greedy BFS using networkx library 4 | 5 | ### Greedy Best First Search ### 6 | 7 | Best-first search is a search algorithm which explores a graph by expanding the most promising node chosen according to a specified rule. A greedy algorithm is one that chooses the best-looking option at each step. Hence, greedy best-first search algorithm combines the features of both mentioned above. It is known to be moving towards the direction of the target, in each step. (PS: There is no visiting back in path, as it is Greedy) 8 | 9 | #### Heuristic function 10 | 11 | Greedy BFS uses heuristics to the pick the "best" node. 12 | 13 | A heuristic is an approximate measure of how close you are to the target. In short, h can be any function at all. We will require only that h(n) = 0 if n is a goal. 14 | 15 | #### BFS v/s Greedy BFS 16 | 17 | BFS expands the most promising node first(by looking at it's proximity to the source node).Hence, the solution is thorough. It might have to return back in path if a dead end is reached. 18 | Whereas, Greedy BFS uses heuristics to prioritize nodes closer to target. Hence, the solution is faster(but not necessarily optimal). There is no returning back in the path. 19 | 20 | Often with large data sets, search algorithms could get computationally expensive with thorough approaches. Hence, we resort to approximation algorithms like Greedy BFS. 21 | 22 | ### Greedy BFS Algorithm 23 | 24 | Heuristic functions are clearly problem-specific. 25 | 26 | Let us understand this better through an example. 27 | 28 | ![Romania map](https://user-images.githubusercontent.com/22571531/27821959-ac69755a-60c1-11e7-8286-951cd1c0437f.png) 29 | 30 | Source: Artificial Intelligence A Modern Approach 31 | by Stuart J. Russell and Peter Norvig 32 | 33 | Given here is the map of Romania with cities and distance between them. We need to find the shortest route from Arad to Bucharest. 34 | 35 | The heurestics that we are using here is the straight-line distance from the city to the goal(Here, Bucharest). Note that, this straight line distance is obtained only by knowing the map coordinates of the 2 cities. 36 | 37 | 38 | #### Input 39 | 40 | Input is taken from the file 41 | ``` 42 | input.txt 43 | ``` 44 | 45 | Each line in the input is of the form 46 | ``` 47 | city1 city2 dist 48 | ``` 49 | It denotes each element of the adjacency list. That is, dist is the distance between city1 and city2. An undireced graph is drawn depicting the map of Romania. 50 | Starting city: Arad 51 | Goal city: Bucharest 52 | 53 | Heuristics is loaded from the file 54 | ``` 55 | heuristics.txt 56 | ``` 57 | Each line is of the form 58 | ``` 59 | city h 60 | ``` 61 | 'h' stands for the heuristics value(here, the straight line distnace) from the city 'city' to goal city(here, Bucharest) 62 | 63 | #### Working: 64 | 65 | Starting from source city, we choose the next city which is the closest to the Goal city amongst all it's neighbours(based on the heuristics function). We terminate, once we've reached the goal city. 66 | 67 | Here, Arad is the starting city. The first node to be expanded from Arad will be Sibiu, because it is closer to Bucharest than either Zerind or Timisoara. The next node to be expanded will be Fagaras, because it is closest. Fagaras in turn generates Bucharest, which is the goal. 68 | 69 | Here, is the resultant graph. 70 | Green coloured node denotes the starting city(Here, Arad). 71 | Red coloured node denotes the goal city(Here, Bucharest). 72 | Edges marked with black is the route from Arad to Bucharest generated by the greedy bfs algorithm. 73 | 74 | ![shortest route](https://user-images.githubusercontent.com/22571531/27821965-b12030d4-60c1-11e7-9e37-9388e4dd8751.png) 75 | 76 | #### Complexity #### 77 | 78 | Time: O(b^m) 79 | b - Branching factor, the average number of successors per state 80 | m - maximum depth of the search 81 | -------------------------------------------------------------------------------- /Assignment Problem/assignment_prob_hungarian.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | from networkx.algorithms import bipartite 4 | from string import ascii_lowercase 5 | 6 | 7 | 8 | def init_labels(cost): 9 | n = len(cost) 10 | lx = [0] * n 11 | ly = [0] * n 12 | for x in range(n): 13 | for y in range(n): 14 | lx[x] = max(lx[x], cost[x][y]) 15 | return lx,ly 16 | 17 | 18 | 19 | def update_labels(T, slack, S, lx, ly, n): 20 | delta = float("inf"); 21 | for y in range(n): 22 | if T[y] == 0: 23 | delta = min(delta, slack[y]) 24 | for x in range(n): 25 | if S[x] != 0: 26 | lx[x] -= delta 27 | for y in range(n): 28 | if T[y] != 0: 29 | ly[y] += delta 30 | for y in range(n): 31 | if T[y] == 0: 32 | slack[y] -= delta 33 | 34 | 35 | 36 | def add_to_tree(x, prevx, S, prev, lx, ly, slack, slackx, cost): 37 | n = len(cost) 38 | S[x] = True 39 | prev[x] = prevx 40 | for y in range(n): 41 | if (lx[x] + ly[y] - cost[x][y]) < slack[y]: 42 | slack[y] = lx[x] + ly[y] - cost[x][y] 43 | slackx[y] = x 44 | 45 | 46 | 47 | def augment(cost, max_match, xy, yx, lx, ly, slack, slackx): 48 | n = len(cost) 49 | if max_match == n: 50 | return; 51 | q = [0] * n 52 | wr = 0 53 | rd = 0 54 | root = 0 55 | S = [False] * n 56 | T = [False] * n 57 | prev = [-1] * n 58 | for x in range(n): 59 | if xy[x] == -1: 60 | q[wr] = x 61 | wr = wr+1 62 | root = x 63 | prev[x] = -2 64 | S[x] = True 65 | break 66 | for y in range(n): 67 | slack[y] = lx[root] + ly[y] - cost[root][y] 68 | slackx[y] = root 69 | while True: 70 | while rd < wr: 71 | x = q[rd] 72 | rd = rd+1 73 | for y in range(n): 74 | if (cost[x][y] == lx[x] + ly[y] and T[y] == 0): 75 | if yx[y] == -1: 76 | break 77 | T[y] = True 78 | q[wr] = yx[y] 79 | wr = wr+1 80 | add_to_tree(yx[y], x, S, prev, lx, ly, slack, slackx, cost) 81 | if y < n: 82 | break 83 | if y < n: 84 | break 85 | update_labels(T, slack, S, lx, ly, n) 86 | wr = 0 87 | rd = 0 88 | for y in range(n): 89 | if T[y] == 0 and slack[y] == 0: 90 | if yx[y] == -1: 91 | x = slackx[y] 92 | break 93 | else: 94 | T[y] = true 95 | if S[yx[y]] == 0: 96 | q[wr] = yx[y] 97 | wr = wr+1 98 | add_to_tree(yx[y], slackx[y], S, prev, lx, ly, slack, slackx, cost) 99 | if y < n: 100 | break 101 | if y < n: 102 | max_match = max_match+1 103 | cx = x 104 | cy = y 105 | ty = 0 106 | flag = 0 107 | if cx != -2: 108 | ty = xy[cx]; 109 | yx[cy] = cx; 110 | xy[cx] = cy; 111 | cx = prev[cx] 112 | cy = ty 113 | while cx != -2: 114 | ty = xy[cx] 115 | yx[cy] = cx 116 | xy[cx] = cy 117 | cx = prev[cx] 118 | cy = ty 119 | augment(cost, max_match, xy, yx, lx, ly, slack, slackx) 120 | 121 | 122 | 123 | def hungarian(B ,pos ,cost): 124 | n = len(cost) 125 | ret = 0; 126 | max_match = 0 127 | xy = [-1] * n 128 | yx = [-1] * n 129 | slack = [0] * n 130 | slackx = [0] * n 131 | lx, ly = init_labels(cost) 132 | augment(cost, max_match, xy, yx, lx, ly, slack, slackx) 133 | for x in range(n): 134 | if (x, chr(xy[x]+97)) in B.edges(): 135 | nx.draw_networkx_edges(B, pos, edgelist = [(x, chr(xy[x]+97))], width = 2.5, alpha = 0.6, edge_color = 'r') 136 | 137 | 138 | 139 | #takes input from the file and creates a weighted bipartite graph 140 | def CreateGraph(): 141 | B = nx.DiGraph(); 142 | f = open('input.txt') 143 | n = int(f.readline()) 144 | cost = [] 145 | 146 | for i in range(n): 147 | list1 = map(int, (f.readline()).split()) 148 | cost.append(list1) 149 | people = [] 150 | for i in range(n): 151 | people.append(i) 152 | job = [] 153 | for c in ascii_lowercase[:n]: 154 | job.append(c) 155 | B.add_nodes_from(people, bipartite=0) # Add the node attribute "bipartite" 156 | B.add_nodes_from(job, bipartite=1) 157 | for i in range(n) : 158 | for c in ascii_lowercase[:n] : 159 | if cost[i][ord(c)-97] > 0 : 160 | B.add_edge(i, c, length = cost[i][ord(c)-97]) 161 | return B,cost 162 | 163 | 164 | 165 | def DrawGraph(B): 166 | l, r = nx.bipartite.sets(B) 167 | pos = {} 168 | # Update position for node from each group 169 | pos.update((node, (1, index)) for index, node in enumerate(l)) 170 | pos.update((node, (2, index)) for index, node in enumerate(r)) 171 | nx.draw(B, pos, with_labels = True) #with_labels=true is to show the node number in the output graph 172 | edge_labels = dict([((u, v), d['length']) for u, v, d in B.edges(data = True)]) 173 | nx.draw_networkx_edge_labels(B, pos, edge_labels = edge_labels, label_pos = 0.2, font_size = 11) #prints weight on all the edges 174 | return pos 175 | 176 | 177 | 178 | #main function 179 | if __name__ == "__main__": 180 | B, cost = CreateGraph(); 181 | pos = DrawGraph(B) 182 | hungarian(B, pos, cost) 183 | plt.show() 184 | -------------------------------------------------------------------------------- /Travelling Salesman Problem/README.md: -------------------------------------------------------------------------------- 1 | # Visualisation of Travelling Salesman Problem using networkx library 2 | 3 | ### Travelling Salesman Problem ### 4 | 5 | Travelling salesman problem is a NP hard problem. Given a set of cities and the distance between every pair of cities, the problem is to find the shortest possible route that visits each city exactly once and returns back to the original city. Hence, it also belongs to the class of optimization problems. 6 | 7 | #### Why NP-hard? 8 | 9 | First, let us understand the definition of NP- hard. 10 | NP (nondeterministic polynomial time) problem is the one whose solution could be verified in polynomial time but the problem is not guaranteed to be solved in polynomial time. 11 | Now, NP - hard problem are those which are atleast as hard as any NP problem. 12 | NP complete problem is the class of problems that are both NP and NP-hard. 13 | 14 | Let us now check both the conditions. 15 | 16 | ##### condition (i): NP 17 | To check that given solution is the right solution for a TSP problem. We need to verify two things: 18 | Firstly, each city must be visited exactly once. (could be done in polynomial time) 19 | Secondly, there is no shorter route than the current solution. (This cannot be guaranteed in polynomial time) 20 | Hence, TSP is not NP 21 | 22 | ##### condition (ii): NP hard 23 | Surely TSP is a NP hard problem. (For, even it's solution can't be guaranteed in polynomial time) 24 | 25 | Thus, TSP belongs to the class of NP-hard problem and not NP-complete. 26 | 27 | 28 | Brute force approach for TSP will need all possible paths to be calculated which is (n-1)! paths( where n is the number of cities). As n increases, it is computationally not feasible to compute that many paths. 29 | 30 | There are certain approximation algorithms for TSP which guarantees to solve the problem in polynomial time at the cost of solution not being exact. Christofides algorithm, is one such heuristics approach which guarantees it's solution to be within a factor of 1.5 of the optimal solution. By far, Christofides algorithm (time complexity : O(n^3)) is known to have the best approximation ratio for a general TSP problem. 31 | 32 | #### Christofides algorithm: 33 | 34 | 1. Create a minimum spanning tree MST of G. (using Kruskal's or Prim's algorithm) 35 | 2. Let odd_vert be the set of vertices with odd degree in MST. The number of vertices with odd_degree is guaranteed to be even( Proof: Handshaking Lemma). 36 | 3. Find a minimum-weight perfect matching pairs in the induced subgraph given by the vertices from odd_vert. Add those edges to MST. 37 | The resulting MST now has all the vertices with even degree- hence, is a Eulerian circuit. 38 | 4. Make the circuit found in previous step into a Hamiltonian circuit by skipping repeated vertices. 39 | 40 | The code here,is an implementation of Christofides algorithm. 41 | 42 | ### INPUT ### 43 | 44 | 45 | Input is taken from the file 46 | #### input.txt #### 47 | 48 | Sample input 49 | ``` 50 | 5 51 | 0 10 8 9 7 52 | 10 0 10 5 6 53 | 8 10 0 8 9 54 | 9 5 8 0 6 55 | 7 6 9 6 0 56 | 57 | ``` 58 | First line contains n, the number of cities. 59 | Followed by n*n distance matrix where matrix[i][j] denotes the distance between city i and city j. 60 | 61 | 62 | ### Draw Graph ### 63 | 64 | 65 | An undireced graph is drawn with nodes representing the cities and egde labels denoting the distance between them. 66 | 67 | ![screenshot from 2017-06-29 12-50-58](https://user-images.githubusercontent.com/22571531/27676532-f2af862a-5ccb-11e7-9ba3-8a9cb87adca9.png) 68 | 69 | Step 1: 70 | 71 | A minimum spanning tree MST is obtained from the given grapg G (using Kruskal's algorithm) 72 | 73 | ![screenshot from 2017-06-29 12-53-47](https://user-images.githubusercontent.com/22571531/27676537-f787e962-5ccb-11e7-8da7-e48e223d33a8.png) 74 | 75 | Step 2: 76 | 77 | There are 2 vertices with odd degree in MST graph, that is, node 2 and node 3. 78 | Hence, odd_vert = [2,3] 79 | 80 | Step 3: 81 | 82 | Since there are only 2 vertices in odd_vert, we get one minimum weight matching pair, i,e, (2,3). Adding this edge to MST, we have the below graph. 83 | 84 | ![screenshot from 2017-06-29 12-48-48](https://user-images.githubusercontent.com/22571531/27676543-fb8d0d76-5ccb-11e7-93b9-bc7d6767b24d.png) 85 | 86 | 87 | Step 4: 88 | 89 | Finding the shortest hamiltonian circuit from the above graph (by skipping already visisted vertices) , we have 90 | ``` 91 | 0 -> 2 -> 3 -> 1 -> 4 -> 0 92 | ``` 93 | 94 | The below diagram shows the shortest route for TSP. 95 | PS: The arrows here are just for visual purposes to denote the route. The cycle could be traversed in any direction. 96 | 97 | ![second](https://user-images.githubusercontent.com/22571531/27676549-01632fc8-5ccc-11e7-964e-eece9960b4b8.png) 98 | 99 | #### Complexity #### 100 | 101 | Time: O(n^3) 102 | n - number of Nodes -------------------------------------------------------------------------------- /Travelling Salesman Problem/tsp_christofides.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import matplotlib.pyplot as plt 3 | import sys 4 | 5 | # A utility function that return the smallest unprocessed edge 6 | def getMin(G, mstFlag): 7 | min = sys.maxsize # assigning largest numeric value to min 8 | for i in [(u, v, edata['length']) for u, v, edata in G.edges( data = True) if 'length' in edata ]: 9 | if mstFlag[i] == False and i[2] < min: 10 | min = i[2] 11 | min_edge = i 12 | return min_edge 13 | 14 | # A utility function to find root or origin of the node i in MST 15 | def findRoot(parent, i): 16 | if parent[i] == i: 17 | return i 18 | return findRoot(parent, parent[i]) 19 | 20 | 21 | # A function that does union of set x and y based on the order 22 | def union(parent, order, x, y): 23 | xRoot = findRoot(parent, x) 24 | yRoot = findRoot(parent, y) 25 | # Attach smaller order tree under root of high order tree 26 | if order[xRoot] < order[yRoot]: 27 | parent[xRoot] = yRoot 28 | elif order[xRoot] > order[yRoot]: 29 | parent[yRoot] = xRoot 30 | # If orders are same, then make any one as root and increment its order by one 31 | else : 32 | parent[yRoot] = xRoot 33 | order[xRoot] += 1 34 | 35 | #function that performs kruskals algorithm on the graph G 36 | def genMinimumSpanningTree(G): 37 | MST = nx.Graph() 38 | eLen = len(G.edges()) # eLen denotes the number of edges in G 39 | vLen = len(G.nodes()) # vLen denotes the number of vertices in G 40 | mst = [] # mst contains the MST edges 41 | mstFlag = {} # mstFlag[i] will hold true if the edge i has been processed for MST 42 | for i in [ (u, v, edata['length']) for u, v, edata in G.edges(data = True) if 'length' in edata ]: 43 | mstFlag[i] = False 44 | 45 | parent = [None] * vLen # parent[i] will hold the vertex connected to i, in the MST 46 | order = [None] * vLen # order[i] will hold the order of appearance of the node in the MST 47 | for v in range(vLen): 48 | parent[v] = v 49 | order[v] = 0 50 | while len(mst) < vLen - 1 : 51 | curr_edge = getMin(G, mstFlag) # pick the smallest egde from the set of edges 52 | mstFlag[curr_edge] = True # update the flag for the current edge 53 | y = findRoot(parent, curr_edge[1]) 54 | x = findRoot(parent, curr_edge[0]) 55 | # adds the edge to MST, if including it doesn't form a cycle 56 | if x != y: 57 | mst.append(curr_edge) 58 | union(parent, order, x, y) 59 | # Else discard the edge 60 | for X in mst: 61 | if (X[0], X[1]) in G.edges(): 62 | MST.add_edge(X[0], X[1], length = G[X[0]][X[1]]['length']) 63 | return MST 64 | 65 | 66 | #utility function that adds minimum weight matching edges to MST 67 | def minimumWeightedMatching(MST, G, odd_vert): 68 | while odd_vert: 69 | v = odd_vert.pop() 70 | length = float("inf") 71 | u = 1 72 | closest = 0 73 | for u in odd_vert: 74 | if G[v][u]['length'] < length : 75 | length = G[v][u]['length'] 76 | closest = u 77 | MST.add_edge(v, closest, length = length) 78 | odd_vert.remove(closest) 79 | 80 | 81 | 82 | 83 | def christofedes(G ,pos): 84 | opGraph=nx.DiGraph() 85 | #optimal_dist = 0 86 | MST = genMinimumSpanningTree(G) # generates minimum spanning tree of graph G, using Prim's algo 87 | odd_vert = [] #list containing vertices with odd degree 88 | for i in MST.nodes(): 89 | if MST.degree(i)%2 != 0: 90 | odd_vert.append(i) #if the degree of the vertex is odd, then append it to odd_vert list 91 | minimumWeightedMatching(MST, G, odd_vert) #adds minimum weight matching edges to MST 92 | # now MST has the Eulerian circuit 93 | start = MST.nodes()[0] 94 | visited = [False] * len(MST.nodes()) 95 | # finds the hamiltonian circuit 96 | curr = start 97 | visited[curr] = True 98 | for nd in MST.neighbors(curr): 99 | if visited[nd] == False or nd == start: 100 | next = nd 101 | break 102 | while next != start: 103 | visited[next]=True 104 | opGraph.add_edge(curr,next,length = G[curr][next]['length']) 105 | nx.draw_networkx_edges(G, pos, arrows = True, edgelist = [(curr, next)], width = 2.5, alpha = 0.6, edge_color = 'r') 106 | # optimal_dist = optimal_dist + G[curr][next]['length'] 107 | # finding the shortest Eulerian path from MST 108 | curr = next 109 | for nd in MST.neighbors(curr): 110 | if visited[nd] == False: 111 | next = nd 112 | break 113 | if next == curr: 114 | for nd in G.neighbors(curr): 115 | if visited[nd] == False: 116 | next = nd 117 | break 118 | if next == curr: 119 | next = start 120 | opGraph.add_edge(curr,next,length = G[curr][next]['length']) 121 | nx.draw_networkx_edges(G, pos, edgelist = [(curr, next)], width = 2.5, alpha = 0.6, edge_color = 'r') 122 | # optimal_dist = optimal_dist + G[curr][next]['length'] 123 | # print optimal_dist 124 | return opGraph 125 | 126 | 127 | 128 | 129 | 130 | #takes input from the file and creates a weighted undirected graph 131 | def CreateGraph(): 132 | G = nx.Graph() 133 | f = open('input.txt') 134 | n = int(f.readline()) 135 | wtMatrix = [] 136 | for i in range(n): 137 | list1 = map(int, (f.readline()).split()) 138 | wtMatrix.append(list1) 139 | #Adds egdes along with their weights to the graph 140 | for i in range(n) : 141 | for j in range(n)[i:] : 142 | if wtMatrix[i][j] > 0 : 143 | G.add_edge(i, j, length = wtMatrix[i][j]) 144 | return G 145 | 146 | def DrawGraph(G,color): 147 | pos = nx.spring_layout(G) 148 | nx.draw(G, pos, with_labels = True, edge_color = color) #with_labels=true is to show the node number in the output graph 149 | edge_labels = nx.get_edge_attributes(G,'length') 150 | nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels, font_size = 11) #prints weight on all the edges 151 | return pos 152 | 153 | 154 | #main function 155 | if __name__ == "__main__": 156 | G = CreateGraph() 157 | plt.figure(1) 158 | pos = DrawGraph(G,'black') 159 | opGraph = christofedes(G, pos) 160 | plt.figure(2) 161 | pos1 = DrawGraph(opGraph,'r') 162 | plt.show() --------------------------------------------------------------------------------