I am trying to implement breadth first search - python

I am trying to have a program that allows the user to click on a vertex to choose the start vertex and hover over a vertex to choose the end_vertex. Then the program uses breadth first search to choose a path. I haven't been able to create the path because whenever I choose both vertices, I get a none type. Please help.
from collections import deque
from load_graph import load_graph
vertex_dict = load_graph("graph.txt")
def bfs(start, goal):
backpointers = {}
path = []
q = deque()
q.append(start)
backpointers[start] = None
while len(q) >= 1:
x = q.popleft()
if x == goal:
path.append(goal)
while backpointers[x] != None:
print(backpointers)
path.append(backpointers[x])
x = backpointers[x]
return path
else:
for vertex in x.get_adjacent():
vertex = vertex_dict[vertex.strip()]
if vertex not in backpointers:
backpointers[vertex] = x
q.append(vertex)
print(len(x.get_adjacent()))
I am positive that the issue it here because It returns a none-type and when I put a bunch of print statements, it got stuck in the else portion.
This is what it looks likes
Vertex Class:
from cs1lib import *
class Vertex:
def __init__(self, name, adjacent, x, y):
self.name = name
self.adjacent = adjacent.split(",")
self.adjacentSTR = adjacent
self.x = int(x)
self.y = int(y)
self.r = 10
self.distance = None
self.is_red = False
def __str__(self):
return self.name+"; "+"Adjencent Vertices: "+self.adjacentSTR+" Location: "+str(self.x)+", "+ str(self.y)
def get_x(self):
return self.x
def set_distance(self, d):
self.distance = d
def get_vertex(self):
return self
def get_y(self):
return self.y
def get_adjacent(self):
return self.adjacent
def link(self, vertex, r, g, b):
set_fill_color(r, g, b)
set_stroke_width(2)
set_stroke_color(r, g, b)
draw_line(self.x, self.y, vertex.get_x(), vertex.get_y())
def draw(self, r, g, b):
set_fill_color(r, g, b)
set_stroke_width(1)
draw_circle(self.x, self.y, self.r)
def mouse_is_nearby(self, mx, my):
if mx <= self.x + self.r and mx >= self.x - self.r and my <= self.y + self.r and my >= self.y - self.r:
# print("close to: " +self.name)
return True

Try this:
from collections import deque
def path(back_links, goal):
path = [goal]
node = goal
while back_links[node] is not None:
node = back_links[node]
path = [node] + path
return path
def bfs(start, goal):
q = deque([start])
visited, back_links = set([]), {start.name: None}
while q:
node = q.popleft()
visited.add(node.name)
if node.name == goal.name:
return path(back_links, goal.name)
for neighbor in node.get_adjacent():
if neighbor.name in visited:
continue
q.append(neighbor)
back_links[neighbor.name] = node.name
return []

Related

A* algorithm TypeError: cannot unpack non-iterable int object

