In [ ]:
%%HTML
<style>
.container { width:100% !important }
</style>
In [2]:
def search(start, goal, next_states):
if goal == start:
return [start]
previous = basic_search(start, goal, next_states)
if previous:
return search(start, previous, next_states) + [goal]
In [1]:
def basic_search(start, goal, next_states):
Frontier = { start }
Visited = set()
while len(Frontier) > 0:
NewFrontier = set()
for s in Frontier:
for ns in next_states(s):
if ns not in Visited and ns not in Frontier:
NewFrontier.add(ns)
if ns == goal:
return s
Visited = Frontier
Frontier = NewFrontier
print(len(Visited))
Given a state
and a parent dictionary Parent
, the function path_to
returns a path leading to the given state
.
In [ ]:
def path_to(state, Parent):
p = Parent[state]
if p == state:
return [state]
return path_to(p, Parent) + [state]
Below, we ensure that we only import graphviz
if this notebook is not loaded from another notebook. This works by checking that the variable file
is not set.
In [ ]:
try:
__file__
except NameError:
import graphviz as gv
The function $\texttt{toDot}(\texttt{source}, \texttt{Edges}, \texttt{Fringe}, \texttt{Visited})$ takes a graph that is represented by
its Edges
, a set of nodes Fringe
, and set Visited
of nodes that have already been visited.
In [ ]:
def toDot(source, goal, Edges, Frontier, Visited, Parent=None):
V = set()
for x, L in Edges.items():
V.add(x)
for y in L:
V.add(y)
dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
dot.attr(rankdir='LR', size='8,5')
for x in V:
if x == source:
dot.node(str(x), color='blue', shape='doublecircle')
elif x in Frontier and x == goal:
dot.node(str(x), label=str(x), color='magenta')
elif x in Frontier:
dot.node(str(x), label=str(x), color='red')
elif x in Visited:
dot.node(str(x), label=str(x), color='blue')
else:
dot.node(str(x), label=str(x))
if Parent:
Path = path_to(goal, Parent)
for u in V:
if Edges.get(u):
for v in Edges[u]:
if Parent and v in Path and Parent[v] == u:
dot.edge(str(u), str(v), color='brown', style='bold')
else:
dot.edge(str(u), str(v))
return dot
In [ ]:
def next_states_test(node):
x, y = node
return { (x+1, y), (x, y+1) }
In [ ]:
def create_edges(n):
Edges = {}
for row in range(n):
for col in range(n):
if (row, col) != (n-1, n-1):
Edges[(row, col)] = list(next_states_test((row, col)))
for k in range(n-1):
Edges[(k, n-1)] = [(k+1, n-1)]
Edges[(n-1, k)] = [(n-1, k+1)]
return Edges
In [ ]:
def search_show(start, goal, next_states, Edges):
Visited = set()
Frontier = { start }
Parent = { start: start }
while len(Frontier) > 0:
display(toDot(start, goal, Edges, Frontier, Visited))
NewFrontier = set()
Visited |= Frontier
for s in Frontier:
for ns in next_states(s):
if not (ns in Visited):
NewFrontier.add(ns)
Parent[ns] = s
if ns == goal:
display(toDot(start, goal, Edges, NewFrontier, Visited, Parent))
return
Frontier = NewFrontier
In [ ]:
def main(n):
Edges = create_edges(n)
search_show((0,0), (n-1,n-1), next_states_test, Edges)
In the figures shown below, the nodes in the set Visited
are colored blue, while the nodes in the set Frontier
are colored red.
In [ ]:
try:
__file__
except NameError:
main(9)
In [ ]: