Bidirectional BFS in Python Implementation - python

I am implementing a bidirectional BFS for a 2d maze problem in Python 3.7.3.
Firstly, here is how I create the maze:
for row in range(dim):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(dim):
grid[row].append(np.random.binomial(1, 0.2, 1)) # Append a cell
if (row == column == dim - 1):
grid[row][column] = 0
grid[0][0] = 0
Now, in order to facilitate the bidirectional BFS, I defined a junct class which is essentially a node which stores both a parent junct from the starting direction and a parent junct from the goal direction.
class junct():
def __init__(self, row, column, parent_S, parent_G):
self.row = row
self.column = column
self.parent_S = parent_S
self.parent_G = parent_G
def __eq__(self, other):
return (self.row == other.row and self.column == other.column)
Here is my bidirectional bfs function. It is part of an Agent class which has not given me any issues so far. I want this function to return a list of tuples (row, column) of all the nodes in the path from the start to the goal.
def bidirectional_bfs(self):
def get_value(maze, a, b):
return maze[a][b]
def is_out_of_bounds(a, b, d):
return (a < 0 or a >= dim) or (b < 0 or b >= d)
grid = self.grid
dim = len(grid)
Q_start = []
Q_goal = []
visited = []
start = junct(0, 0, None, None)
goal = junct(dim-1, dim-1, None, None)
Q_start.append(start)
Q_goal.append(goal)
visited.append(start)
visited.append(goal)
#beginning loop
while (len(Q_start) > 0) and (len(Q_goal) > 0):
#initializations
current_S = Q_start[0]
current_G = Q_goal[0]
row_S = current_S.row
column_S = current_S.column
row_G = current_G.row
column_G = current_G.column
#some mechanics
if len(Q_start) > 0:
Q_start.pop(0)
if len(Q_goal) > 0:
Q_goal.pop(0)
#in case the current node from starting is in the goal Queue
if (current_S in Q_goal):
#forming the path back to G
current = current_S
path_S = [current]
while current.parent_S is not None:
path_S.append(current.parent_S)
current = current.parent_S
path_S = [(item.row, item.column) for item in path_S]
print(path_S)
#in case the current node from goal is in the start Queue
if (current_G in Q_start):
#forming the path back to S
current = current_G
path_G = [currrent]
while current.parent_S is not None:
path_G.append(current.parent_G)
current = current.parent_G
path_G = [(item.row, item.column) for item in path_G]
print(path_G)
if (current_S in Q_goal) and (current_G in Q_start):
path = [item for item in path_G for item in path_S]
print(path)
return path
#enqueueing children from the start direction
children_S = [junct(row_S+1, column_S, current_S, None), junct(row_S-1, column_S, current_S, None), junct(row_S, column_S+1, current_S, None), junct(row_S, column_S-1, current_S, None)]
for child in children_S:
if not is_out_of_bounds(child.row, child.column, dim):
if child not in visited:
if get_value(grid, child.row, child.column) == 0:
Q_start.append(child)
visited.append(child)
#enqueueing childen from the goal direction
#enqueueing children from the start direction
children_G = [junct(row_G+1, column_G, None, current_G), junct(row_G-1, column_G, None, current_G), junct(row_G, column_G+1, None, current_G), junct(row_G, column_G-1, None, current_G)]
for child in children_S:
if not is_out_of_bounds(child.row, child.column, dim):
if child not in visited:
if get_value(grid, child.row, child.column) == 0:
Q_goal.append(child)
visited.append(child)
return []
print("No path")
Where am I going wrong in my code? What needs to be changed in order to return the path?

Related

maximum heap priority queue python