This is the python code which uses A* algorithm for finding solution for 8 puzzle problems, I got some error messages, how can I fix it?(The error message is under the code)
There are several object-oriented programming concepts for Problems class, Node class that are implemented to express the problem solution search that you need to understand in order to make the Python program complete. The priority queue is to make the nodes to be explored to be sorted according to their f-evaluation function score and return the min one as the first node to be searched next.
There is also a memorize function to memorize the heuristic value of state as a look-up table so that you don’t need to calculate the redundant computing of heuristic estimation value, so you can ignore it at this point if you don’t understand.
The components you need to implement is to make the abstract part of the program realizable for 8 -puzzle with the successor methods attached to a problem class which consists of initial state and goal state. Make sure the program can run correctly to generate the solution sequence that move the empty tile so that the 8-puzzle can move "Up", "Down", "Left", "Right", from initial state to goal state.
import math
infinity = math.inf
from itertools import chain
import numpy as np
import bisect
class memoize:
def __init__(self, f, memo={}):
self.f = f
self.memo = {}
def __call__(self, *args):
if not str(args) in self.memo:
self.memo[str(args)] = self.f(*args)
return self.memo[str(args)]
def coordinate(state):
index_state = {}
index = [[0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2]]
for i in range(len(state)):
index_state[state[i]] = index[i]
return index_state
def getInvCount(arr):
inv_count = 0
empty_value = -1
for i in range(0, 9):
for j in range(i + 1, 9):
if arr[j] != empty_value and arr[i] != empty_value and arr[i] > arr[j]:
inv_count += 1
return inv_count
def isSolvable(puzzle) :
inv_count = getInvCount([j for sub in puzzle for j in sub])
return (inv_count % 2 == 0)
def linear(state):
return sum([1 if state[i] != goal[i] else 0 for i in range(9)])
#memoize
def manhattan(state):
index_goal = coordinate(goal)
index_state = coordinate(state)
mhd = 0
for i in range(9):
for j in range(2):
mhd = abs(index_goal[i][j] - index_state[i][j]) + mhd
return mhd
#memoize
def sqrt_manhattan(state):
index_goal = coordinate(goal)
index_state = coordinate(state)
mhd = 0
for i in range(9):
for j in range(2):
mhd = (index_goal[i][j] - index_state[i][j])**2 + mhd
return math.sqrt(mhd)
#memoize
def max_heuristic(state):
score1 = manhattan(state)
score2 = linear(state)
return max(score1, score2)
class PriorityQueueElmt:
def __init__(self,val,e):
self.val = val
self.e = e
def __lt__(self,other):
return self.val < other.val
def value(self):
return self.val
def elem(self):
return self.e
class Queue:
def __init__(self):
pass
def extend(self, items):
for item in items: self.append(item)
class PriorityQueue(Queue):
def __init__(self, order=min, f=None):
self.A=[]
self.order=order
self.f=f
def append(self, item):
queueElmt = PriorityQueueElmt(self.f(item),item)
bisect.insort(self.A, queueElmt)
def __len__(self):
return len(self.A)
def pop(self):
if self.order == min:
return self.A.pop(0).elem()
else:
return self.A.pop().elem()
# Heuristics for 8 Puzzle Problem
class Problem:
def __init__(self, initial, goal=None):
self.initial = initial; self.goal = goal
def successor(self, state):
reachable = []
def get_key(val):
for key, value in index_state.items():
if val == value:
return key
return -1
def candidate(state, Position):
state = state.copy()
zero_index = state.index(0)
swap_index = state.index(get_key(Position))
state[zero_index], state[swap_index] = state[swap_index], state[zero_index]
return state
index_state = coordinate(state)
zero_position = index_state[0]
move_pair = {"left":[zero_position[0], zero_position[1] - 1],
"right":[zero_position[0], zero_position[1] + 1],
"up":[zero_position[0] - 1, zero_position[1]],
"down":[zero_position[0] + 1, zero_position[1]]
}
for action, position in move_pair.items():
#print(action, position)
if get_key(position) != -1:
reachable.append((action, candidate(state, position)))
#print(reachable)
return reachable
def goal_test(self, state):
return state == self.goal
def path_cost(self, c, state1, action, state2):
return c + 1
def value(self):
abstract
class Node:
def __init__(self, state, parent=None, action=None, path_cost=0, depth =0):
self.parent = parent
if parent:
self.depth = parent.depth + 1
else:
self.depth = 0
self.path_cost = path_cost
self.state = state
if action:
self.action = action
else: self.action = "init"
def __repr__(self):
return "Node state:\n " + str(np.array(self.state).reshape(3,3)) +"\n -> action: " + self.action + "\n -> depth: " + str(self.depth)
def path(self):
x, result = self, [self]
while x.parent:
result.append(x.parent)
x = x.parent
return result
def expand(self, problem):
for (act,n) in problem.successor(self.state):
if n not in [node.state for node in self.path()]:
yield Node(n, self, act,
problem.path_cost(self.path_cost, self.state, act, n))
def graph_search(problem, fringe):
closed = {}
fringe.append(Node(problem.initial,depth=0))
while fringe:
node = fringe.pop()
if problem.goal_test(node.state):
return node
if str(node.state) not in closed:
closed[str(node.state)] = True
fringe.extend(node.expand(problem))
return None
def best_first_graph_search(problem, f):
return graph_search(problem, PriorityQueue(min, f))
def astar_search(problem, h = None):
h = h or problem.h
def f(n):
return max(getattr(n, 'f', -infinity), n.path_cost + h(n.state))
return best_first_graph_search(problem, f)
def print_path(path, method):
print("*" * 30)
print("\nPath: (%s distance)" % method)
for i in range(len(path)-1, -1, -1):
print("-" * 15)
print(path[i])
goal = [1, 2, 3, 4, 5, 6, 7, 8, 0]
# Solving the puzzle
puzzle = [7, 2, 4, 5, 0, 6, 8, 3, 1]
if(isSolvable(np.array(puzzle).reshape(3,3))): # even true
# checks whether the initialized configuration is solvable or not
print("Solvable!")
problem = Problem(puzzle,goal)
path = astar_search(problem, manhattan).path()
print_path(path, "manhattan")
path = astar_search(problem, linear).path()
print_path(path, "linear")
path = astar_search(problem, sqrt_manhattan).path()
print_path(path, "sqrt_manhattan")
path = astar_search(problem, max_heuristic).path()
print_path(path, "max_heuristic")
else :
print("Not Solvable!") # non-even false
TypeError Traceback (most recent call last)
<ipython-input-124-2a60ddc8c009> in <module>
9 problem = Problem(puzzle,goal)
10
---> 11 path = astar_search(problem, manhattan).path()
12 print_path(path, "manhattan")
13
<ipython-input-123-caa97275712e> in astar_search(problem, h)
18 def f(n):
19 return max(getattr(n, 'f', -infinity), n.path_cost + h(n.state))
---> 20 return best_first_graph_search(problem, f)
21
22 def print_path(path, method):
<ipython-input-123-caa97275712e> in best_first_graph_search(problem, f)
12
13 def best_first_graph_search(problem, f):
---> 14 return graph_search(problem, PriorityQueue(min, f))
15
16 def astar_search(problem, h = None):
<ipython-input-123-caa97275712e> in graph_search(problem, fringe)
8 if str(node.state) not in closed:
9 closed[str(node.state)] = True
---> 10 fringe.extend(node.expand(problem))
11 return None
12
<ipython-input-121-e5a968bd54f0> in extend(self, items)
18
19 def extend(self, items):
---> 20 for item in items: self.append(item)
21
22 class PriorityQueue(Queue):
<ipython-input-122-db21613469b9> in expand(self, problem)
69
70 def expand(self, problem):
---> 71 for (act,n) in problem.successor(self.state):
72 if n not in [node.state for node in self.path()]:
73 yield Node(n, self, act,
TypeError: cannot unpack non-iterable int object
I got some error messages, how can I fix it?
There is one error message, The pieces of codes you get in the error message are the stack trace, which might help you to know how the execution got at the final point where the error occurred. In this case that is not so important. The essence of the error is this:
for (act,n) in problem.successor(self.state)
TypeError: cannot unpack non-iterable int object
So this means that the successor method returned an int instead of a list.
Looking at the code for successor, I notice that it intends to return a list called reachable, but there is a return statement right in the middle of the code, leaving the largest part of that code unexecuted (so-called "dead code"):
return state
This statement makes no sense where it is positioned. It seems to be an indentation problem: that return belongs inside the function just above it, like this:
def candidate(state, Position):
state = state.copy()
zero_index = state.index(0)
swap_index = state.index(get_key(Position))
state[zero_index], state[swap_index] = state[swap_index], state[zero_index]
return state # <-- indentation!

How to find all path of a graph

Update
Thanks to the comments of some community members, I realize that there are some similar problems, but they may a bit different, please allow me to explain it further.
I actually hope to use the same method in a real problem, So briefly:
Reuse of edges in differernt path is completely allowed
a unique(or a new) path from A to B is defined as a collection of vertices that have any different vertices.
Let me use a quiz from Python data structure and algorithm analysis by Bradley .N Miller and David L. Ranum to expain my qusetion.
Quesion:
Consider the task of converting the word FOOL to SAGE, also called word ladder problem. In solving
In the word ladder problem, only one letter must be replaced at a time, and the result of each step must be a word, not non-existent.
Input:
FOUL
FOOL
FOIL
FAIL
COOL
FALL
POOL
PALL
POLL
POLE
PALE
PAGE
SALE
POPE
POPE
SAGE
We can easily find the path from FOOL to SAGE, as Bradley showed:
enter image description here
and I used Breadth First Search (BFS) to solve probem:
class Vertex:
def __init__(self, key, value = None):
self.id = key
self.connectedTo = {}
self.color = 'white'
self.dist = sys.maxsize
self.pred = []
self.disc = 0
self.fin = 0
self.value = value,
#self.GraphBulided = False
self.traverseIndex = 0
self.predNum = 0
def addNeighbor(self, nbr, weight=0):
self.connectedTo[nbr] = weight
def __str__(self):
return '{} connectedTo: {}'.format(self.id, \
str([x.id for x in self.connectedTo]))
def setColor(self, color):
self.color = color
def setDistance(self, d):
self.dist = d
#I want store all Pred for next traverse so I use a list to do it
def setPred(self, p, list = False):
if not list:
self.pred = p
else:
self.pred.append(p)
self.predNum += 1
def setDiscovery(self,dtime):
self.disc = dtime
def setFinish(self,ftime):
self.fin = ftime
#def setGraphBulided(self, tag = True):
# self.GraphBulided = tag
def getFinish(self):
return self.fin
def getDiscovery(self):
return self.disc
def getPred(self):
if isinstance(self.pred, list):
if self.traverseIndex < self.predNum:
return self.pred[self.traverseIndex]
else:
return self.pred[-1]
else:
return self.pred
def __hash__(self):
return hash(self.id)
def getPredById(self):
if self.traverseIndex < self.predNum and isinstance(self.pred, list):
pred = self.pred[self.traverseIndex]
self.traverseIndex += 1
print("vertix {}: {} of {} preds".format(self.id, self.traverseIndex, self.predNum))
return [pred, self.traverseIndex]
else:
pred = None
return [pred, None]
def getCurrPredStaus(self):
#if not self.pred:
# return None
return self.predNum - self.traverseIndex
def getDistance(self):
return self.dist
def getColor(self):
return self.color
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self, nbr):
return self.connectedTo[nbr]
def getValue(self):
return self.value
def findPath(self, dest):
pass
class Graph:
def __init__(self):
self.vertList = {}
self.numVertics = 0
self.verticsInSerach = set()
self.GraphBulided = False
def addVertex(self, key, value = None):
self.numVertics = self.numVertics + 1
newVertex = Vertex(key, value=value)
self.vertList[key] = newVertex
return newVertex
def getVertex(self, n):
if n in self.vertList:
return self.vertList[n]
else:
return None
def __contains__(self, n):
return n in self.vertList
def addEdge(self, f, t, cost = 0, fvalue = None, tvalue = None):
if f not in self.vertList:
nv = self.addVertex(f, fvalue)
if t not in self.vertList:
nv = self.addVertex(t, tvalue)
self.vertList[f].addNeighbor(self.vertList[t], cost)
def setGraphBulided(self, tag = True):
self.GraphBulided = tag
def getVertices(self):
return self.vertList.keys()
def setGraphBulided(self, tag = True):
self.GraphBulided = tag
def setSerachedVertixs(self, vertix):
self.verticsInSerach.add(vertix)
def getGraphBulided(self):
return self.GraphBulided
def getSerachedVertixs(self):
return self.verticsInSerach
def __iter__(self):
return iter(self.vertList.values())
def __hash__(self):
hashIds = [x for x in self.getVertices()]
if len(hashIds) > 0 and hashIds[0]:
return hash(', '.join(hashIds))
else:
return None
Here are some additional functions for building graphs
def buildGraph(wordFile, DFSgraph = False):
d = {}
g = Graph()
if DFSgraph:
g = DFSGraph()
wfile = open(wordFile)
for line in wfile:
word = line[:-1]
for i in range(len(word)):
bucket = word[:i] + '_' + word[i+1:]
if bucket in d:
d[bucket].append(word)
else:
d[bucket] = [word]
for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1, word2)
wfile.close()
return g
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
def bfs(g, start, listpred = False):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while (vertQueue.size() > 0):
currentVert = vertQueue.dequeue()
if currentVert.getConnections():
g.setSerachedVertixs(currentVert)
for nbr in currentVert.getConnections():
#print('sreach {}'.format(currentVert.getId()))
if (nbr.getColor() == 'white' or nbr.getColor() == 'gray'):
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance() + 1)
if nbr.predNum > 0 and currentVert.getId() not in [x.getId() for x in nbr.pred]:
nbr.setPred(currentVert, listpred)
elif nbr.predNum == 0:
nbr.setPred(currentVert, listpred)
vertQueue.enqueue(nbr)
currentVert.setColor('black')
Therefore, we can easily find the shortest path we need (If we only store one pred for one vertix).
wordGraph = buildGraph('fourletterwords1.txt', DFSgraph=False)
bfs(wordGraph, wordGraph.getVertex('FOOL'), listpred=True)
def traverse(y):
x=y
while(x.getPred()):
print(x.getPred())
x = x.getPred()
print(x.getId())
traverse(wordGraph.getVertex('SAGE'))
However, I still don't know how to trace all the paths correctly, can you give me some suggestions?
FIND path from src to dst ( Dijkstra algorithm )
ADD path to list of paths
LOOP P over list of paths
LOOP V over vertices in P
IF V == src OR V == dst
CONTINUE to next V
COPY graph to working graph
REMOVE V from working graph
FIND path from src to dst in working graph( Dijkstra algorithm )
IF path found
IF path not in list of paths
ADD path to list of paths

