Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand this priority queue depth-first search?

The following is pseudocode implement depth-first search(DFS) with one stack and a large table to mark visited nodes:

DFS(N0):
   StackInit(S)
   S.push((N0, null))
   if isGoal(N0) then do
      return true
   markVisited(N0)
   S.push((null, N0))
   while !isEmpty(S) then do
      (N, parent) := S.pop()
      R := next((N, parent))
      if isNull(R) then do
         continue             // So no new node add to this layer.
      S.push((R, parent))
      if marked(R) then do
         continue
      if isGoal(R) then do    // If it's goal don't have to explore it.
         return true
      markVisited(R)
      if depthMax((R, parent)) then do
         continue
      S.push((null, R))
   return false

The problem I want to solve is a modification from it: it substitutes the stack S with PriorityQueue PQ. This algorithm is used to simulate IDA* algorithm (this is stated in a textbook, which unfortunately not written in English, so I won't provide reference / book title):


DFS2(N0, f, LIMIT):
   PriorityQueueInit(PQ)
   // A node (N, parent) stored in PQ represents a path from `N0` to `N`\
        passing the node `parent`; A node with smaller value on f() is \
        prioritized than those with larger value.
   PQ.push((N0, null))
   if isGoal(N0) then do
      return true
   markVisited(N0)
   PQ.push((null, N0))
   while !isEmpty(PQ) then do     // (1)
      (N, parent) := PQ.poll()
      R := next((N, parent))      // (2)
      if isNull(R) then do
         continue
      PQ.offer((R, parent))
      if marked(R) then do
         continue
      if isGoal(R) then do
         return true
      markVisited(R)
      if f((R, parent)) > LIMIT then do
         continue
      PQ.offer((null, R))
   return false
  • (1): In A* algorithm, a priority queue is used to store nodes which haven't been explored, i.e. open list. While in the first DFS pseudocode I provided, the stack S is close list, so I assume that in the second pseudocode PQ is close list, too. So how can the second pseudocode simulate IDA* algorithm, with a close list?
  • (2): It fetch the current smallest node from PQ, which is probably not a sibling of node N, i.e. It jumps to another subtree from current subtree contains N. What's the purpose of this line?

Can anyone show me the correctness of the second algorithm, i.e. why it can be used in IDA* algorithm?


updated for more information: I have spent many time and effort on this question, but it seems to be very hard because of the following points:

  1. All graphs appear in the textbook are drawn tree-like, i.e. only one parent for each node, to show the concepts. This makes me confused: Does the second algorithm only work for trees?

  2. Considering the line

    if f((R, parent)) > LIMIT then do ...
    

    If the second one also works for graph, not just tree, then there might be many parents go to R, should I consider all cases or just the current one, parent?

like image 395
Rainning Avatar asked Dec 24 '20 03:12

Rainning


People also ask

What is priority queue explain with example?

An ascending order priority queue gives the highest priority to the lower number in that queue. For example, you have six numbers in the priority queue that are 4, 8, 12, 45, 35, 20. Firstly, you will arrange these numbers in ascending order. The new list is as follows: 4, 8, 12, 20.

Can we use queue in depth-first search?

DFS stands for Depth First Search. 2. BFS(Breadth First Search) uses Queue data structure for finding the shortest path. DFS(Depth First Search) uses Stack data structure.

What is depth-first search used for?

Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. The algorithm starts at the root node (selecting some arbitrary node as the root node in the case of a graph) and explores as far as possible along each branch before backtracking.

What is the difference between priority queue and dequeuing?

When a data element is enqueued into the priority queue, it is given a priority number. In contrast with dequeuing of a standard queue, data elements with a high priority are dequeued before data elements with a low priority.

What is a high priority queue in Java?

Priority Queue | Set 1 (Introduction) 1 Every item has a priority associated with it. 2 An element with high priority is dequeued before an element with low priority. 3 If two elements have the same priority, they are served according to their order in the queue.

What is the complexity of depth first search?

This type of algorithm prioritizes the processing of leaves before roots in case a goal lies at the end of a tree. Depth-first search visits every vertex once and checks every edge in the graph once. Therefore, DFS complexity is O (V + E) O(V +E). This assumes that the graph is represented as an adjacency list.

What is depth first search in DBMS?

Understanding Depth First Search. As defined in our first article, depth first search is a tree-based graph traversal algorithm that is used to search a graph. Unlike BFS, a DFS algorithm traverses a tree or graph from the parent vertex down to its children and grandchildren vertices in a single path until it reaches a dead end.


1 Answers

There's a lot going on here.

As far as I can tell this code always returns the first goal node that reaches the top of the queue. Under the assumptions below about f and next, this goal node is f-optimal. But I wouldn't call this IDA*.

First, typically both A* and IDA* will open all neighbors of the current node at the same time. This code...doesn't. It uses iterators but only one loop. The first push is for the next sibling of the current node, and the second push is for the child. This is fine, I guess, except that siblings should be enumerated in increasing f-order so that a promising sibling doesn't get hidden after an unpromising one.

Second, unlike A*, IDA* doesn't have a close list. In a sense IDA* always has a search tree, since if it reaches two equivalent nodes, it still treats them as if they are distinct nodes. A* does have a close list, but it's more complicated than what's presented here. The way that A* handles cycles is that, if it discovers a cheaper path to an already closed node, then it reopens the node. This code doesn't, so it's only correct if there is never a need to reopen a node. As a result, this code needs f to be what's called a consistent heuristic (on every path, f never goes down as you follow the path), while A* only needs f to be admissible (f never underestimates the cost to reach a goal state).

like image 157
David Eisenstat Avatar answered Oct 21 '22 22:10

David Eisenstat