CS440 Fall 2001
Assignment 3

Due 5:00 PM, Tuesday, Oct. 16th
Department of Computer Science
Link
 to Colorado State University Home 
 Page


A* Search
(Updated Oct. 16th)

A* Algorithm

Implement the A* algorithm described below. Do so with a minimum of global variables; the only global variables used should be counters for the number of nodes generated and the maximum queue size. You may start your solution with this code for iterative deepening.

Problems

Use your code to solve these problems. Your code must produce answers in a format just like like the examples shown. Your numerical values may differ a little.

Problem 1: Write a function named effective-branching-factor that has arguments for the solution path depth and the number of nodes generated and returns the effective branching factor. Recall from class that you must search for an approximation to the solution of the polynomial. A binary search is very efficient for this. Return an effective branching factor that results in a number of nodes that is within 0.01 of the true number of nodes generated. For example:

CL-USER(62): (effective-branching-factor 6 2000)
3.345683

CL-USER(64): (effective-branching-factor 5 6)
1.0004883

CL-USER(65): (effective-branching-factor 50 60000)
1.2025168

Problem 2: Solve a modified version of Graham's simple search problem by writing a function named findpath that accepts a start and goal state, a map, and t or nil to indicate the use of the hash table. Your function must solve the search problem, print the effective branching factor and the maximum queue length, then return the path from the start state to the goal state.

The modification is to add costs to each link in the map. Represent each successor by a list of the node letter and the cost of getting to that node. If A is the first node that has two successors, B and C, and it costs 2 to get to B and 5 to get to C, the map will be represented as '((a (b 2) (c 5))). You may use an very uninformative heuristic function for this that returns 0 for all states.

For example, the following calls show the benefit of using the hash table. First we solve the problem without the hash table, then again with the hash table.

CL-USER(7): (findpath 'a 'g '((a (b 1) (c 10) (d 1)) (b (b 1) (g 20)) (c (g 5)) (d (e 1)) 
		              (e (f 1)) (f (a 1)))   nil)
Effective branching factor is 9.411919.  Max queue length is 45.0.
(A C G)

CL-USER(8): (findpath 'a 'g '((a (b 1) (c 10) (d 1)) (b (b 1) (g 20)) (c (g 5)) (d (e 1)) 
		              (e (f 1)) (f (a 1)))   t)
Effective branching factor is 2.3730469.  Max queue length is 3.0.
(A C G)

Draw this map on a piece of paper. Consider the start and goal nodes and the path that is returned. Type an explanation of why A* is so much more efficient for this problem when the hash table is used. Type your answer as a comment in the source code, clearly marked as Problem 2.

Problem 3: Now you will apply A* to solve our robot example from previous assignments. First, write a function named robot-path that accepts the size of the square world, a list of barriers as lists of x and y pairs not including the outer walls, the start state, the goal state, a heuristic function to be used to calculate h for any node, and t or nil to specify use of the hash table. Let the cost of each action be equal to 1. Your function must solve the search problem, print the effective branching factor and the maximum queue length, the return the solution path as lists of x, y pairs and the action as a direction.

For example:

CL-USER(27): (robot-path 5 '((2 2)(2 3)(2 4)) '(1 1) '(5 5) #'(lambda (n) 0) t)
Effective branching factor is 1.5427856.  Max queue length is 9.0.
(((1 1) START) ((2 1) E) ((3 2) NE) ((3 3) N) ((4 4) NE) ((5 5) NE))
Now let's do this again with a better heuristic function. Let's use the smallest number of steps between a node and the goal. You must define the function dist to do this, which simply returns the maximum of the absolute value of the difference in x and the difference in y.
CL-USER(28): (setf barriers (loop for y from 2 to 12 collect (list 10 y)))
((10 2) (10 3) (10 4) (10 5) (10 6) (10 7) (10 8) (10 9) (10 10) (10 11)
 (10 12))

CL-USER(29): (robot-path 20 barriers '(1 1) '(20 20)
                  #'(lambda (n) (dist (node-state n) '(20 20))) t)
Effective branching factor is 1.1286695.  Max queue length is 64.0.
(((1 1) START) ((2 2) NE) ((3 3) NE) ((4 4) NE) ((5 5) NE) ((6 6) NE)
 ((7 7) NE) ((8 8) NE) ((9 9) NE) ((9 10) N) ((9 11) N) ((9 12) N)
 ((10 13) NE) ((11 13) E) ((12 13) E) ((13 13) E) ((14 14) NE) ((15 15) NE)
 ((16 16) NE) ((17 17) NE) ((18 18) NE) ((19 19) NE) ((20 20) NE))

Problem 4: To further explore the effects of different heuristic functions and of the hash table, write a function named robot-compare-hfuncs that has no arguments, performs a total of six searches, and prints the following table. For this function we don't care what it returns. The first two rows of results are for solving a small problem with a world of size 5, barriers at (3 3) and (3 4) a start state of (1 1) and a goal state of (4 4). The large problem is for a size of 10, barriers at (5 y) as y goes from 2 to 7, a start state of (1 1) and a goal state of (10 10). The "h = 0" heuristic function is a rather useless heuristic that is a constant zero for all nodes. The "h = dist" heuristic function is the distance function.

CL-USER(35): (robot-compare-hfuncs)

                   Without Hash Table            With Hash Table
                Path  Nodes  MaxQ    EBF      Path  Nodes  MaxQ    EBF
 small  h = 0     5    945    773   5.26        5     22      9   1.79
 small  h = dist  5     30     25   1.98        5     18     13   1.67
 large  h = dist 13   2809   2350   1.81       13     49     25   1.20
NIL
Type some comments comparing these numbers and explaining the differences. Type at least 10 sentences.

Extra Credit

Each of these extra credit problems are worth about the same amount as one quiz.

Extra Credit Problem 1: Let's say that it is harder for the robot to move diagonally than it is for it to move N, S, E, or W. Modify this search problem to reflect this and solve the problem again. Type some comments about the resulting search paths and how they are different than the ones you get from the original robot-path code.

Extra Credit Problem 2: Write a lisp function that prints the robot's world, including the outer walls, barriers, start and goal states and the solution path, using characters as shown below:

CL-USER(57): (setf barriers (append
		(loop for y from 2 to 12 collect (list 10 y))
		(loop for x from 10 downto 5 collect (list x 12))))
((10 2) (10 3) (10 4) (10 5) (10 6) (10 7) (10 8) (10 9) (10 10) (10 11)
 (10 12) (10 12) (9 12) (8 12) (7 12) (6 12) (5 12))

CL-USER(58): (show-maze '(1 1) '(20 20) 20 barriers
                 (robot-path 20 barriers '(1 1) '(20 20)
                       #'(lambda  (n) (dist '(20 20) (node-state n))) t))

######################
#                   G#
#                  . #
#                 .  #
#                .   #
#               .    #
#              .     #
#             .      #
#    .........       #
#   .######          #
#    .    #          #
#     .   #          #
#      .  #          #
#       . #          #
#      .  #          #
#     .   #          #
#    .    #          #
#   .     #          #
#  .      #          #
# .       #          #
#S                   #
######################
NIL
Now I did it again with higher diagonal action costs being twice the cost of non-diagonal costs:
######################
#                   G#
#                  . #
#                 .  #
#                .   #
#               .    #
#              .     #
#             .      #
#            .       #
#    ###### .        #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#         #.         #
#S.........          #
######################