Why are the elements in my heapq not ordered python?

I am using a simple heapq in python with custom elements on which I implemented the lt function.
class Edge:
def __init__(self, cost, u, v):
self.u = u
self.v = v
self.cost = cost
def weight(self):
w = self.cost
v = self.v
while v.parent is not None:
w += v.const
v = v.parent
return w
def __lt__(self, other):
return self.weight() < other.weight()
Then I keep a heap of these elements in another array called P:
class Vertex:
def __init__(self, node=None):
#other stuff omited #####
self.P = []
def add_incoming_nodes(self, subgraph):
for node, costs in subgraph.items():
#if costs[self.vertex] is not 0: #node is not self
#push endpoints of the edge from another vertex to this vertex
heapq.heappush(self.P, Edge(costs[self.vertex], node, self))
The problem is that when I heappop an element, I would expect it to be the smallest element in my array right ? But this assertion here fails
#select arbitrary vertex
a = all_nodes[0]
while a.P: #while P[a] is not ∅
edge = heapq.heappop(a.P)
for a_edge in a.P:
assert edge.weight() < a_edge.weight()

Create a picklable Python class

I am trying to create some custom Python classes for my application. When I try to debug my code I can not pick the instances of my custom classes, I receive the error "Object XXX is not picklable".
I found this page https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled but I don't understand how I should implement the methods that make my class picklable.
For example how would you modify the following classes so that I can pick instances of them?
class Point3D:
def __init__ (self, x, y, z):
self.x = x
self.y = y
self.z = z
def move(self, vector):
self.x += vector.x
self.y += vector.y
self.z += vector.z
return
def isValidPoint(self):
isNotValid = False
isNotValid = math.isnan(self.x) or math.isnan(self.y) or math.isnan(self.z)
return not isNotValid
And
class PointCloud3D:
def __init__ (self):
self.points = []
def getNumberOfPoints(self):
return len(self.points)
def addPoint(self, point):
self.points.append(point)
return
def addPointCloud3D(self, additionalPointCloud3D):
for self.point in additionalPointCloud3D:
self.addPoint(point)
def getCloudCenter(self):
numberOfPoints = self.getNumberOfPoints()
centersSumX = 0
centersSumY = 0
centersSumZ = 0
for point in self.points:
centersSumX = centersSumX + point.x
centersSumY = centersSumY + point.y
centersSumZ = centersSumZ + point.z
centerX = centersSumX/numberOfPoints
centerY = centersSumY/numberOfPoints
centerZ = centersSumZ/numberOfPoints
center = Point3D(float(centerX), float(centerY) , float(centerZ))
return center
While here you can find the code that I am trying to debug:
from classDatabase import Point3D, PointCloud3D
testPoint1 = Point3D(1.5, 0.2, 2.3)
testPoint2 = Point3D(3.5, 1.2, 5.3)
testPointCloud3D = PointCloud3D()
testPointCloud3D.addPoint(testPoint1)
testPointCloud3D.addPoint(testPoint2)
Finally a screenshot of the issue:

How to give start,end coordinates

I'm new to qgis and in here I want to find a path between two selected points on the map(Roads-vector layer). The points are selected by the user, using mouse clicks.
So here I used the astar algorithm to find path between two points.
*******************************astar.py**********************************
import heapq
class AStar(object):
def __init__(self, graphAstar):
self.graphAstar = graphAstar
def heuristic(self, node, start, end):
raise NotImplementedError
def search(self, start, end):
openset = set()
closedset = set()
current = start
openHeap = []
openset.add(current)
openHeap.append((0,current))
while openset:
temp = heapq.heappop(openHeap)
current = temp[1]
if current == end:
path = []
while current.parent:
path.append(current)
current = current.parent
path.append(current)
return path[::-1]
openset.remove(current)
closedset.add(current)
for node in self.graphAstar[current]:
if node in closedset:
continue
if node in openset:
new_g = current.gg + current.move_cost(node)
if node.gg > new_g:
node.gg = new_g
node.parent = current
else:
node.gg = current.gg + current.move_cost(node)
node.H = self.heuristic(node, start, end)
node.parent = current
openset.add(node)
heapq.heappush(openHeap, (node.H,node))
return None
class AStarNode(object):
def __init__(self):
self.gg = 0
self.H = 0
self.parent = None
def move_cost(self, other):
raise NotImplementedError
*****************************astar_grid.py*******************************
from astar import AStar, AStarNode
from math import sqrt
class AStarGrid(AStar):
def heuristic(self, node, start, end):
return sqrt((end.x - node.x)**2 + (end.y - node.y)**2)
class AStarGridNode(AStarNode):
def __init__(self, x, y):
self.x, self.y = x, y
super(AStarGridNode, self).__init__()
def move_cost(self, other):
diagonal = abs(self.x - other.x) == 1 and abs(self.y - other.y) == 1
return 14 if diagonal else 10
and in the main code, the following method is used to create graph from vector layer.
**************************plugin.py**********************************
def make_graph(self, mapinfo):
nodes = [[AStarGridNode(x, y) for y in range(mapinfo['height'])] for x in range(mapinfo['width'])]
graphAstar = {}
for x, y in product(range(mapinfo['width']), range(mapinfo['height'])):
node = nodes[x][y]
graphAstar[node] = []
for i, j in product([-1, 0, 1], [-1, 0, 1]):
if not (0 <= x + i < mapinfo['width']): continue
if not (0 <= y + j < mapinfo['height']): continue
graphAstar[nodes[x][y]].append(nodes[x+i][y+j])
return graphAstar, nodes
And I called that method in FindRoutes method..
def findRoutes(self):
vl=self.canvas.currentLayer()
director = QgsLineVectorLayerDirector( vl, -1, '', '', '', 3 )
properter = QgsDistanceArcProperter()
director.addProperter( properter )
crs = self.canvas.mapRenderer().destinationCrs()
builder = QgsGraphBuilder( crs )
global x1
global y1
global x2
global y2
pStart = QgsPoint( x1, y1 )
pStop = QgsPoint( x2, y2 )
graphAstar, nodes = self.make_graph({ "width": 8, "height": 8 })
paths = AStarGrid(graphAstar)
start, end = ??
path = paths.search(start, end)
My question is, how to pass the start and end coordinates to the function above? Because passing them just as coordinates (start, end = pStart, pStop) does not work.
How do add them to the graph created as nodes?
Or is there any easy way to do it?
Please help me to to find a solution to this problem.
Thank You
When i do an astar, the node i use are intern of the astar and contain a reference vers the original point object (your tuple of position).
Maybe it's the same with your AStarGridNode ?
In your case :
start = AStarGridNode(x1, y1)
stop = AStarGridNode(x2, y2)
This part could be in the your search function to hide this from the user.

Categories

Resources