Assignment 12 -- Due Monday, November 30 (at the beginning of lab)
CS 4521 Fall Semester, 2009
20 Points

Topics: Depth-first and breadth-first search and applications

The assignment consists of three required tasks and one extra credit task involving depth-first and breadth-first search and an application of them to a particular problem.

Discussion: Artificial intelligence researchers often test theories of problem solving by modeling problems in a "blocks world", where state representation is simplified and possible actions are well defined. Consider a world in which there are two blocks, A and B, and three places (or locations), p, q and r, where blocks may be placed. The possible states in this world are:

  +-------+    +-------+    +-------+    +-------+    +-------+    +-------+
S1| A     |  S2|       |  S3|       |  S4|   B   |  S5|       |  S6|     B |
  | B     |    | B A   |    | B   A |    |   A   |    |   A B |    |     A |
  | ----- |    | ----- |    | ----- |    | ----- |    | ----- |    | ----- |
  | p q r |    | p q r |    | p q r |    | p q r |    | p q r |    | p q r |
  +-------+    +-------+    +-------+    +-------+    +-------+    +-------+

  +-------+    +-------+    +-------+    +-------+    +-------+	   +-------+
S7|     A |  S8|       |  S9|       | S10| B     | S11|       |	S12|   A   |
  |     B |    | A   B |    |   B A |    | A     |    | A B   |	   |   B   |
  | ----- |    | ----- |    | ----- |    | ----- |    | ----- |	   | ----- |
  | p q r |    | p q r |    | p q r |    | p q r |    | p q r |	   | p q r |
  +-------+    +-------+    +-------+    +-------+    +-------+	   +-------+
The rule of action in this world is that a block can be moved (by an idealized robot arm, say) and placed on another place or block provided no other block is on top of it. Suppose the problem is to come up with a sequence of moves which will get us from the initial state to the goal state as depicted below:
                      +-------+             +-------+
                    S1| A     |          S12|   A   |
                      | B     |             |   B   |
                      | ----- |             | ----- |
                      | p q r |             | p q r |
                      +-------+             +-------+
                       initial                 goal
It is immediately obvious to humans that a solution to this problem is a three step solution that moves A from atop B to r, then moves B from p to q, and finally moves A from r to atop B. How could we write a program to come up with this solution?

Task 1: Graph Representation

One way is to represent the entire problem by an undirected graph G = (V,E) in which the vertices in V are the states {S1, S2, ..., S12} (which can be simply represented by the integers 1, 2, ..., 12 as in the text). Also an edge (Si,Sj) (i.e. (i,j)) is in E if it is legal to move a block to get from state Si to state Sj. The graph is undirected because if it is legal to move a block to get from state Si to state Sj, it is also legal to move it back, since a just-moved block can't have any other block on top of it.

Pictorially, this graph could be represented as shown below:


                                +-------+
                             S1 | A     |
                                | B     |
                                | ----- |
                                | p q r |
                                +-------+
                               /         \
                              /           \
                     +-------+             +-------+
                  S2 |       |          S3 |       |
                     | B A   |-------------| B   A |
                     | ----- |             | ----- |
                     | p q r |             | p q r |
                     +-------+             +-------+
                    /         \             \       \
                   /           \             \       \
          +-------+             +-------+     \       +-------+
       S4 |   B   |          S5 |       |      \   S6 |     B |
          |   A   |-------------|   A B |       \     |     A |
          | ----- |             | ----- |        \    | ----- |
          | p q r |             | p q r |         \   | p q r |
          +-------+             +-------+          \  +-------+
                               /    |               \     |
                      ________/     |                \    |
                     /              |                 \   |
          +-------+ /           +-------+             +-------+
       S7 |     A |/         S8 |       |          S9 |       |
          |     B |-------------| A   B |             |   B A |
          | ----- |             | ----- |             | ----- |
          | p q r |             | p q r |             | p q r |
          +-------+             +-------+             +-------+
                               /    |                /    |
                      ________/     |       ________/     |
                     /              |      /              |
          +-------+ /           +-------+ /           +-------+
       S10| B     |/         S11|       |/         S12|   A   |
          | A     |-------------| A B   |-------------|   B   |
          | ----- |             | ----- |             | ----- |
          | p q r |             | p q r |             | p q r |
          +-------+             +-------+             +-------+
We can represent this graph using the adjacency-list method and then use the depth-first or breadth-first search algorithms from Chapter 22 to find paths within it.

The vertices V and edges E for this graph are contained in the file graphdata.txt, the beginning of which looks like the picture below. Note: as in the text, the vertices are represented by integers starting at 1; usually attributes are kept in arrays (which are of size |V|+1, and index 0 is ignored), with the vertices being indexes into the arrays (e.g. pi[5] is the predecessor of vertex 5, which might have the value 2). The first line of the file contains the number of vertices |V|. Each of the rest of the lines contains two integers u and v, where (u,v) is an edge in E:

