Python - Calculating Distance in Dijkstra - python

I am having some trouble in determining the distance of each node from the start node, or rather getting any information back at all.
I get no output from my function, attached in the following link.
#Values to assign to each node
class Node:
distFromSource = infinity
previous = invalid_node
visited = False
#for each node assign default values
def populateNodeTable(network):
nodeTable = []
index = 0
f = open('network.txt', 'r')
for line in f:
node = map(int, line.split(','))
nodeTable.append(Node())
print "The previous node is " ,nodeTable[index].previous
print "The distance from source is " ,nodeTable[index].distFromSource
index +=1
nodeTable[startNode].distFromSource = 0
return nodeTable
#calculate the distance of each node from the start node
def tentativeDistance(currentNode, nodeTable):
nearestNeighbour = []
for currentNode in nearestNeighbour:
currentDistance == currentNode.distFromSource + [currentNode][nearestNeighbour] #gets current distance from source
print "The current distance"
if currentDistance != 0 & currentNode.distFromSource < Node[currentNode].distFromSource:
nodeTable[currentNode].previous = currentNode
nodeTable[currentNode].length = currentDistance
nodeTable[currentNode].visited = True
nodeTable[currentNode] +=1
nearestNeighbour.append(currentNode)
for currentNode in nearestNeighbour:
print nearestNeighbour
return nearestNeighbour
My logic is, at least in my mind, correct; however, I don't get as much as an error message when the code is run.

