def dijkstra(self, start, goal, exceptions=None): '''Dijkstra's algorithm, conceived by Dutch computer scientist Edsger Dijkstra in 1956 and published in 1959, is a graph search algorithm that solves the single-source shortest path problem for a graph with nonnegative edge path costs, producing a shortest path tree. .. note:: Unmodified, Dijkstra's algorithm searches outward in a circle from the start node until it reaches the goal. It is therefore slower than other methods like A* or Bi-directional Dijkstra's. The algorithm is included here for performance comparision against other algorithms only. .. seealso:: :func:`aStarPath`, :func:`dijkstraBi` ''' dist = {} # dictionary of final distances came_from = {} # dictionary of predecessors # nodes not yet found queue = PriorityQueue() # The set of nodes already evaluated closedset = [] queue.push(0, start) while len(queue) > 0: #log.debug("queue: " + str(queue)) weight, x = queue.pop() dist[x] = weight if x == goal: #log.debug("came_from: " + str(came_from)) path = self.reconstructPath(came_from, goal) #log.info("Path: %s" % path) return path closedset.append(x) for y in self.neighborNodes(x): if y in closedset: continue if(exceptions is not None and y in exceptions): continue costxy = self.timeBetween(x,y) if not dist.has_key(y) or dist[x] + costxy < dist[y]: dist[y] = dist[x] + costxy queue.reprioritize(dist[y], y) came_from[y] = x #log.debug("Update node %s's weight to %g" % (y, dist[y])) return None
def test_reprioritize(self): pq = PriorityQueue() for letter in range(ord('A'), ord('Z')+1): letter = chr(letter) pq.push(0, letter) pq.reprioritize(1, letter) self.assertEqual(len(pq), 26, "Incorrect length") for letter in range(ord('A'), ord('Z')+1): letter = chr(letter) pri, val = pq.pop() self.assertEqual(letter, val) self.assertEqual(pri, 1) self.assertEqual(len(pq), 0, "Incorrect length")
def aStarPath(self, start, goal, exceptions=None): '''A* is an algorithm that is used in pathfinding and graph traversal. Noted for its performance and accuracy, it enjoys widespread use. It is an extension of Edger Dijkstra's 1959 algorithm and achieves better performance (with respect to time) by using heuristics. Takes in the ``start`` node and a ``goal`` node and returns the shortest path between them as a list of nodes. Use pathCost() to find the cost of traversing the path. .. note:: Does not currently use the heuristic function, making it less efficient than the bi-directional Dijkstra's algorithm used in :func:`dijkstraBi`. .. deprecated:: 0.5 Use :func:`shortestPath` instead. .. seealso:: :func:`dijkstra`, :func:`dijkstraBi` ''' # The set of nodes already evaluated closedset = [] # The set of tentative nodes to be evaluated. openset = [start] # The map of navigated nodes. came_from = {} # Distance from start along optimal path. g_score = {start: 0} h_score = {start: self.heuristicEstimateOfDistance(start, goal)} # The estimated total distance from start to goal through y. f_score = PriorityQueue() f_score.push(h_score[start], start) while len(openset) != 0: # the node in openset having the lowest f_score[] value heur, x = f_score.pop() if x == goal: path = self.reconstructPath(came_from, goal) #log.info("Path found of weight: %g" % self.pathCost(path)) #log.info("Path: %s" % path) return path try: openset.remove(x) except ValueError as e: log.critical("Remove %s from the openset: %s" % (str(x), e)) raise closedset.append(x) for y in self.neighborNodes(x): if y in closedset: continue if(exceptions is not None and (x,y) in exceptions): costxy = float('infinity') else: costxy = self.timeBetween(x,y) tentative_g_score = g_score[x] + costxy if y not in openset: openset.append(y) tentative_is_better = True elif tentative_g_score < g_score[y]: tentative_is_better = True else: tentative_is_better = False if tentative_is_better == True: #log.debug("Update node %s's weight to %g" % (y, #tentative_g_score)) came_from[y] = x g_score[y] = tentative_g_score h_score[y] = self.heuristicEstimateOfDistance(y, goal) f_score.reprioritize(g_score[y] + h_score[y], y) return None # Failure