12  
1 2
1 3
2 1
2 3
2 4
2 5
3 1
3 2
3 6
3 9
4 2
4 5
. .
. .
. .
The first thing you need to do is design and write a procedure Build-Graph to read a file like this and return an adjacency-list representation of it. Since the file represents an undirected graph, if a pair u,v is in the file, then u must be on v's adjacency list, and vice versa (actually, if u,v is in the file, so is v,u; moreover the job of reading the data in has been done for you).

Task 2: Breadth-First Search

Breadth-first search is only slightly more complicated due to its use of a queue (there is pseudocode for an array implementation of ENQUEUE() and DEQUEUE() on page 203 of the text). You should be able to directly implement breadth-first search based on the BFS algorithm given in the text. Note: the distance attribute, d[u] is not used (but the predecessor attribute, pi[u], is used to print the solution). Here is are the two-lines of pseudocode to do a test BFS:
  BFS(G, start)
  PRINT-PATH(G, start, end)
The following output shows how the breadth-first search test works on the S1 -> S12. It is the (only) minimal solution to the problem.
         +---------------------+
         |                     |
         |  1 -> 3 -> 9 -> 12  |
         |                     |
         +---------------------+

Task 3: Depth-First Search

A simple change to the DFS algorithm given in class can find paths from a given node to all others (since they are all reachable in this case). Note: the time variable and time stamps, d[u] and f[u] are not used (but the predecessor attribute, pi[u], is used to print the solution). Here is the algorithm:
DFS(G, start)                |> note addition of start node
  for each vertex u in V[G] do
     color[u] <- WHITE
     pi[u] <- NIL
  DFS-Visit(start)           |> search from start only, not from all u in V
Note that although the DFS examples given in the text and in class were on directed graphs, the DFS algorithms work just as well on undirected graphs. The PRINT-PATH algorithm given in the text for printing paths in breadth-first predecessor trees can also be used on depth-first predecessor trees. Testing depth-first search on our blocks problem is completely analogous to the breadth-first case:
  DFS(G, start)
  PRINT-PATH(G, start, end)
Implement these depth-first search algorithms and apply them to some blocks world problems. The following output shows one possibility for how a depth-first search test works on the S1 -> S4 (you may get a different sequence).
         +-----------------------------------------------------+
         |                                                     |
         |  1 -> 3 -> 9 -> 12 -> 11 -> 10 -> 8 -> 7 -> 5 -> 4  |
         |                                                     |
         +-----------------------------------------------------+
Obviously, this is not the shortest solution to the problem, although DFS may come up with a shortest solution (even BFS can come up with different shortest solutions on some graphs, but not this one). An intelligent human would not seriously solve the problem by coming up with this path.

Helpful code: Here is a .h file for the Graph class graph.h and skeleton code for the Graph class implementation graph.cpp. Note: looking ahead, the Graph class has been designed to work with both weighted and unweighted graphs. Here is a .h file for the Queue class queue.h and code for the Queue class implementation queue.cpp. Here is a "driver" program that runs the tests: driver.cpp. Here is a "Makefile" that puts it all together: Makefile. When you download these files, be sure to remove the ".txt" suffixes (by moving them to the same file name without the ".txt").

Task 4: Extra Credit (up to 5 points) Extending the Blocks World

At this point it may seem as though breadth-first search is the best way to model blocks world problem solving in all cases. To see if this is right, consider some simple extensions to the blocks world. Suppose that we introduce a third block, C. The legal places p, q, and r remain the same. Thus the states involved in the graph representation of the problem would include:
		     +-------+    +-------+    +-------+
		     | C     |    |       |    |       |
		     | A     |    | C     |    |       |
		     | B     |    | B A   |    | B C A | . . . etc.
		     | ----- |    | ----- |    | ----- |
		     | p q r |    | p q r |    | p q r |
		     +-------+    +-------+    +-------+
Your final tasks for this part:
  1. (1 point) Determine exactly how many states would be required to completely represent the blocks world problem in a graph given 3 blocks.
  2. (1 points) Answer the same question if there are 4 blocks (using the same places p, q, and r as above).
  3. (3 points) Answer the same question in general: if there are b blocks and n places.

What To Hand In

  1. Well documented code implementing the algorithms (Task 1):
    • BFS
    • DFS (this is done for you)
    • DFS-Visit
    • PRINT-PATH
    and any other algorithms you use to complete the above tasks.
     
  2. A script clearly showing the results of the tests for Task 2:
    • BFS-Test(graph.txt, 1, 12)
    • BFS-Test(graph.txt, 12, 1)
    • BFS-Test(graph.txt, 1, 4)
    • BFS-Test(graph.txt, 4, 1)

    The same for the tests for Task 3:
    • DFS-Test(graph.txt, 1, 12)
    • DFS-Test(graph.txt, 12, 1)
    • DFS-Test(graph.txt, 1, 4)
    • DFS-Test(graph.txt, 4, 1)
    
    
  3. Your solutions to problems i, ii, and iii of Task 4 (if done) including all of your work in arriving at them.

Page URL: http://www.d.umn.edu /~ddunham/cs4521f09/assignments/a12/assignment.html
Page Author: Doug Dunham
Last Modified: Sunday, 29-Nov-2009 18:59:56 CST
Comments to: ddunham@d.umn.edu