Lab 5: Search

Aim

The aim of this lab is to show how different search strategies work. You will get an understanding of the strengths and weaknesses of the different search strategies.

Preparation

Read chapters 3 and 4 in the Russell and Norvig book.

About the lab

Your task in this lab is to run different search algorithms for the vacuum domain. The results you obtain will be the basis for a discussion about the applicability of the algorithms in this domain. The discussion could include the time and space complexity of the algorithms, whether they are optimal and the completeness of the algorithms.

Lab system

The lab system can be found at ~TDDA23/www-pub/mtrl/labs/ailabs/aima/search/ and is partly identical to the previous lab. The idea is to use a new kind of agent, a search agent, that thinks first and acts afterwards. We use the same domain as in the previous lab, i.e. the vacuum domain.

Given a problem description, a vacuum search agent searches a sequence of actions that describe the movements that have to be done to clean all dirty squares and then goes back to the start position to shut itself down. A prerequisite for this is that the vacuum agent has complete knowledge about the world, and in particular about where the dirt is located. This means that when the search is performed, no percepts are needed to act upon. As the agent has complete knowledge, there is no need for obtaining information via perception.

Search algorithms

Different search algorithms can be found at ~TDDA23/www-pub/mtrl/labs/ailabs/aima/search/algorithms/. The file ~TDDA23/www-pub/mtrl/labs/ailabs/aima/algorithms/simple.lisp contains functions for the basic search functions breadth-first-search, depth-first-search, depth-limited-search, iterative-deepening-search. There are also search algorithms that use heuristic functions: uniform-cost-search, greedy-search, and a*-search. For the vacuum domain, the heuristic function h that is used by greedy-search and a*-search to estimate the distance to the goal is defined as the number of pieces of dirt that are still left times two. The cost for each action is one.

The file ~TDDA23/www-pub/mtrl/labs/ailabs/aima/search/ algorithms/repeated.lisp contains algorithms with loop detection, such as, for instance no-cycles-depth-first-search. The loop detector no-returns makes sure that the algorithm does not generate nodes equal to the parent node. no-duplicates makes sure the algorithm avoids generating nodes that have been generated before and no-cycles makes sure no cycles are generated.

To create a problem

The search algorithms take a problem as input and return a sequence of actions that lead to a predefined goal. The problems can be generated using the constructor functions for the problem domain. The function vacuum-problem in the file ~TDDA23/www-pub/mtrl/labs/ailabs/aima/search/domains/vacuum.lisp takes the size of the world in m x n squares as a mandatory argument together with a list dirt with squares that are dirty and a probability factor dirt-probability for a square being dirty as an optional argument. If dirt is nil dirt is randomly assigned to all squares using dirt-probability, otherwise not. The constructor to specify a square is @ and takes an x-coordinate and a y-coordinate as arguments.

To create a vaccum problem with 2 x 2 squares and dirt at square (1 1), (the agent starts at square (0 0)), you write:
(setq vp (vacuum-problem 2 2 :dirt (list (@ 1 1)))) which returns
#<vacuum world problem state:((1 0) ((1 1)) 2 2 T (0 0)), expanded: 0 > where
((1 0) ((1 1)) 2 2 T (0 0)) represents the root node in the search tree.
(1 0) is the agent's direction at the east.
((1 1)) represents the square with dirt.
2 2 is the size of the world.
T denotes the fact that the vacuum agent is switched on.
(0 0) is the agent's position.

To run search algorithms on problems

The agent solves a problem by building a search tree where each node represents a state. Every action transforms a state into a new state. For instance, if the agent goes forward in the start state, the next node/state is
((1 0) ((1 1)) 2 2 T (1 0))

