TypeError:unorderable类型:Node()<节点()

时间:2015-11-17 18:40:22

标签: python search tile

在Python中,我正在实现用于解决平铺问题的A *搜索算法。 我有以下Node类,它将状态保存为元组的元组。例如,初始状态是:

storage: :s3,
s3_credentials: Proc.new{|a| a.instance.s3_credentials }

def s3_credentials
  {bucket: "foo/bar", access_key_id: ENV["access_key_id"], secret_access_key: ENV["secret_access_key"]}
end

以下是Node类

initial= ((7,2,4),(5,0,6),(8,3,1));#empty tile is marked with value 0

我还有一个TileProblem类,它包含将由A *使用的启发式,如下所示,

class Node:
    def __init__(self, state, parent=None, action=None, pathCost=0, emptyTileI=1,emptyTileJ=1):
        self.state = state
        self.parent = parent
        self.action = action
        self.pathCost = pathCost
        self.emptyTileI=emptyTileI;#row index of empty tile
        self.emptyTileJ=emptyTileJ;#column index of empty tile
    def expand(self, problem):
        children=[];#empty list of children nodes initially.
        #after doing some work....
        return children #a list of Node objects, one for each successor states, parent of the created nodes is self
    def getState(self):
        return self.state;
    def getPathCost(self):
        return self.pathCost;
    def getParent(self):
        return self.parent;

优先级队列类如下,

## very generic Problem superclass, subclasses can overwrite the goal test and the constructor, and should also add a successors function
class Problem:
    def __init__(self, initial, goal=None):
        self.initial = initial
        self.goal = goal
    def goalTest(self, state):
        return state == self.goal

class TileProblem(Problem):
    def __init__(self, initial, goal=None):
        self.initial = initial
        self.goal = goal
    #used in priority queue
    "(Uses Accumulated Manhattan Distance heuristic)"
    def fAMD(self,element):
        return self.g(element)+self.hAMD(element)
    "(Uses Number of Misplaced Tiles heuristic)"
    def fMT(self,element):
        return self.g(element)+self.hMT(element)

    #backward cost. #When this function is executed, the parent of the element has been already updated (by expand function in parent Node)
    def g(self,element):
        return element.pathCost
    #forward cost 
    "(Accumulated Manhattan Distance heuristic)"
    def hAMD(self,element):
        goalState=self.goal
        elementState=element.getState()
        "We will calculate the accumulated Manhattan distance between goal state and element state"
        accumulatedSum=0;
        for i,tgoal in enumerate(goalState):
            for j,vGoal in enumerate(tgoal):
                for m, tElement in enumerate(elementState):
                    for n, vElement in enumerate(tElement):
                        if vGoal==vElement:
                            accumulatedSum=accumulatedSum + abs(i-m)+abs(j-n);#Manhattan distance

        return accumulatedSum

    #forward cost 
    "(Number of Misplaced Tiles heuristic)"
    def hMT(self,element):
        goalState=self.goal
        elementState=element.getState()
        "We will calculate the number of misplaced tiles between goal state and element state"
        misplacedTileSum=0;
        for m, tElement in enumerate(elementState):
            for n, vElement in enumerate(tElement):
                if(vElement!=goalState[m][n]):
                    misplacedTileSum=misplacedTileSum+1;
        return misplacedTileSum;

我的A *算法,

class PriorityQueue:
    def __init__(self, f):
        self.f = f ## save the function for later, when we apply it to incoming items (nodes)
        self.q = []#defaultdict(list)
        self.maximal_size=0
    def push(self, item):
        insort(self.q, (self.f(item), item))
        self.updateMaximalSize();
    def pop(self):
        return self.q.pop(0)[1]
    def empty(self):
        return self.q==[];
    def getMaximalSize(self):
        return self.maximal_size
    def updateMaximalSize(self):
        if(len(self.q)>self.maximal_size):
            self.maximal_size=len(self.q)
    def getF(self):
        return self.f;
   # def printQ(self):
    #    for t in self.q:
     #       print("("+repr(t[0])+","+repr(t[1].getState())+")");

    #returns the priority value of an element if it exists or None otherwise
    #Needed in A* to judge whether to push an element to the queue or not by comparing its current priority to the updated one
    def getPriorityValue(self,item):
        for e in self.q:
            if e[1].getState()==item.getState():
                return e[0];
        return None

    #updates the priority value of an element in the queue. Needed in A* to decrease the priority value of an element
    def updatePriorityValue(self,item):
        self.q = [(v,i) if (i.getState() != item.getState()) else (self.f(item),item) for (v, i) in self.q]
        self.updateMaximalSize();