For school i have to make an assignment -->
"The city of Amsterdam wants to store the maximum values of the past few years for research
purposes. It is important that the current maximum measured value can be accessed very quickly.
One idea to fulfill this requirement is to use a priority queue. Your job is to implement a priority
queue with a maximum heap and return again a tuple of the current maximal measurement and
its corresponding date when the maximum occurred. Output: date,covid level"
The program takes as input:
(string)’yyyy-mm-dd’, (int)sensor id, (int)covid level.
The expected output is: yyyy-mm-dd,covid level.
Input: 2022−09−08, 23, 371; 2022−09−08, 2, 3171; 2022−09−08, 12, 43; 2021−03−21, 4, 129
Output: 2022 −09 −08, 3171
I have provided my code below. When creating a max heap, the max element should be the first element (root). A Max-Heap is a complete binary tree in which the value in each internal node is greater than or equal to the values in the children of that node, though when inserting the tuples the nodes do not get sorted. My output is very strange, i do not understand where it comes from. When putting in the above input, this is my output:
1.1.1977, 9223372036854775807
could somebody help me? what piece of code am i missing, i have gone over it so many times.
import sys
class MaxHeap:
def __init__(self, maxsize):
self.maxsize = maxsize
self.size = 0
self.Heap = [0] * (self.maxsize + 1)
self.Heap[0] = ('1.1.1977', sys.maxsize)
self.FRONT = 1
# Function to return the position of
# parent for the node currently
# at pos
def parent(self, pos):
return pos // 2
# Function to return the position of
# the left child for the node currently
# at pos
def leftChild(self, pos):
return 2 * pos
# Function to return the position of
# the right child for the node currently
# at pos
def rightChild(self, pos):
return (2 * pos) + 1
# Function that returns true if the passed
# node is a leaf node
def isLeaf(self, pos):
if pos >= (self.size // 2) and pos <= self.size:
return True
return False
# Function to swap two nodes of the heap
def swap(self, fpos, spos):
self.Heap[fpos], self.Heap[spos] = (self.Heap[spos],
self.Heap[fpos])
# Function to heapify the node at pos
def maxHeapify(self, pos):
if not self.isLeaf(pos):
if (self.Heap[pos] < self.Heap[self.leftChild(pos)] or
self.Heap[pos] < self.Heap[self.rightChild(pos)]):
if (self.Heap[self.leftChild(pos)] >
self.Heap[self.rightChild(pos)]):
self.swap(pos, self.leftChild(pos))
self.maxHeapify(self.leftChild(pos))
else:
self.swap(pos, self.rightChild(pos))
self.maxHeapify(self.rightChild(pos))
# Function to insert a node into the heap
def insert(self, element):
if self.size >= self.maxsize:
return
self.size += 1
self.Heap[self.size] = element
current = self.size
while (self.Heap[current] >
self.Heap[self.parent(current)]):
self.swap(current, self.parent(current))
current = self.parent(current)
# Function to print the contents of the heap
def Print(self):
for i in range(1, (self.size // 2) + 1):
print(i)
print("PARENT : " + str(self.Heap[i]) +
"LEFT CHILD : " + str(self.Heap[2 * i]) +
"RIGHT CHILD : " + str(self.Heap[2 * i + 1]))
# Function to remove and return the maximum
# element from the heap
def extractMax(self):
extraction = self.Heap[self.FRONT]
self.Heap[self.FRONT] = self.Heap[self.size]
self.size -= 1
self.maxHeapify(self.FRONT)
return extraction
# Driver Code
if __name__ == "__main__":
input = input()
input = input.split(";")
dates = []
values = []
for d in input:
date = d.split(',', 2)
dates.append(date[0])
values.append(date[2])
values = [int(x) for x in values]
tuples = list(zip(dates, values))
heap = MaxHeap(len(tuples) + 1)
# print(tuples)
for t in tuples:
heap.insert(t)
print(t)
print(heap.extractMax())

A* Search for Maze - Infinite Loop When Path does not Exist - Python

I am trying to implement an A-star search algorithm to find a path in a square maze from (0,0) to (dimension - 1, dimension - 1). My algorithm returns the correct path when it exists; however, if there is no path, then it runs in an infinite loop. How do I fix this? For now, I've put a condition to run if the length of the open list exceeds (dimension ^ 4), but this is obviously not a permanent fix. I am using Python 3.7.3.
import numpy as np
class node():
def __init__(self, parent=None, location=None):
self.parent = parent
self.location = location
self.g = float(0)
self.h = float(0)
self.f = float(0)
#returns euclidean distance between two nodes
#takes the locations/tuples of two nodes as arguments
#works properly
def euclidean_distance(node_1, node_2):
return float((((node_2[1] - node_1[1])**2) + ((node_2[0] - node_1[0])**2))**0.5)
#to make extracting the value at a given location in the maze easier
#takes the maze and two integers as arguments
def get_value(maze, a, b):
return maze[a][b]
def out_of_bounds(a, b, dim):
return (a < 0 or a >= dim) or (b < 0 or b >= dim)
#Euclidean A* Search, takes the maze and dimension as arguments
def a_star_euclidean(maze, dim):
#initializing start node and end node
start = node(None, (0,0))
end = node(None, (dim-1, dim-1))
#initializing open list and closed list
open_list = []
closed_list = []
open_list.append(start)
while len(open_list) > 0:
#assigning currentNode
currentNode = open_list[0]
currentNode_index = 0
#current location
for index, item in enumerate(open_list):
if item.f < currentNode.f:
currentNode = item
currentNode_index = index
#(currentNode.location)
row = currentNode.location[0]
column = currentNode.location[1]
#updating open list and closed list
open_list.pop(currentNode_index)
closed_list.append(currentNode)
#in case goal node is already reached
if currentNode.location == end.location:
path = []
current = currentNode
while current is not None:
path.append(current.location)
current = current.parent
#return path[::-1] #returning the path from start to end
path.reverse()
return path
else:
closed_list.append(currentNode)
#generating childs
child_locations = [(row+1, column), (row-1, column), (row, column+1), (row, column-1)]
#print(child_locations)
child_nodes = [node(currentNode, location) for location in child_locations]
#print(child_nodes)
for child in child_nodes:
#declaring row and column variables for child nodes
child_row = int(child.location[0])
child_column = int(child.location[1])
if not out_of_bounds(child_row, child_column, dim):
# Child is on the closed list
if child in open_list:
continue
#computing g(n), h(n), f(n)
child.g = float(currentNode.g + 1)
child.h = float(euclidean_distance(child.location, end.location))
child.f = float(child.g + child.h)
#child is in open list
if child in closed_list:
continue
if get_value(maze, child_row, child_column) == 0:
open_list.append(child)
else:
continue
else:
continue
#if (len(open_list) > dim**4): #b^d worst case
#return None
def main():
maze = []
dim = int(input("Enter the dimension of the game: "))
print(dim)
for row in range(dim):
maze.append([])
for column in range(dim):
maze[row].append(int(np.random.binomial(1, 0.3, 1)))
maze[0][0] = 0
maze[dim-1][dim-1] = 0
print(maze)
print("----------")
print(a_star_euclidean(maze,dim))
#print(euclidean_distance((1,1), (2,2)))
main()
I believe the issue is that child in closed_list is never true, because you haven't overriden the __eq__ operator of the node class. Because of this, python doesn't know how to compare two instances of the node class, so falls back to comparing if they are references to the same object in memory, otherwise it returns false. So two nodes are never equal when searching through closed_list.
Try defining the __eq__ operator for the node class like so. You can change the comparison to include other properties as you need.
class node():
def __init__(self, parent=None, location=None):
self.parent = parent
self.location = location
self.g = float(0)
self.h = float(0)
self.f = float(0)
def __eq__(self, other):
return self.location == other.location

Python Trees: Modifying a tree

This is my python code to make an Ordered Binary Decision Diagram (not very relevant for the context). So I just have a tree of a particular height, and I need to set some of the leaf nodes to one. So I have a variable path which involves an array of "decisions", to go left or right from that particular node. But my code is by mistake modifying multiple roots. I am fairly new to Python and I used to rely on pointers when I used C.
def makeCubes(arr):
ans = []
for ar in arr:
ar2 = [ar[i:i + 2] for i in range(0, len(ar), 2)]
#splitting into segments of 2 each
if not '00' in ar2:
ans += [ar2]
return ans
class Node:
def __init__(self,key):
self.key = key
self.left = None
self.right = None
def addLeft(self,node):
self.left = node
def addRight(self,node):
self.right = node
def makeTree(size):
if(size == 1):
leaf = Node('x0')
leaf.addLeft(Node('zero'))
leaf.addRight(Node('zero'))
return leaf
else:
node = Node('x'+str(size-1))
childNode = makeTree(size-1)
node.addLeft(childNode)
node.addRight(childNode)
return node
def inOrder(root):
if(root != None):
return inOrder(root.left) + [root.key] + inOrder(root.right)
return []
def makeOBDD(array):
maxLen = max([len(word) for word in array])
tree = makeTree(maxLen)
for cube in array:
tree = makeOne(tree,cube)
return tree
def makeOne(root,cube):
print("cube",cube)
if(cube == []):
print("updated")
root.key = 'one'
else:
element = cube[0]
if(element == '01'):
root.addLeft(makeOne(root.left,cube[1:]))
elif(element == '10'):
root.addRight(makeOne(root.right,cube[1:]))
return root
# ab + a'b'
'''
Expected output
x1
/ \
x0 x0
/ \ / \
1 0 0 1
'''
cubeSet = ['1010','0101']
cubes = makeCubes(cubeSet)
print(cubes)
obdd = makeOBDD(cubes)
print(inOrder(obdd))

Inserting into n-child tree in Python

I am trying to implement a tree for the travelling salesperson problem. My particular tree has 5 destinations which are fully connected to each other.
One of the destinations is guaranteed to always be the starting destination and that you are only allowed to visit each destination once with the exception of the starting destination which you have to return to (ie if you have [1,2,3,4,5] with 1 the starting destination, a possible sequence of moves would be 1-3-5-2-4-1)
I tried implementing a tree in python with the following code (I brute forced it since I know the maximum depth is going to be 5).
class Node(object):
def __init__(self,value, city, children = [None, None, None, None]):
self.value = value
self.city = city
self.children = children
class Tree(object):
def __init__(self):
self.root = None
def insert(self,value,city):
newNode = Node(value,city)
if self.root is None:
self.root = newNode
else:
self._insert(1, newNode)
def _insert(self,depth, newNode):
if depth is 1:
for x in range(0,4):
if self.root.children[x] is None:
self.root.children[x] = newNode
return
elif self.root.children[3] is not None:
self._insert(2, newNode)
return
if depth is 2:
for x in range(0,4):
for y in range(0,3):
if self.root.children[x].children[y] is None:
self.root.children[x].children[y] = newNode
return
elif self.root.children[3].children[2] is not None:
self._insert(3, newNode)
return
if depth is 3:
for w in range(0,4):
for x in range(0,3):
for y in range(0,2):
if self.root.children[w].children[x].children[y] is None:
self.root.children[w].children[x].children[y] = newNode
return
elif self.root.children[3].children[2].children[1] is not None:
self._insert(4,newNode)
return
if depth is 4:
for w in range(0,4):
for x in range(0,3):
for y in range(0,2):
for z in range(0,1):
if self.root.children[w].children[x].children[y].children[z] is None:
self.root.children[w].children[x].children[y].children[z] = newNode
return
elif self.root.children[3].children[2].children[1].children[0] is not None:
self._insert(5,newNode)
return
if depth is 5:
for w in range(0,4):
for x in range(0,3):
for y in range(0,2):
for z in range(0,1):
for u in range(0,1):
if self.root.children[w].children[x].children[y].children[z].children[u] is None:
self.root.children[w].children[x].children[y].children[z].children[u] = newNode
return
elif self.root.children[3].children[2].children[1].children[0].children[0] is not None and w is 3 and x is 2 and y is 1 and z is 0 and u is 0:
print "The table is full"
def delete(self):
self.root = None
x = Tree()
x.insert(0, "Pretoria")
x.insert(60, "Johannesburg")
x.insert(1200, "Cape Town")
x.insert (600, "Durban")
x.insert(400, "Bloemfontein")
x.insert(1400, "Port Elizabeth")
My root and first level populate correctly but all the children nodes of the second, third, fourth and fifth level all populate exactly the same as the first level. When I checked their memory, they all populated the exact same memory space and I have no idea why. This happens when the following line of code runs:
x.insert(1400, "Port Elizabeth")
The tree for some reason is fully populated at this point despite only having 5 entries.
I tried using pointers at first but the same issue crops up.
Long story short, how would one go about inserting into an n-ary tree with decreasing n as you increase in depth?
This particular tree has the following attributes:
Root: 4 children per node (1 node with 4 children)
Level 1: 3 children per node (4 nodes with 3 children)
Level 2: 2 children per node (12 nodes with 2 children)
level 3: 1 child per node (24 nodes with 1 child)
level 4: 1 child per node (24 nodes with 1 child) (this is final destination in the TSP)

Parsing a tree using python

I have to make a program that parses a tree represented using a set parenthesis and numbers. So each parenthesis represent node in a tree and the program is supposed to print out all the children nodes for each parent node. The python code is as follows:
class context(object):
def __init__(self, label=None, parent=None, children=[]):
self.label = label
self.parent = parent
self.children = []
self.list = []
def make_tree(self, tree):
stack = []
index = 0
while index < len(tree):
if tree[index] is '(':
if self.label is None:
self.label = tree[index+1]
index = index+1
else:
if len(stack) == 0:
stack.append(context(tree[index+1], self.label))
index = index+1
else:
stack.append(context(tree[index+1], stack[len(stack)-1].label))
index = index+1
elif tree[index] is ')':
if len(stack) == 1:
self.children.append(stack.pop())
return
else:
stack[len(stack)-2].children.append(stack.pop())
index = index+1
def traverse(self, size, obj):
if self.label is None or size == 0:
return []
temp_list = []
temp = []
dic = {}
tt = [children.label for children in obj.children]
dic[obj.label] = tt
temp.append(dic)
for child in obj.children:
temp_list = child.traverse(len(child.children), child)
print temp
return temp + temp_list
line = '( Root ( 1 ( 2 ) ( 3 ( 4 ) ( 5 ) ) ( 6 ( 7 ) ( 8 ( 9 ) ) ) ) ) '.split()
test = context()
test.make_tree(line)
final = test.traverse(len(test.children), test)
The result have to be this.
If I print out the list in the make_tree function, I get correct result... But the final result is not correct. In this case, I am missing {'3':['4','5']}
Any comment??
I just looked at some of your code. It didn't have much time so I couldn't have really debugged it way more but you can also implement by having tmpList in the way belong and basically keep updating at every point. Alko's solution works as well, but this might be a bit more clear.
def traverse(self, size, obj, tmpList):
if self.label is None or size == 0:
return []
dic = {}
tt = [children.label for children in obj.children]
dic[obj.label] = tt
tmpList.append(dic)
for child in obj.children:
child.traverse(len(child.children), child, tmpList)
return tmpList
You call this by:
final = test.traverse(len(test.children), test, [])
You overwrite child results with assignment to temp_list, you probably want instead do:
for child in obj.children:
temp_list += child.traverse(len(child.children), child)

Categories