I am trying to build a very simple A* Search Algorithm in Python 3. Given the following distances for each node (considering S is the starting node and G the end one)
further_cost = {'s': 11.2, 'a': 9, 'b': 9.3, 'd': 6.2, 'c': 6.7, 'e': 4.2, 'f': 2.1, 'g': 0}
previous_cost = {'s': 0, 'a': 2, 'b': 2.5, 'c': 4, 'd': 3, 'e': 3, 'f': 2.5, 'g': 2}
I want to write a function that finds the best path based on total cost (i.e., f(n) for those familiar with the terminology) for the following search space:
sp = {'s': ['a', 'b'],
'a': ['b', 'd', 's'],
'b': ['a', 'e', 'c'],
'c': ['b'],
'd': ['s', 'a', 'e'],
'e': ['d', 'b', 'f'],
'f': ['e', 'g']}
This is what I have written so far. The issue is that I cannot seem to implement dynamic programming. In other words, I cannot make it so that the algorithm selects the path having the lower f(n).
def extend(queue, state_space):
current_path = queue[0]
current_state = current_path[-1]
extensions = state_space[current_state]
newpaths = []
for ext in extensions:
if not ext in current_path: # check for and don't add loops
newpaths.append(current_path ext)
return newpaths
def a_search(goal, state_space=sp, heuristic=further_cost, a = previous_cost, strategy='best', queue=['s']):
print (queue)
if not queue:
print('Search failed')
return False
elif queue[0][-1] == 'g':
print('Goal found with path {}'.format(queue[0]))
return True
else:
new_paths = extend(queue, state_space)
cost = {}
for path in new_paths:
cost[path] = 0
for node in path:
if node == path[-1]:
cost[path] = further_cost.get(node) previous_cost.get(node)
else:
cost[path] = previous_cost.get(node)
if strategy == 'best':
#new_queue = sorted(new_paths queue[1:], key=lambda x: cost[x[-1]])
new_queue = new_paths queue[1:]
new_queue = sorted(new_queue, key=cost.get)
print(new_queue, cost)
else:
print('Unknown search algorithm')
return False
a_search(goal, state_space, heuristic, a, strategy, new_queue)
The function returns the following error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-105-dfe3fabe38db> in <module>
----> 1 a_search(['g'], sp, further_cost, previous_cost, 'best', ['s'])
<ipython-input-104-f872f8359edc> in a_search(goal, state_space, heuristic, a, strategy, queue)
40 return False
41
---> 42 a_search(goal, state_space, heuristic, a, strategy, new_queue)
<ipython-input-104-f872f8359edc> in a_search(goal, state_space, heuristic, a, strategy, queue)
32 #new_queue = sorted(new_paths queue[1:], key=lambda x: cost[x[-1]])
33 new_queue = new_paths queue[1:]
---> 34 new_queue = sorted(new_queue, key=cost.get)
35
36 print(new_queue, cost)
TypeError: '<' not supported between instances of 'NoneType' and 'float'
I suspect I may be making some conceptual mistake here. Ay help would be appreciated!
CodePudding user response:
Apparently you have some values in your cost dictionary that are of type None
. Perhaps the previous_cost.get
call returned None
for some early value.
I might suggest a different approach. Rather than having separate collections for each piece of data used by A*, you should group them into objects. Make a node object that overrides __lt__
and pass in your f and g scores and your parent to its constructor.