I am attempting to find any Hamiltonian paths in a given grid, which contains obstacles at various nodes. My issue is that my code has been running for days now and has yet to come to an end. While this problem is in the NP-Complete region, from what I am seeing I am not sure that a lack of enough time is my issue.
My approach has been, in python, to use recursion to perform a Depth First Search through all of the possible orders of left, right, up, and down movements that could be made through the grid. I have researched other methods to Hamiltonian path problems, but they were more complicated for what I have done and I did not think a small grid would need them
The following is the grid I am searching. 0 is an open node, 1 is an obstacle, and S is the start.
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,1,0,0,1,0,1,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,S]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
Here is an example output of the running function's current grid, with the 1s now also representing visited nodes.
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1]
[1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1]
However, even at approximately 50000 steps per second, the code never seems to stop examining the bottom right corner. For example, the two 0s at nodes (3,1) and (3,2) have never been reached.
So this leaves me with some questions: Is this just a standard symptom of NP-Hard, even though I am only attempting a 13x9 grid? Am I reaching a python recursion limit, causing my code to endlessly rerun the same DFS branches? Or is there something else I am missing?
This is a simplified version of my search method:
#examines options of steps at current marker cell and iterates path attempts
def tryStep():
global path #list of grid movements
global marker #current cell in examination
set marker to traveled
if whole grid is Traveled:
print path data
end program
#map is incomplete, advance a step
else:
if can move Up:
repeat tryStep()
if can move left:
repeat tryStep()
if can move down:
repeat tryStep()
if can move right:
repeat tryStep()
#Failure condition reached, must backup a step
set marker cell to untraveled
if length of path is 0:
print 'no path exists'
end program
last = path.pop()
if last == "up":
move marker cell down
if last == "left":
move marker cell right
if last == "down":
move marker cell up
if last == "right":
move marker cell left
return
Therefore, the code should iterate through all possible paths through the grid, until one forms a Hamiltonian path. For reference here is my actual code I am running:
'''
Created on Aug 30, 2014
@author: Owner
'''
#Search given grid for hamiltonian path
import datetime
#takes grid cord and returns value
def getVal(x,y):
global mapWidth
global mapHeight
global mapOccupancy
if (((x < mapWidth) and (x >-1)) and (y < mapHeight and y >-1)):
return mapOccupancy[y][x]
else:
#print "cell not in map"
return 1
return
#sets given coord cell value to visted
def travVal(x,y):
global mapWidth
global mapHeight
global mapOccupancy
if (((x < mapWidth) and (x >-1)) and ((y < mapHeight) and (y >-1)))== True:
mapOccupancy[y][x] = 1
else:
#print "cell not in map"
return 1
return
#sets given coord cell value to open
def clearVal(x,y):
if (((x < mapWidth) and (x > -1)) and ((y < mapHeight) and (y > -1)))==True:
mapOccupancy[y][x] = 0
else:
#print "cell not in map"
return 1
return
#checks if entire map has been traveled
def mapTraveled():
isFull = False
endLoop= False
complete = True
for row in mapOccupancy:
if endLoop ==True:
isFull = False
complete = False
break
for cell in row:
if cell == 0:
complete = False
endLoop = True
break
if complete == True:
isFull = True
return isFull
#examines options of steps at current marker cell and iterates path attempts
def tryStep():
global path
global marker
global goalCell
global timeEnd
global timeStart
global printCount
travVal(marker[0],marker[1])
printCount += 1
#only print current map Occupancy every 100000 steps
if printCount >= 100000:
printCount = 0
print ''
print marker
for row in mapOccupancy:
print row
if mapTraveled():
print 'map complete'
print "path found"
print marker
print path
for row in mapOccupancy:
print row
print timeStart
timeEnd= datetime.datetime.now()
print timeEnd
while True:
a=5
#if map is incomplete, advance a step
else:
#Upwards
if getVal(marker[0],marker[1]-1) == 0:
marker = [marker[0],marker[1]-1]
#print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('up')
tryStep()
#left wards
if getVal(marker[0]-1,marker[1]) == 0:
marker = [marker[0]-1,marker[1]]
#print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('left')
tryStep()
# down wards
if getVal(marker[0],marker[1]+1) == 0:
marker = [marker[0],marker[1]+1]
#print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('down')
tryStep()
#right wards
if getVal(marker[0]+1,marker[1]) == 0:
marker = [marker[0]+1,marker[1]]
# print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('right')
tryStep()
#Failure condition reached, must backup steps
clearVal(m[0],m[1])
last = path.pop()
#print 'backing a step from:'
#print last
if last == "up":
marker = [marker[0],marker[1]+1]
if last == "left":
marker = [marker[0]+1,marker[1]]
if last == "down":
marker = [marker[0],marker[1]-1]
if last == "right":
marker = [marker[0]-1,marker[1]]
return
if __name__ == '__main__':
global timeStart
timeStart = datetime.datetime.now()
print timeStart
global timeEnd
timeEnd= datetime.datetime.now()
global printCount
printCount = 0
global mapHeight
mapHeight = 9
global mapWidth
mapWidth =13
#occupancy grid setup
r0= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r1= [0,0,0,0,0,0,1,0,0,0,0,0,0]
r2= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r3= [0,0,0,1,0,0, 1 ,0,1,0,0,0,0]
r4= [0,0,0,0,0,0,0,0,0,0,0,0, 0]
r5= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r6= [0,0,0,0,0,0,1,0,0,0,0,0,0]
r7= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r8= [0,0,0,0,0,0,0,0,0,0,0,0,0]
global mapOccupancy
mapOccupancy = [r0,r1,r2,r3,r4,r5,r6,r7,r8]
#record of current trail attempt
global path
path = []
#marker for iterating through grid
global marker
start = [12,4]
#start =[0,2]
m = start
global goalCell
goalCell = [6,3]
print marker
tryStep()
#no path avalible if this point is reached
print'destination is unreachable'
print 'last path: '
for row in mapOccupancy:
print row
print path
print m
print mapOccupancy
print timeStart
timeEnd= datetime.datetime.now()
print timeEnd