To solve a problem with a specific algorithm, use the function solve.
(solve vp :algorithm #'no-duplicates-breadth-first-search) prints the following information

Searching...

Level      Number of nodes in queue
=====      =====
0          1
1          4
2          7
3          8
4          8
5          7
6          5
7          5
8          7
9          7
=====      =====

Search completed!

(FORWARD (TURN LEFT) FORWARD (TURN LEFT) SUCK FORWARD (TURN LEFT) FORWARD
SHUT-OFF)
#<NODE f(9) = g(9) + h(0) state:((0 -1) NIL 2 2 NIL (0 0)) >
F(9) means that the cost for the solution is 9 as the number of actions is 9 and each action costs 1. State represents the state in which the problem is when the search is finished.

You can obtain more information by setting the argument print to t.
(solve vp :algorithm #'no-duplicates-breadth-first-search :print t) gives extra information

Action               State
=====                ======
                     ((1 0) ((1 1)) 2 2 T (0 0))
FORWARD              ((1 0) ((1 1)) 2 2 T (1 0))
(TURN LEFT)          ((0 1) ((1 1)) 2 2 T (1 0))
FORWARD              ((0 1) ((1 1)) 2 2 T (1 1))
(TURN LEFT)          ((-1 0) ((1 1)) 2 2 T (1 1))
SUCK                 ((-1 0) NIL 2 2 T (1 1))
FORWARD              ((-1 0) NIL 2 2 T (0 1))
(TURN LEFT)          ((0 -1) NIL 2 2 T (0 1))
FORWARD              ((0 -1) NIL 2 2 T (0 0))
SHUT-OFF             ((0 -1) NIL 2 2 NIL (0 0))
=====                ======
Total of 57 nodes expanded.

Note: Some of the algorithms may not find a solution in an acceptable time span and you will have to stop the execution.

Running the search algorithms with chrono
To be able to get information about the resources an algorithm needs to find a solution, you can use the function time which returns the search time as well as the amount of memory used during the search.
(time (solve vp :algorithm #'no-cycles-breadth-first-search))
gives the extra information:
; cpu time (non-gc) 4,640 msec user, 360 msec system
; cpu time (gc)     350 msec user, 40 msec system
; cpu time (total)  4,990 msec user, 400 msec system
; real time  5,661 msec
; space allocation:
;  394,524 cons cells, 6,613 symbols, 414,696 other bytes
Running the search algorithms in the vacuum world.
To run a search agent in the world as defined in the problem you can use the function run-problem which returns the points for a vacuum agent that uses search.
(run-problem vp :algorithm #'no-duplicates-depth-first-search :display t)

Comparing different algorithms

You can also compare different search algorithms using the function compare-search-algorithms which returns a table with information about the different algorithms' efficiency, among which the cost and the number of expanded nodes.
(compare-search-algorithms
        #'(lambda ()
               (vacuum-problem 3 3 :dirt nil))
        '(a*-search no-duplicates-breadth-first-search))
returns
Solved  Cost  Length  Nodes  Algorithm
====== ====== ====== ======= =========
   10    10.8   10.8   335.7 A*-SEARCH
   10    10.8   10.8   398.5 NO-DUPLICATES-BREADTH-FIRST-SEARCH
This means that a*-search found a solution in 10 out of 10 cases, that the cost for the length of the solution was 10.8 in average, and that the algorithm expanded on average 335.7 nodes.

Note! You have to use a lambda-expression to obtain the problem. Otherwise the world is not re-initialized between the different executions for the different algorithms.

Task

  1. Start Allegro (if you are running Netscape then exit it and restart it when Allegro has started) from the background menu or from a shell with: Wait for it to start.
    Many files will be loaded.
  2. IMPORTANT! If you would like to use a version of emacs that handles a graphical presentation of the search lab, type the following instead of 1 above: This loads a special emacs allegro system.
    In the lisp environment type:
  3. Conduct a fairly scientific evaluation of the search algorithms according to this basic outline for how to evaluate a theory:
  4. Algorithms with loop detection are available in the file repeated.lisp. Look into whether a certain loop detection technique makes an algorithm complete and/or optimal and describe your results so that you directly relate the results of the search to the characteristics of the vacuum domain.
  5. Look at the differences in the environment for the search agents and your agent from the previous lab according to the list of properties of an agent environment that you find on page 46 of the course book. Use this comparison to say something about how your agent and the search agents behave relative to each other. What search agent is most similar to your agent, with respect to how it solves the whole vacuum problem? Note that you are not just to compare the reasoning it performs in each step of the simulation.
This is not a complete description of exactly how you are supposed to perform your experiments. Just remember to carefully motivate to yourselves what steps you take, what problems you create, what test runs you do and what data you compare.

Examination

Write a report where you present what has been done in parts 2-5 from above.

Tips