最后,在我的主要内容

def aStarSearch(problem,frontier):
    closed=[];#explored set
    frontier.push(Node(problem.initial))
    print("In A* Search, Popping The Following Nodes (States) in-order:")
    while not frontier.empty():
        node=frontier.pop();
        print(node.getState()), #printing the history of popped nodes(states)
        closed.append(node.getState()); # add it to closed state to prevent processing it again
        if problem.goalTest(node.getState()): #if this is a goal node
            return node; #just return it
        children=node.expand(problem); #otherwise, lets expand it
        for c in children: #looping over the children
            if(c.getState() in closed): #already popped from the queue and closed
                continue; #ignore it
            priorityValue=frontier.getPriorityValue(c); #the child priority value in the queue
            if(priorityValue==None): #not in the queue
                frontier.push(c) #add it to the queue
            elif (frontier.getF(c) < priorityValue): #in the queue but this is a better path
                frontier.updatePriorityValue(c); #decrease the priority in the queue
        #frontier.printQ();        
    return None;

当我运行代码时,出现以下错误:

initial= ((7,2,4),(5,0,6),(8,3,1));#empty tile is marked with value 0
goal=((1,2,3),(4,5,6),(7,8,0));

"A* Graph Search using Accumulated Manhattan Distance heuristic"
print("A* Graph Search using Accumulated Manhattan Distance heuristic:")
tileAStarSearch = TileProblem(initial,goal); 
frontier= PriorityQueue(tileAStarSearch.fAMD); #accumulated Manhattan distance heuristic
aStarResult=aStarSearch(tileAStarSearch, frontier);

我不明白这个问题的原因。为什么insort会关心这些物品。我只希望它推动项目并按照&#34;优先级排序&#34;在我的情况下,这是一个整数(累计的曼哈顿距离)。我怎么解决这个问题?感谢。

1 个答案:

答案 0 :(得分:9)

队列中的节点具有相同的优先级。然后Python尝试通过比较节点来命令(priority, node)元组。这是因为元组在字典顺序中进行比较,就像你对名字进行排序一样。使用两个名称,如果第一个字母匹配,则比较第二个字母等,直到您有不同的字母并可以对它们进行排序,比较元组的工作方式相同。如果优先级匹配,则比较节点。

使节点可订购(您可以使用functools.total_ordering() decorator__eq____lt__方法)或将计数器值插入优先级队列元组以打破平局:< / p>

# at the top
from itertools import count

class PriorityQueue:
    def __init__(self, f):
        self.f = f ## save the function for later, when we apply it to incoming items (nodes)
        self.q = []#defaultdict(list)
        self.maximal_size=0
        self._counter = count()
    def push(self, item):
        insort(self.q, (self.f(item), next(self._counter), item))
        self.updateMaximalSize()

并更新PriorityQueue()类的其余部分以查找索引2处的项目(或者更好的是,在索引-1处)。更新updatePriorityValue()方法中的列表解析,将队列项解压缩到(v, c, i),并将其再次包含在左侧表达式中。

计数器(由itertools.count()生成)插入一个不断增加的整数,因此永远不会有两个(priority, counter, item)元组,其中优先级和计数器都相等;因此,这些项目永远不会被比较。

这意味着,对于相同的优先级,以后插入的项目将赢得平局。如果您希望先前插入 的项目获胜,请使用-next(self._counter)