"""
|
|
:Author: James Sherratt
|
|
:Date: 20/10/2019
|
|
:License: MIT
|
|
|
|
:name: graph.py
|
|
"""
|
|
|
|
|
|
class Graph:
|
|
|
|
def __init__(self):
|
|
self.vertices = set()
|
|
self.edges = set()
|
|
|
|
def add_vertex(self, vert):
|
|
"""
|
|
Add a vertex to the graph.
|
|
|
|
:param vert: name of the vertex.
|
|
:return: None
|
|
"""
|
|
self.vertices.add(vert)
|
|
|
|
def add_edge(self, vert1, vert2, directional=False):
|
|
"""
|
|
Add an edge to the graph. The edge will be defined as a simple tuple where:
|
|
- The first value is the initial edge.
|
|
- The second is the final edge.
|
|
- The third is whether the edge is directional.
|
|
|
|
:param vert1: the start vertex.
|
|
:param vert2: the end vertex.
|
|
:param directional: whether or not the edge has a direction. Default: False
|
|
:return: None
|
|
"""
|
|
self.vertices.add(vert1)
|
|
self.vertices.add(vert2)
|
|
if (not directional) and (vert1 > vert2):
|
|
# swap if not directional to avoid duplicates in the set.
|
|
self.edges.add((vert2, vert1, directional))
|
|
else:
|
|
self.edges.add((vert1, vert2, directional))
|
|
|
|
def adjacency(self, vert1, vert2):
|
|
"""
|
|
Check if 2 vertices are adjacent (if they exist). Note: if vert1 and vert2
|
|
are connected, but directionally from vert2 to vert1, False is returned.
|
|
|
|
:param vert1: The first vertex to compare.
|
|
:param vert2: The second vertex to compare.
|
|
:return: True if adjacent, False if not, None if either are not in the set.
|
|
"""
|
|
if (vert1 not in self.vertices) or (vert2 not in self.vertices):
|
|
return None
|
|
|
|
for edge in self.edges:
|
|
if (vert1 == edge[0]) and (vert2 == edge[1]):
|
|
return True
|
|
if (not edge[2]) and ((vert1 == edge[1]) and (vert2 == edge[0])):
|
|
return True
|
|
return False
|
|
|
|
def neighbours(self, vert):
|
|
"""
|
|
Get the neighbours of a vertex.
|
|
:param vert: name of the vertex.
|
|
:return: list of neighbours, or None if the vertex is not in the graph.
|
|
"""
|
|
if vert not in self.vertices:
|
|
return None
|
|
|
|
neighbours = set()
|
|
for edge in self.edges:
|
|
if vert == edge[0]:
|
|
neighbours.add(edge[1])
|
|
elif (not edge[2]) and (vert == edge[1]):
|
|
neighbours.add(edge[0])
|
|
return neighbours
|
|
|
|
def as_dict(self):
|
|
"""
|
|
Convert the graph to a dictionary where:
|
|
- Each key is a vertex.
|
|
- Each value is a set of neighbours you can travel to.
|
|
|
|
:return: dict representing the graph.
|
|
"""
|
|
graph_dict = {v: set() for v in self.vertices}
|
|
for edge in self.edges:
|
|
graph_dict[edge[0]].add(edge[1])
|
|
if not edge[2]:
|
|
graph_dict[edge[1]].add(edge[0])
|
|
|
|
return graph_dict
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mygraph = Graph()
|
|
mygraph.add_edge("a", "b")
|
|
mygraph.add_edge("b", "c")
|
|
mygraph.add_edge("b", "d")
|
|
mygraph.add_edge("c", "b")
|
|
mygraph.add_edge("a", "e", directional=True)
|
|
mygraph.add_vertex("z")
|
|
print("b neighbours:", mygraph.neighbours("b"))
|
|
print("a neighbours:", mygraph.neighbours("a"))
|
|
print("q neighbours:", mygraph.neighbours("q"))
|
|
print("e neighbours:", mygraph.neighbours("e"))
|
|
print()
|
|
# Adjacency has direction.
|
|
print("a and e adjacent:", mygraph.adjacency("a", "e"))
|
|
print("e and a adjacent:", mygraph.adjacency("e", "a"))
|
|
print("d and b adjacent", mygraph.adjacency("d", "b"))
|
|
print("q and a adjacent:", mygraph.adjacency("q", "a"))
|
|
print("z and a adjacent:", mygraph.adjacency("z", "a"))
|
|
print()
|
|
print("as dict")
|
|
print(mygraph.as_dict())
|
|
|
|
# Exercise/ project: add a method "path" to find path between 2 vertices.
|
|
# (Hint: lookup DFS/ BFS algorithm.)
|