You're setting nearestNeighbour to be an empty list, and then you're looping over it with for currentNode in nearestNeighbour -- which does nothing, because the list is empty -- and then you're returning from the function.
(I assume tentativeDistance is the function you're calling and seeing nothing from.)

You should rethink your algorithm design. Try looking up a pseudocode definition of Dijkstra's algorithm and implementing that in Python. In particular, you should think about the control flow in your program.
You might want to have a look at this cookbook recipe for a Python implementation of Dijkstra and see if you can understand it.

Related

Can my code be classified as a depth first search?

I wrote code for a DFS after reading about what it is but not actually seeing the code. I did this to challenge myself (I always have believed that to learn something new you must always first challenge yourself). The thing is after I wrote my code, I compared my implementation to the one in the book I read it in (Introduction to the Design and Analysis of Algorithms - A. Levitin) and it is completely different. So now I am wondering well it works as intended... is it still a DFS?
I made the implementation to solve a maze. I will give a rundown on my code and also upload the code here (Some people hate reading other people's code while others do.)
Algorithm (What I understood and did):
Convert maze into a graph/map
Set start position as current node and run loop in which...
I choose one of the adjacent nodes as the next current node and do this until I stumble upon a dead end. Also I am adding each node I pass through into a list that acts as my stack.
Once I am at a dead end, I keep poping items from the stack and each time I pop, I check if it has adjacent nodes that have not been visited.
Once I have found an unvisited adjacent node, we continue the entire process from step 3.
We do this until current node is the end position.
Then I just retrace my way back through the stack.
Here is my code:
# Depth First Search implementation for maze...
# from random import choice
from copy import deepcopy
import maze_builderV2 as mb
order = 10
space = ['X']+['_' for x in range(order)]+['X']
maze = [deepcopy(space) for x in range(order)]
maze.append(['X' for x in range(order+2)])
maze.insert(0, ['X' for x in range(order+2)])
finalpos = (order, order)
pos = (1, 1)
maze[pos[0]][pos[1]] = 'S' # Initializing a start position
maze[finalpos[0]][finalpos[1]] = 'O' # Initializing a end position
mb.mazebuilder(maze=maze)
def spit():
for x in maze:
print(x)
spit()
print()
mazemap = {}
def scan(): # Converts raw map/maze into a suitable datastructure.
for x in range(1, order+1):
for y in range(1, order+1):
mazemap[(x, y)] = []
t = [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
for z in t:
if maze[z[0]][z[1]] == 'X':
pass
else:
mazemap[(x, y)].append(z)
scan()
path = [pos] # stack
impossible = False
while path[-1] != finalpos:
curpos = path[-1]
i = 0
while i < len(mazemap[curpos]):
if mazemap[curpos][i] in path:
del mazemap[curpos][i]
else:
i += 1
nextpos = None
if mazemap[curpos] == []:
while nextpos == None:
try:
wrongpos = path.pop(-1)
if mazemap[wrongpos] == []:
pass
else:
path.append(wrongpos)
# nextpos = choice(mazemap[wrongpos])
nextpos = mazemap[wrongpos][-1]
mazemap[wrongpos].remove(nextpos)
except IndexError:
impossible = True
break
else:
# nextpos = choice(mazemap[curpos])
nextpos = mazemap[curpos][-1]
if impossible:
break
path.append(nextpos)
if not impossible:
for x in path:
if x == pos or x == finalpos:
pass
else:
maze[x[0]][x[1]] = 'W'
else:
print("This maze not solvable, Blyat!")
print()
spit()
As always, I greatly appreciate your suggestions!
Your algorithm looks DFS to me. DFS means exploring the path as deep as possible, backtrack to the previous node only if there is no solution and your algorithm works in a similar way by popping nodes from the stack. You just mimic the recursion stack using your own stack so it looks quite different from the standard solution.
Essentially, all recursive algorithms can be simulated using stack and loop. But most of the time doing this will make the algorithm much less readable. To tackle a difficult problem, I think the usual way to do it is to first come up with the recursive solution. After making sure the recursive solution is bug-free, then start implementing the iterative version using stack if you care a lot about the efficiency.
Other Suggestion:
if mazemap[curpos][i] in path: is a O(n) operation since path is a normal list. Consider using a separate hash set to store visited nodes and use the set to check repetition instead to make it O(1).

Linked list with two pointers trying to catch a loop

Hello I need help on detecting a loop and returning False on a linked list but first, let me explain how this linked list looks like:
This would be the node class:
class Node:
def __init__(self, next = None, stairs = None):
self.next = next
self.stairs = stairs
Since your step size doesn't change the code will, once it has visited a node twice visit it over and over again. This is due to the fact that it will make the same decisions at every node that follows the repeated node. Thus you only have to detect if (at least) one node has been visited twice. Two common ways of doing this are the following:
Count how many nodes there are in the linked list (i.e. take a new variable N=0 and increment it on every run of the first loop of the play function). Then in the second loop count how many nodes have been visited. Once that number is larger than N you know that at least one node has been visited at least twice and therefore you have detected a circle and need to break out of the loop (or return).
def play(first, step):
'''(LinkedList, int) -> bool
'''
# locates the end_node
end_list = first
found = False
# Used to find Node population
N = 0
while end_list.next != None and found != True:
if end_list.next == first:
found = True
else:
end_list = end_list.next
N = N + 1
stepcount = 1
count = 1
current = first
winner = False
loop = False
# Goes through the linked list
while current != None and winner != True and loop != True:
# If count == step, then we check if we are at the last square or
# else if we are on a stairs then we may use them.
# If none of them are found then we itterate normally making count back to 1.
# If stepcount passes the overall N (population of all the nodes), then it will detect a loop
if stepcount > N:
loop = True #one node has been visited more than once so there is a loop
elif count == step:
if current == end_list:
winner = True
elif current.stairs:
current = current.stairs
count = 0
else:
current = current.next
count = 0
stepcount = stepcount + 1
else:
current = current.next
count = count + 1
return current == end_list
Keep track of which nodes you have visited: To do this you can just add a new attribute to each node you visit (i.e. node.visited = True). At the beginning (i.e. in the initial loop) of your function play you'd want to make sure that the structure is clean, i.e. set node.visited = False. If you don't want the nodes to be changed after the function play has been called you can just delete them in another loop at the end (i.e. del node.visited).
Possibilities:
Use some sort of node or path disabling, as I suggested last time. Your posting doesn't mention why that doesn't work for you.
Count how many steps you've taken and compare against the node population (call it N). If you take n steps without reaching the end, then you're in a loop.
Try to construct a new list that contains the steps from where you start to the final node. This is a strictly linear linked list, such as START -> 3 -> 6 or START -> 1 -> 2 -> 3 ... If you try to add a node that's already in this linked list, then you have a loop.

Breaking out of the recursion in multi nested tree python

I have a multi nested tree structure and i am trying to find the current level of the provided string/node.I an using recursion to traverse the nodes and return the current level.
def dicq(self,value,current_level):
d = {}
for child in self.children:
if child.name == value:
print current_level
else:
(child.dicq(value,current_level+1))
return current_level
root.dicq('7.3',1)
root is the nested tree structure and i am giving it 7.3(The node which i am finding the level of) and 1(the default level meaning first children). If i simply print the current_level in the if statement it is correct but if i put return in the if statement it doesn't return.I want to return the current level as soon as i find the node.Any suggestions?
Right now your code is returning current_level irrespective of wheather node you are looking for is found or not.
What you need to do is to return current_level only if matching node is found. If not, return something which indicates matching node is not found. Also, you need to ensure your results propagates properly across levels of recursion and you stop looking further when a match is found.
Here is code which might help. Note: I have not tested it.
def dicq(self,value,current_level):
d = {}
retval = -1
for child in self.children:
if child.name == value:
retval = current_level
else:
retval = child.dicq(value,current_level+1)
if retval != -1:
break
return retval
If value is found, that level will be returned. If not, -1 will be returned indicating that its not found anywhere in that part of the tree.

Returning value when condition met in recursion

I am trying to find tours in a graph. I have written the following code, this seems to be printing tours correctly. I want it to stop once it have found the first tour and return the tour as a list. However, the recursion stack seems to finish to completion and I am not getting the desired result. How can I return a value and fully stop the recursion when I find the first tour i.e. my condition is met? Thanks.
def get_tour(start, graph, path):
if path==[]:
from_node=start
else:
from_node=path[-1][1]
if graph==[]:
if start in path[-1]:
print "Tour Found"
return path
else:
edges=[node for node in graph if from_node in node]
for edge in edges:
to_node=[i for i in edge if i<> from_node][0]
p=list(path)
p.append((from_node,to_node))
g=list(graph)
g.remove(edge)
get_tour(start, g,p)
g=[(1,2), (1,3), (2,3)]
get_tour(1, graph=g, path=[])
When using recursion you need to pass back the return value up to the whole call stack. Normally this isn't the best way to use recursion.
Without going in the details of your code, here is a quick suggestion:
def get_tour(start, graph, path):
ret_val = None
# Some code..
if graph==[]:
# Some code..
else:
edges=[node for node in graph if from_node in node]
for edge in edges:
# Some more code..
ret_val = get_tour(start, g,p)
if ret_val:
break
return ret_val
The reason the code continues to execute after finding the tour and returning the path is because it returns it to the call that was made within the iteration through the edges. If there is no break or return condition there then the iterations continue (and more recursive calls are followed).
Here is an amended version of your code that returns to the original call (as well as the recursive call) as soon as the conditions are satisfied, I have added some debug information to try to make the process clearer:
#!/usr/bin/python
# globals
verbose = True
def get_tour(start, graph, path):
if path==[]:
from_node=start
else:
from_node=path[-1][1]
if verbose:
print '\nfrom_node:\t', from_node
print 'start:\t', start
print 'graph:\t', graph
print 'path:\t', path
if graph==[]:
if start in path[-1]:
print "Tour Found"
return path
else:
edges=[node for node in graph if from_node in node]
for edge in edges:
to_node=[i for i in edge if i <> from_node][0]
p=list(path)
p.append((from_node,to_node))
g=list(graph)
g.remove(edge)
path = get_tour(start, g, p)
if path:
return path
g=[(1,2), (1,3), (2,3)]
get_tour(1, graph=g, path=[])

Python A* pathfinding, what is this line doing?

I am reviewing this stack overflow post
Python - Speed up an A Star Pathfinding Algorithm
I am trying to determine what the line for tile in graph[current]: represents. Namely what graph[] represents. I feel like graph should represent the entire grid, but I second guess this because we are giving current as argument to the [] operator on graph, so it has to be returning something, but im not sure what it should be. Maybe the tiles that we can travel to that are directly adjacent to current?
Also what does this syntax mean current = heapq.heappop(openHeap)[1]?
import heapq
def aStar(self, graph, current, end):
openSet = set()
openHeap = []
closedSet = set()
def retracePath(c):
path = [c]
while c.parent is not None:
c = c.parent
path.append(c)
path.reverse()
return path
openSet.add(current)
openHeap.append((0,current))
while openSet:
current = heapq.heappop(openHeap)[1]
if current == end:
return retracePath(current)
openSet.remove(current)
closedSet.add(current)
for tile in graph[current]:
if tile not in closedSet:
tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10
if tile not in openSet:
openSet.add(tile)
heapq.heappush(openHeap, (tile.H,tile))
tile.parent = current
return []
I believe the graph variable is a dict of some sort where the key is the current tile, and the value is a list of all the valid neighboring tiles. That way, every node in the graph is easily accessible via simple dict lookup.
The pseudocode on Wikipedia the author linked to in the original post supports this hypothesis -- the functionally equivalent line is listed as for each neighbor in neighbor_nodes(current)
What the line current = heapq.heappop(openHeap)[1] is doing is returning the literal tile object. If you observe the lines openHeap.append((0,current)) and heapq.heappush(openHeap, (tile.H,tile)), you can observe that the author is adding a tuple of two elements to openHeap where the first element is the heuristic, and the second element is the literal tile object.
Therefore, the line current = heapq.heappop(openHeap)[1] is identical to writing:
temp = heapq.heappop(openHeap)
current = temp[1]
...or to writting:
h, current = heapq.heappop(openHeap)
What the heaqpq.heappop() function itself is doing is returning the smallest element in the heap. Presumably, it's using the first element in the tuple to index, and so will return the open tile with the smallest heuristic as a cheap O(1) operation.

Categories

Resources