├── 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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
36 |
37 | Visualization of the result :
38 |
39 | Here, the red colored nodes denote the centers.
40 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
68 |
69 | Step 1:
70 |
71 | A minimum spanning tree MST is obtained from the given grapg G (using Kruskal's algorithm)
72 |
73 | 
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 | 
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 | 
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()
--------------------------------------------------------------------------------