CS 216 - Data Structures
Homework #4


Due: Thursday 10/16 at the beginning of class

NOTE: This work is to be done in pairs.

A Taste of AI - Part II

Do the following exercises from the Java Uniformed Search page Starter code is available.  Place written exercise answers in your README file.

Object-Oriented Problem Solving: Suppose you wish to develop a problem-solving engine for a collection of related problems.  However, you are unsure as to the best problem solving technique and will likely need to experiment with several.  What would be the first classes you would design and why?  (Hint: The Searcher and SearchNode classes were developed from a similar need.  How can you generalize from this example?  That is, for problem solving beyond search, how would you describe the general classes you would need for a good object-oriented approach?  This exercise encourages you to generalize from the previous exercise.) 

Computational Time versus Node Count:  One can always measure a programs time performance using the Unix "time" command or Java's System.currentTimeMillis(), which returns the current time in milliseconds.  Many search researchers instead use the node count as an estimate of the time performance of their algorithms.  What are the pros/cons of using node count rather than system time?  Consider comparison of results run on different computers.  Consider the comparison of two different search node implementations, where one has a smarter, more computationally expensive expand method that reduces the need for search (e.g. one which sorts the children in some beneficial way).

Breadth-First Search Experimentation: Measure the time and node count performance of your breadth-first search implementation on your scalable problem.  For randomly generated problems, measure several runs and report the median value.  Plot problem size versus runtime from the smallest size up to the largest size that usually terminates in less than one minute. 

Breadth-First Search Properties:  What is the time and space complexity of breadth-first search?  Is the search optimal?  Why or why not?  Is the search complete?  Why or why not?

Breadth-First Versus Depth-First:  Compare the time and space complexities of these searches.  Is depth-first search optimal?  Is it complete?  How would you summarize the trade-off(s) between breadth-first and depth-first search?

Depth-Limited Search Implementation: Create a new Searcher class based on DepthFirstSearcher.java called DepthLimitedSearcher.java.  Depth-limited search is exactly like depth-first search, except that it limits the depth of search as the name implies.  This is accomplished simply by not generating children for search nodes at a given depth limit.  In other words, you need to modify your depth-first search code such that (1) you have a constructor that takes a depth-limit parameter, and (2) you expand a node only when its depth is less than the depth-limit.  Test this algorithm with the PegSolitaireNode class for different depth-limits.  Which depth limit(s) yield an optimal solution?

Depth-Limited Search versus Depth-First Search:  Compare the time and space complexities of these searches.  Is depth-limited search optimal?  Is it complete?  How would you summarize the trade-off(s) between depth-limited and depth-first search?

Iterative-Deepening Depth-First Search Implementation:  Create a new Searcher class called IterativeDeepeningDepthFirstSearcher.java.  Iterative-deepening depth-first search searches by iteratively performing depth-limited searches with successive depth-limits 0, 1, 2, etc. until a goal node is found.  Thus your implementation will create and apply successive DepthLimitedSearcher objects with increasing depth-limits.  Be sure to iteratively update goalNode and nodeCount accordingly.  Test your implementation with BucketsNode.java. printing your node count and checking that it reflects the node counts of all successive depth-limited searches.

Iterative-Deepening Depth-First Search Experimentation: Measure the time and node count performance of your iterative-deepening depth-first search implementation on your scalable problem.  For randomly generated problems, measure several runs and report the median value.  Plot problem size versus runtime from the smallest size up to the largest size that usually terminates in less than one minute. 

Iterative-Deepening Depth-First Search Versus Depth-First Search: Compare the time and space complexities of these searches.  Is iterative-deepening depth-first search optimal?  Is it complete?  How would you summarize the trade-off(s) between iterative-deepening depth-first search and depth-first search?

The Right Tool for the Right Job: Which search algorithm(s) are most suitable for each of the different search problems you've worked with?  Why?  For each algorithm, what are the properties of suitable problems for application?  Summarize the trade-offs between all of the algorithms you've implemented.