Modelling with Graphs
A set of algorithms on graphs
In this coursework I implemented a range of graph algorithms using Python and NetworkX.
Basic greedy colouring
This can be found in the file Part A/greedy_col_basic.py
This is designed to:
- Visit the vertices of the graph sequentially
- At every step assign in a greedy fashion the smallest possible colour
- Output the constructed colouring and the number of different colours in the colouring
For this I implemented two functions
find_smallest_color
- Given the graph and a given vertex, return the smallest colour that can be assigned
def find_smallest_color(G,i):
n = len(G.nodes())
keys = G.adj[i]
list = []
for key in keys:
list.append(G.nodes[key]['color'])
color=1
while color in list:
color += 1
return color
greedy
- Actually perform the greedy algorithm
def greedy(G):
global kmax
for i in G.nodes():
G.nodes[i]['color'] = find_smallest_color(G,i)
kmax = max(G.nodes[i]['color'] for i in G.nodes)
for i in G.nodes():
print('vertex', i, ': color', G.node[i]['color'])
print()
print('The number of colors that Greedy computed is:', kmax)
Variation on Greedy Colouring
This can be found in the file Part A/greedy_col_variation.py
Instead of visiting the nodes sequentially, this should visit the vertices such that the next visited node is adjacent to at least one visited node. Amongst the list of adjacent vertices, the smallest should be chosen. Then the rest of the algorithm will be carried out as before.
For this the function find_smallest_color
doesn't require any editing, but the function greedy
is changed to look like this
def greedy(G):
n = len(G.nodes())
global kmax
global visited_counter
G.nodes[1]['color']=1
G.nodes[1]['visited']='yes'
for i in range(1,len(G)):
next_vertex=find_next_vertex(G)
G.nodes[next_vertex]['color']=find_smallest_color(G,next_vertex)
G.nodes[next_vertex]['visited'] = 'yes'
visited = nx.get_node_attributes(G, 'color')
kmax=(max([v for k, v in visited.items()]))
print()
for i in G.nodes():
print('vertex', i, ': color', G.node[i]['color'])
print()
print('The number of colors that Greedy computed is:', kmax)
print()
This also has the newly implemented function find_next_vertex
which provides the index of the vertex to choose next
def find_next_vertex(G):
visited = nx.get_node_attributes(G, 'visited')
visited=[k for k, v in visited.items() if v=="yes"]
adjacent=set()
for item in visited:
adjacent=adjacent|(set(G.neighbors(item)))
visited=set()
for item in adjacent:
if G.nodes[item]['visited']=='yes':
visited.add(item)
adjacent-=visited
return min(adjacent)
Breadth First Search
This can be found in the file Part B/breadth_first.py
This performs a breadth first search from a given node a
to a given node b
This is implemented in just one function
def bfs(G,a,b):
G.add_nodes_from(G.nodes(), label = -1) # initialization of all labels
G.node[a]['label'] = 0
i=0
while G.node[b]['label']==-1:
vertex_list=[node for node in G.nodes() if G.node[node]['label']==i]
for u in vertex_list:
adjacent=list(G.adj[u])
for v in adjacent:
G.node[v]['label']=i+1
i+=1
return G.node[b]['label']
Depth first search
This can be found in the file Part B/depth_first_pair_nodes.py
This performs a depth first search starting from a given node a
to a given node b
At every step, among the neighbours of the currently visited vertex, the algorithm chooses the smallest one to continue the exploration from it.
In addition, it adds a label to each of the visited vertices with the path length
This is implemented with just one function
def dfs(G,a,b,u):
if a==u:
G.node[u]['label']=0
else:
G.node[u]['label']=G.node[a]['label']+1
G.node[u]['visited'] = 'yes'
print(u)
if u==b:
return
sort_list = list(G.neighbors(u))
sort_list.sort()
for v in sort_list:
if G.node[v]['visited'] == 'no':
dfs(G,u,b, v)
Diameter
The code for this can be found in the file Part B/Diameter.py
The diameter is the greatest distance between any pair of vertices in the input graph. This is implemented with the breadth first algorithm seen before, along with an additional function
def max_distance(G):
max=0
nodes=list(G.nodes())
pairs=[[i,j] for i in nodes for j in nodes]
for i in pairs:
distance=bfs(G,i[0],i[1])
if distance>max:
max=distance
return max