Computer Science 315
Artificial Intelligence

Assignment 2 - AIMIA Chapter 3: Search

Now I ain't no monkey
I sure can't climb no tree


Oscar Woods, "Lone Wolf Blues" (1936)

Due Wednesday, 03 October

In this problem set, you will write Python implementations of depth-first, breadth-first, and uniform-cost search. If written efficiently, your code will take up less than 80 (non-blank) lines of Python, much of it repeated among files. You will test your code first a simple problem: searching for goal nodes in a binary tree You will write and turn in the following files, whose classes and methods you can see by clicking on the file name below: You may find it useful to implement a Node class within search.py, as illustrated in Figure 3.9. To see what methods are available to your code, here is the API for the Problem class. You will call these methods, rather than implementing them – unless you do the extra-credit work of creating your own problem. In either case, should save problem.py now.

I suggest sticking very close to the algorithm(s) in Figure 3.9; your Python code should match the pseudocode nearly line-for-line. This approach takes a little more discipline than just "winging it", but will get you to a solution faster. The only extra thing you need to add is a call to the takeAction method of the Problem class, which should come right after you call your REMOVE-FRONT implementation to get the first node from the fringe. This call will do something useful in the problem you're solving – printing out state information, moving the Quagent bot, etc.

Test #1: Using TREE-SEARCH to search a tree

When you're solving a problem by using a data structure, the simplest test is often a problem that takes the same form as your data structure. This program will test your tree-search code by seeking goal nodes in a tree – in this case, a fully-balanced binary tree. 1   Each node in the tree is assigned to be a goal or not with a specified probability, and is a assigned a random step cost between 1 and 100. To run the test, type

python treetest.py depth goalprob

where depth is the depth of the desired tree, and goalprob is the probability that a given node is a goal state. Once your Search implementations are working, you will see how each algorithm (DFS, BFS, UCS) visits each node, which will help you debug. If you add more print statements to debug along the way, be sure to remove them before submitting your solution: you will lose points for extra junk in the output. Also, do not submit a modified treetest.py, because I will test your solution with the original.. I tested the program with a depth of 3 and a goal probability of 0.2 (meaning that around 20% of the nodes were goal states). If you want to use the same random values each time, you can specify a seed value for the random-number generator; e.g.:

python treetest.py 3 0.2 0

This program will print out the binary tree, showing the state on each tree node (with goal nodes starred), as well as its step cost and path cost. The program will then call your DFS, BFS, and UCS algorithms in succession. If you've written these properly, and called the takeAction method, you should see a list of the order in which the states are visited for each algorithm. At the end of the list should be the final state, or None if the tree contained no goal states. If your search algorithm returns the final node on success, as it should, you'll need to write a __repr__ (string representation) method for your Node class, so that it can be printed out properly; otherwise, my code will just print out the machine address of the Node object. I suggest returning the node's state as a string.

Test #2: Extra Credit

For extra credit, find a problem that can be solved by one or all of the three search methods you've implemented, and implement the problem in Python, based on the Problem API. As in the TreeProblem example, you should put all the code needed to run your test into a single file, and tell me how to run it. I suggest the 8-Puzzle or 8-Queens Problem.

What to Turn In

Send me an email with the following files attached: search.py, dfsearch.py, bfsearch.py, ucsearch.py, and your extra-credit problem if you do it.
1You are welcome to look at this code, but don't be confused into thinking that it will help you solve the problem. The nodes you create in your solution will have different contents from the binary-tree nodes used in this particular problem. It may be better to treat each problem as a "black box" with which you communicate via the Problem API.