Graph
Table of Contents
Vertex | Edge | |
---|---|---|
People | like each other | undirected |
People | is the boss of | directed |
Tasks | cannot be processed at the same time | undirected |
Computers | have a direct network connection | undirected |
Airports | planes flies between them | directed |
City | can travel between them | directed |
Graph search problem
Path finding problem
Shortest path problem
$$\delta(s,\upsilon) =\min_{p\in P_{s\upsilon}} c(p)$$
$\quad \;$ where $P_{s\upsilon} = \{ s \mapsto \upsilon \}$ ia s set of paths from $s$ to $\upsilon$, and $c(p)$ is length (cost) of path $p$
import networkx as nx
import matplotlib.pyplot as plt
%matplotlib inline
g = nx.Graph()
g.add_edge('a','b',weight = 0.1)
g.add_edge('b','c',weight = 1.5)
g.add_edge('a','c',weight = 1.0)
g.add_edge('c','d',weight = 2.2)
# draw a graph with nodes and edges
nx.draw(g)
plt.show()
# draw a graph with nodes' labels
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g,pos,node_size = 500) # nodes
nx.draw_networkx_edges(g,pos) # edges
nx.draw_networkx_labels(g,pos,font_size = 15,font_family = 'sans-serif') # labels
plt.axis('off')
plt.show()
# draw a graph with nodes' labels and edges' weights
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g,pos,node_size = 500) # nodes
nx.draw_networkx_edges(g,pos) # edges
nx.draw_networkx_labels(g,pos,font_size = 15,font_family = 'sans-serif') # labels
labels = nx.get_edge_attributes(g,'weight')
nx.draw_networkx_edge_labels(g,pos,edge_labels=labels)
plt.axis('off')
plt.show()
g = nx.Graph()
g.add_node(1)
g.add_node(2)
g.add_node(3)
g.add_edge(1,2)
g[1][2]['weight'] = 1
g.add_edge(1,3,weight=3)
pos = pos = nx.spring_layout(g)
nx.draw(g,pos)
nx.draw_networkx_labels(g,pos,font_size = 15,font_family = 'sans-serif')
labels = nx.get_edge_attributes(g,'weight')
nx.draw_networkx_edge_labels(g,pos,edge_labels=labels)
plt.show()
g = nx.Graph()
g.add_nodes_from([1,2,3]) # a list of nodes
g.add_edges_from([(1,2),(1,3),(2,3)]) # a list of edges
nx.draw(g)
plt.show()
g = nx.Graph()
g.add_nodes_from([1,2,3]) # a list of nodes
g.add_weighted_edges_from([(1,2,1.2),(1,3,2.1),(2,3,2.5)])
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g,pos,node_size = 500) # nodes
nx.draw_networkx_edges(g,pos) # edges
nx.draw_networkx_labels(g,pos,font_size = 15,font_family = 'sans-serif') # labels
labels = nx.get_edge_attributes(g,'weight')
nx.draw_networkx_edge_labels(g,pos,edge_labels=labels)
plt.axis('off')
plt.show()
g = nx.Graph()
g.add_nodes_from([1,2,3]) # a list of nodes
g.add_weighted_edges_from([(1,2,1.2),(1,3,2.1),(2,3,2.5)])
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g,pos,node_size = 500) # nodes
nx.draw_networkx_edges(g,pos) # edges
nx.draw_networkx_labels(g,pos,font_size = 15,font_family = 'sans-serif') # labels
labels = nx.get_edge_attributes(g,'weight')
nx.draw_networkx_edge_labels(g,pos,edge_labels=labels)
plt.axis('off')
plt.show()
print(nx.number_of_nodes(g))
print(nx.number_of_edges(g))
g.nodes()
g.edges()
g.neighbors(1)
A = nx.adjacency_matrix(g)
print(A)
print(A.todense())
import networkx as nx
import matplotlib.pyplot as plt
# construct a graph first
dg = nx.DiGraph()
dg.add_nodes_from([0,1,2,3,4])
dg.add_weighted_edges_from([(0,1,1),(0,2,4),(1,2,2),(1,4,11),(2,3,4),(2,4,8),(3,4,3)])
# plot a graph
pos = nx.spring_layout(dg)
nx.draw(dg,pos,node_size = 500)
nx.draw_networkx_labels(dg,pos,font_size = 10)
labels = nx.get_edge_attributes(dg,'weight')
nx.draw_networkx_edge_labels(dg,pos,edge_labels=labels)
plt.show()
dg.successors(0)
dg.predecessors(4)
A = nx.adjacency_matrix(dg)
A.todense()
import networkx as nx
import matplotlib.pyplot as plt
# construct a graph first
G = nx.Graph()
G.add_nodes_from([1,2,3,4,5,6,7,8])
G.add_edges_from([(1,3),(1,4),(1,5),(1,6),(1,7),(2,4),(2,5),(3,8),(5,7)])
# plot a graph
pos = nx.spring_layout(G)
nx.draw(G,pos,node_size = 500)
nx.draw_networkx_labels(G,pos,font_size = 10)
plt.show()
T = nx.dfs_tree(G,8)
nx.draw(T,pos,node_size = 500)
nx.draw_networkx_labels(T,pos,font_size = 10)
plt.show()
print(nx.dfs_successors(G,8))
T = nx.bfs_tree(G,8)
nx.draw(T,pos,node_size = 500)
nx.draw_networkx_labels(T,pos,font_size = 10)
plt.show()
print(nx.bfs_successors(G,8))
# plot a graph
pos = nx.spring_layout(G)
nx.draw(G,pos,node_size = 500)
nx.draw_networkx_labels(G,pos,font_size = 10)
plt.show()
paths = nx.all_simple_paths(G, source=2, target=8)
print(list(paths))
import networkx as nx
import matplotlib.pyplot as plt
# construct a graph first
G = nx.Graph()
G.add_nodes_from([0,1,2,3,4])
G.add_weighted_edges_from([(0,1,1),(0,2,4),(1,2,2),(1,4,11),(2,3,4),(2,4,8),(3,4,3)])
# plot a graph with weights displayed
pos = nx.spring_layout(G)
labels = nx.get_edge_attributes(G,'weight')
nx.draw(G,pos,node_size = 500)
nx.draw_networkx_labels(G,pos,font_size = 10)
nx.draw_networkx_edge_labels(G,pos,edge_labels=labels)
plt.show()
# find the shortest path in a graph
print(nx.shortest_path(G,0,4,weight = 'weight'))
# Q: stack
def Graph_Search_DFS(graph, s):
Q = [s]
marked = []
while Q:
v = Q.pop()
if v not in marked:
marked.append(v)
for w in graph[v]:
if w not in marked:
Q.append(w)
return marked
# Q: queue
def Graph_Search_BFS(graph, s):
Q = [s]
marked = []
while Q:
v = Q.pop(0)
if v not in marked:
marked.append(v)
for w in graph[v]:
if w not in marked:
Q.append(w)
return marked
Adj = {
0: [1, 5],
1: [0, 2],
2: [1, 3, 5, 6],
3: [2, 6],
4: [5],
5: [0, 2, 4],
6: [2, 3]
}
print(Graph_Search_DFS(Adj, 0))
print(Graph_Search_BFS(Adj, 0))
# will be used to get reverse path from label
def get_path(v, label, p):
p.append(v)
if label[v] == -1:
return p
else:
p = get_path(label[v], label, p)
return p
def Find_Path(graph, s, t):
label = [-1]*len(graph)
if s in [t]:
return s
Q = [s]
marked = []
while Q:
v = Q.pop()
if v not in marked:
marked.append(v)
if v in [t]:
return get_path(v, label, [])
for w in graph[v]:
if w not in marked:
label[w] = v
Q.append(w)
return
Adj = {
0: [1, 5],
1: [0, 2],
2: [1, 3, 5, 6],
3: [2, 6],
4: [5],
5: [0, 2, 4],
6: [2, 3]
}
path = Find_Path(Adj, 0, 3)
print(path)
# Reverse path (= backtracking)
path = path[::-1]
print(path)
$$\delta(s,\upsilon) =\min_{p\in P_{s\upsilon}} c(p)$$
$\quad \;$ where $P_{s\upsilon} = \{ s \mapsto \upsilon \}$ ia s set of paths from $s$ to $\upsilon$, and $c(p)$ is length (cost) of path $p$
Dijkstra's algorithm
Basic idea:
Initially $\rho[\upsilon] = \infty$ for all nodes. Starting with $s$, mark nodes as Graph-Search. When a node $\upsilon$ is newly marked. For each node $\omega \in Q$ updata $\rho[\omega]$ with
When all nodes reachable from $s$ are marked, $\forall \upsilon \in V, \;\rho[\upsilon] = \delta(s,\upsilon)\quad$ ($\rho[\upsilon]= \infty$ if $\upsilon$ is not reachable from $s$)
# example of priority queue
import queue
Q = queue.PriorityQueue()
Q.put(5)
Q.put(1)
Q.put(4)
print(Q.queue)
print(Q.get())
print(Q.get())
# example of priority queue, \rho[v]=min_{u \in Q} \rho[u]
q = queue.PriorityQueue()
q.put([1, 5])
q.put([4, 3])
q.put([0, 6])
print(q.get()[1])
rho = [float('inf')]*7
rho[2] = 0
print(rho)
def Dijkstra(graph, s, t):
label = [-1]*len(graph)
rho = [float('inf')]*len(graph)
rho[s] = 0
Q = queue.PriorityQueue()
Q.put([rho[s], s])
marked = []
while Q:
v = Q.get()[1]
if v not in marked:
marked.append(v)
if v in [t]:
return get_path(v, label, [])
for w in graph[v].keys():
if w not in marked:
rho[w] = min(rho[w], rho[v] + graph[v][w])
if rho[w] == rho[v] + graph[v][w]:
label[w] = v
Q.put([rho[w], w])
return
# define graph with weights
Adj = {
0: {1:2, 2:1},
1: {2:3, 3:3},
2: {4:1},
3: {5:2},
4: {3:2, 5:5},
5: {},
}
# get adjacent nodes
print(Adj[2])
print(Adj[2].keys())
# get distance or weight from 2 to 4
print(Adj[2][4])
path = Dijkstra(Adj, 0, 5)
print(path)
# Reverse path (backtracking)
path = path[::-1]
print(path)
%%html
<center><iframe width="560" height="315" src="https://www.youtube.com/embed/bbf8YCRvAHE?rel=0"
width="560" height="315" frameborder="0" allowfullscreen></iframe></center>
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')