lisp program for the water jug problem
TRANSCRIPT
1
Introduction to Artificial Intelligence 人工智慧
Lecture 4March 14, 2012
洪國寶
2
Outline
•
Review•
Lisp (cont.)
•
Search Methodologies–
Problem Solving as Search
–
Properties of search methods
3
LISP• LISP (LISt Programming):
– As its name suggests LISP is based around handling of lists of data. A list in LISP is contained within brackets, such as:
(A B C)• Lists represent data and also programs, meaning LISP
programs can manipulate other programs, and it is even possible to write self-modifying LISP programs.
4
Review: Basic LISP concept
• Atoms• Lists• Expressions• The Evaluation Rule• Symbols
– Numbers, strings– Special symbols NIL and T
5
•
Data and Programs represented using Symbolic Expressions–
Atoms, Lists
•
Assigning variables (set, setf)•
List manipulation–
cons, remove, car / first, cdr
/ rest, append, list
–
push, pop–
second, third, …, nth
•
T, NIL, Predicates•
If, when, unless, cond, and, or
Review: Basic LISP concept
6
Outline
•
Review •
Lisp (cont.)
•
Search Methodologies–
Problem Solving as Search
–
Properties of search methods–
Heuristics
7
Basic Lisp functions•
Numeric functions: + -
* / incf
decf
•
List access: car (first), second …
tenth, nth, cdr
(rest), last, length
•
List construction: cons, append, list, push, pop•
Predicates: listp, numberp, stringp, atom, null, =, equal, eql, and, or, not
•
Special forms: setq/setf, quote, defun, if, cond, case, progn, loop
•
Input / Output: read, print, format •
Advanced list processing: assoc, mapcar, mapcan
8
Creating new functions
•
Lisp support a large number of built-in functions, including–
Arithmetic functions
–
Loop and program control functions–
I/O functions
–
List manipulation and other data structuring functions
•
In lisp we program by defining new functions in the lisp environment. ■
9
Defun•
Defun
is a Lisp macro for DEfining
FUNctions
• (defun
<proc-name> (<parameter1> <parameter2> ...) <expression1> <expression2> ...)
•
Side effect–
defines a user-defined lisp procedure
•
Returns the name of the procedure defined•
Defun does not evaluate its arguments
•
Resulting user-defined procedure is used like any other Lisp procedure
• > (defun
sqr
(x) (* x x))–
SQR• > (sqr
5)
–
25
10
Output• So far: the toplevel
prints return values
–
But, need a general way to print–
E.g. the load procedure only prints the return value of the last
expression• Print, Format
– > (print 3)33
– > (defun
verbose-add (a b)(format t "~A plus ~A equals ~A.~%" a b (+ a b))(+ a b))
– > (verbose-add 3 5)3 plus 5 equals 88
11
Input
• Read– > (defun
askme
(prompt)
(format t "~A" prompt)(read))
ASKME– > (askme
"How old are you? ")
How old are you? 33
12
C/C++ Example• C/C++: Convert units of sq. meters to sq. yards
#include <iostream.h>void main (){const float meters_to_yards = 1.196;float size_in_sqmeters;float size_in_sqyards;
cout
<< "Enter size in square meters: ";cin
>> size_in_sqmeters;
size_in_sqyards
= meters_to_yards * size_in_sqmeters;
cout<<"The size in square yards is " << size_in_sqyards
<< endl;
}
13
C/C++ Example• C/C++: Convert units of sq. meters to sq. yards#include <iostream.h>void main (){
const float meters_to_yards = 1.196;float size_in_sqmeters;float size_in_sqyards;
cout
<< "Enter size in square meters: ";cin
>> size_in_sqmeters;
size_in_sqyards
= meters_to_yards * size_in_sqmeters;
cout<<"The size in square yards is " << size_in_sqyards
<< endl;}
14
Equivalent Lisp Example• Literal Translation> (defun
converter ()(setf
meters_to_yards 1.196)
(format t "Enter size in square meters: ")(setf
size_in_sqmeters
(read))
(setf
size_in_sqyards(* meters_to_yards size_in_sqmeters))
(format t "The size in square yards is: ~A~%"size_in_sqyards)
)CONVERTER> (converter)Enter size in square meters: 2.0The size in square yards is 2.392NIL
• C/C++: Convert units of sq. meters to sq. yards#include <iostream.h>void main (){
const float meters_to_yards = 1.196;float size_in_sqmeters;float size_in_sqyards;
cout
<< "Enter size in square meters: ";cin
>> size_in_sqmeters;
size_in_sqyards
= meters_to_yards * size_in_sqmeters;
cout<<"The size in square yards is " << size_in_sqyards
<< endl;}
15
Better Lisp Function
• Using a more lisp-like style of programming> (defun
converter (sq_meters) (* sq_meters
1.196))
CONVERTER> (converter 2.0)2.392
• Take advantage of toplevel–
Users enter expressions; toplevel
prints the return value
–
Avoid variable assignments, side effects ■
16
Functional Programming
•
Writing programs that return values–
Instead of modifying things (side effects)
–
Avoid things like setf
•
Dominant paradigm in Lisp•
Allows interactive testing–
Can immediately test anything at any time
–
Don't have to worry that it will mess up some "state"–
Don't have long edit-compile-run cycle
17
Example: Both-ends• Define a procedure that gives both ends of a list
– > (setf
itinerary ’(Albany NYC Chicago Seattle Anchorage))– > (both-ends itinerary)
»
(ALBANY ANCHORAGE)
• Three steps–
Get first element
– > (first itinerary)»
ALBANY–
Get last element
– > (first (last itinerary)) »
ANCHORAGE–
Combine the two
– > (list (first itinerary) (first (last itinerary)))
• Define procedure– > (defun
both-ends (l) (list (first l) (first (last l))))
18
Scope•
Consider
• > (setf
a ’ORIG-A b ’ORIG-B c ’ORIG-C)–ORIG-C
• > (list a b c)–(ORIG-A ORIG-B ORIG-C)
• > (defun
myfun
(a) (setf
a ’myfun-a) (setf
b ’myfun-b) (list a b))• > (myfun
c)–(MYFUN-A MYFUN-B)
• > (list a b c)–(ORIG-A MYFUN-B ORIG-C)
•
Value of C is copied to A–
Parameter passing: Pass by Value (Like C/C++ default)
•
Global variables are still accessible!–
Like C/C++ Global variables
A,B,C A
19
Let• Let = Lisp’s way of defining local variables
– (let ( (<var1> <value1>) (<var2> <value2>) … )
<expr1><expr2>
)
• Example– (defun
distance (x1 y1 x2 y2)(let ( (dx
(-
x2 x1))(dy
(-
y2 y1)) )(sqrt
(+ (sqr
dx) (sqr
dy))) ))
• Let evaluates in parallel (not sequentially)–
Uses original values of variables in all (<var> <value>) pairs
– (let ( (dx
(-
x2 x1)) (dy
(-
y2 y1))(dx_sqr
(sqr
dx)) (dy_sqr
(sqr
dy)) ) ;; Won’t work!(sqrt
(+ dx_sqr
dy_sqr)) )
20
Let vs. Let*• Let -
Parallel evaluation
– > (setf
x ’outside)»
OUTSIDE– > (let ((x ’inside) (y x)) (list x y))
»
(INSIDE OUTSIDE)
• Let* -
Sequential evaluation– > (setf
x ’outside)»
OUTSIDE– > (let* ((x ’inside) (y x)) (list x y))
»
(INSIDE INSIDE)
• Let* Implementation of distance– (let* ( (dx
(-
x2 x1)) (dy
(-
y2 y1))(dx_sqr
(sqr
dx)) (dy_sqr
(sqr
dy)) ) ;; OK!(sqrt
(+ dx_sqr
dy_sqr)) )
21
Factorial• Definition of Factorial N!• C++ Implementation
int
factorial (int
x) {int
i,f;f = 1;for (i=1; i<=x; i++) f = f * i;return f;
}
• Lisp Implementation(defun
factorial (n)(let ((f 1))
(dotimes
(i n f) (setf
f (* f (+ i 1))))))
)1(
*...*3*2*1
1
0
1
i
Ni
N
i
N
i
22
DoTimes• DOTIMES is Lisp’s way of doing iteration
–
C/C++for (i=0; i<n; i++) {
<body>}
–
Lisp (dotimes
(i n) <body>)
–
First parameter is a list with three elements•
counter variable (e.g. i)
•
number of times to iterate (e.g. n)–
Counter variable (i) ranges from 0 to n-1
–
Optional return value can be specified (default is NIL)(dotimes
(i n return_value) <body>)
23
Recursively Calculating Factorial• Mathematical Definition of Factorial
• C/C++ Implementationlong Factorial (long X) {
if (X <= 1)return 1;
elsereturn X * Factorial(X-1);
}
• Lisp Implementation(defun
recursive-factorial (x)(if (<= x 1)
1(* x (recursive-factorial (-
x 1)))))
XX
X X X!
, ;*( )!,
1 11 1
24
Recursive calls–
Show recursion when calling (recursive-factorial 4)
– Begin (recursive-factorial 4)– Since 4>1, evaluate 4 * (recursive-factorial 3)– Begin (recursive-factorial 3)– Since 3>1, evaluate 3 * (recursive-factorial 2)– Begin (recursive-factorial 2)– Since 2>1, evaluate 2*(recursive-factorial 1)– Begin (recursive-factorial 1)– Since 1<=1, return 1– End (recursive-factorial 1), returns 1– 2 * (recursive-factorial 1) = 2 * 1 = 2– End (recursive-factorial 2), returns 2– 3 * (recursive-factorial 2) = 3 * 2 = 6– End (recursive-factorial 3), returns 6– 4 * (recursive-factorial 3) = 4 * 6 = 24– End (recursive-factorial 4), returns 24
(defun recursive-factorial (x)(if (<= x 1)
1(* x (recursive-factorial (- x 1)))))
25
Tower of Hanoi• Three pegs, S(start), T(temp), E(end)• N disks• Goal: Move disks from peg S to peg E• Restriction: Larger disk can’t be placed on top of
smaller diskS T E
26
Tower of Hanoi
• Solution to Tower of Hanoi–(defun
hanoi-aux (n start end temp)
(if (> n 1) (hanoi-aux (-
n 1) start temp end))(print (list start end))(if (> n 1) (hanoi-aux (-
n 1) temp end start)))
–(defun
hanoi
(n) (hanoi-aux n 'S 'E 'T))
• Example Runs (demo)> (hanoi
2)
(S T) (S E) (T E) NIL
> (hanoi 3)(S E) (S T) (E T) (S E) (T S) (T E) (S E) NIL
27
Lists as recursive structures
•
The basic functions for accessing the components of lists are car (first) and cdr (rest).
•
The way in which car and cdr
operate suggests a recursive approach to manipulating list structures. To perform an operation on each of the elements of a list:
1.
If the list is empty, quit.2.
Perform the operation on the first element of the list, and recur on the remainder of the list.
28
Lists as recursive structures
•
Example: member function
(defun
member (element list)(cond
((null list) nil)((equal element (car list) list)((t (member element (cdr
list)))))
•
ExerciseDefine a function that returns the length of a list.
29
Lists as recursive structures•
car-cdr recursion
•
Example: define a function that returns the number of atoms in a list(defun
count-atoms (list)
(cond
((null list) 0)((atom list) 1)(t (+ (count-atoms (car list))
(count-atoms (cdr
list))))))
30
Functions as Objects• Functions are regular objects• Function
–
Returns the object associated with the function– > (function +)
#<SYSTEM FUNCTION + >
–
Can use #' macro as a convenience– > #'+
#<SYSTEM FUNCTION + >
–
Examples– > (funcall
#'+ 1 2 3)
– > (apply #'+ '(1 2 3)); Note: These are equivalent to (+ 1 2 3)
31
Funcall• Funcall
–
Template• (funcall
#'<procedure> <arg1> … <argN>)
–
Calls the specified procedure with the given argments–
Equivalent to• (<procedure> <arg1> … <argN>)
–
Example 1• > (funcall
#'+ 3 2 7) ;; Same as (+ 3 2 7)
–
12–
Example 2• > (defun
eval-infix (arg1 operator arg2)
(funcall
operator arg1 arg2))• > (eval-infix 3 #'+ 2)
• Useful if you need to pass in a procedure name, to be applied at a future time
32
Apply• Apply
–
Similar to Funcall–
(typically) takes two arguments,
•
procedure object•
list of arguments to be passed to procedure object– (funcall
#'+ 3 2 7) ;; Same as (+ 3 2 7)– (apply #'+ '(3 2 7)) ;; Same as (+ 3 2 7)
–
Apply can actually take additional arguments•
Extra arguments are combined into a single list
•
Following are equivalent– (apply #'+ '(1 2 3 4 5 6))– (apply #'+ 1 2 3 '(4 5 6))
»
Argument fed to + is (append (list 1 2 3) ‘(4 5 6))
33
Mapcar
• Mapcar
-
MAPs
a function to successive CARs• MAPCAR
– (mapcar
<procedure> <argument>)Applies <procedure> to each element of <argument>
• Example– > (mapcar
#'oddp
'(1 2 3))
»
(T NIL T)– > (mapcar
#'= '(1 2 3) '(3 2 1))
»
(NIL T NIL)
34
Lambda• Lambda generates an unnamed function• Example
– > ((lambda (x) (+ x 100)) 1)»
101•
Defines an unnamed function which takes one parameter (x), and has the body (+ x 100)
•
The function adds 100 to its argument•
Invokes the unnamed function with a value of 1 for the parameter
•
The return value is 1 + 100 = 101
• Why use unnamed functions?–
Analogy to Java's "anonymous" classes
•
Don’t have to make up names for procedures•
Definition of procedure is close to where it is used
35
MAPxxxx• mapcar
-
MAPs
a function to successive CARs
–
Examples– > (mapcar
#'(lambda (x) (* x 2)) '(1 2 3 4 5))
(2 4 6 8 10)– > (mapcar
#'= '(1 2 3) '(3 2 1))
(NIL T NIL)
• Other MAPxxxx
functions–
maplist
•
Maplist
first applies the function to the entire list, then to the cdr of the list, then to the cddr of the list, and so on until the list has been decremented to NIL.
–
mapc, mapl, mapcan, mapcon
36
Outline
•
Review •
Lisp (cont.)
•
Search Methodologies–
Problem Solving as Search
–
Properties of search methods–
Heuristics
37
Introduction•
This chapter introduces a number of search methods, including depth-first search and breadth-first search.
•
The properties of search methods, which are useful in comparing different search methods, are identified.
•
This chapter also introduces the idea of heuristics for search and presents a number of methods, such as best-first search, that use heuristics to improve the performance of search methods.
38
Problem Solving as Search
•
A problem can be represented through a search space. It can be considered to consist of a goal and a set of actions that can be taken to lead to the goal.
•
Methods for examining a search space are called search methods.
39
Definition of a search problem
•
A search problem, P, is characterized by P={D, Si
, T, G} where–
D is a set of system states that represent the problem state-
space.–
Si
∈ D is a starting (initial) state.–
T={t1,t2, …
} is a set of transformations (operators, rules).
–
G
D is a set of goal states.•
A solution to P, denoted Ts, is a sequence of ti
=t1
, t2
, …
tn
with the property that tn
…(t2
(t1
(Si
))) ∈
G.
40
Definition of a search problem•
Note that D and T may be finite or countably
infinite.
We may partition D into two mutually exclusive subsets: –
Those Dr
D where there exists some Ts
such that tn
…(t2
(t1
(Si
))) ∈
Dr.These are reachable states.
–
Those Dur
D for which no Ts
exists such that tn
…(t2
(t1
(Si
))) ∈
Dur
.These are unreachable states.
•
If G ∩ Dr≠
then P is solvable.–
Unfortunately, it is difficult to ascertain if P is solvable before attempting a solution.
41
Definition of a search problem
•
To provide a formal description of a problem (as a search problem)–
Define a state space.
–
Specify the initial state(s)–
Specify the goal state(s).
–
Specify a set of rules that describe the actions available.
• Example: Water Jug Problem
42
Water Jug Problem
• Problem– You have a four gallon jug and a three gallon jug and the
goal is to come up with exactly two gallons of water.
• Operations– Dump bucket contents on the ground– Dump bucket contents in other bucket– Fill bucket to top with water
43
Water Jug Problem•
To provide a formal description of the Water Jug Problem:–
Define a state space.
•
(x y) where 0 ≦ x ≦ 4, 0 ≦ y ≦ 3–
Specify the initial state
•
(0 0)–
Specify the goal state(s).
•
(2 d) or (d 2)–
Specify a set of rules that describe the actions available.
•
(0 y) (4 y) (Fill bucket to top with water)• …
44
Tree Representation
(0 0)
(4 0) (0 3)
(0 3) (0 0) (4 3) (1 3) (3 0) (4 3) (0 0)
45
Lisp program for the water jug problem (1)
•
Initial state, goal state
(defvar
*start* '(0 0))
(defun
first-jug (state) (car state))
(defun
second-jug (state) (cadr
state))
(defun
mk-state (f s) (list f s))
(defun
goalp
(state)
(eq
(first-jug state) 2))
46
Lisp program for the water jug problem (2)
•
Generate new states
(defun
new-states (state)
(remove-null(list
(fill-first state)(fill-second state)(pour-first-second state)(pour-second-first state)(empty-first state)(empty-second state))))
(defun
remove-null (x)
(cond((null x) nil)((null (car x)) (remove-null (cdr
x)))
((cons (car x) (remove-null (cdr
x))))))
47
Lisp program for the water jug problem (3)
•
Operators for the water jug problem(defun
fill-first (state)(cond
((< (first-jug state) 4) (mk-state 4 (second-jug state)))))
(defun
fill-second (state)(cond
((< (second-jug state) 3) (mk-state (first-jug state) 3))))
(defun
pour-first-second (state)(let ( (f (first-jug state))
(s (second-jug state)))(cond
((zerop
f) nil)((= s 3) nil)((<= (+ f s) 3)
(mk-state 0 (+ f s)))(t (mk-state (-
(+ f s) 3) 3)))))
48
Lisp program for the water jug problem (4)
•
Operators for the water jug problem(defun
pour-second-first (state)(let ( (f (first-jug state))
(s (second-jug state)))(cond
((zerop
s) nil)((= f 4) nil)((<= (+ f s) 4)
(mk-state (+ f s) 0))(t (mk-state 4 (-
(+ f s) 4))))))
(defun
empty-first (state)(cond
((> (first-jug state) 0) (mk-state 0 (second-jug state)))))
(defun
empty-second (state)(cond
((> (second-jug state) 0) (mk-state (first-jug state) 0))))
49
Search for a solution
•
Data-Driven or Goal-Driven Search•
Brute Force Search–
Generate and test
–
DFS–
BFS
–
Depth-First Iterative Deepening
•
Heuristic
search
50
Data-Driven or Goal-Driven Search
•
The two main approaches to searching a search tree are data-driven search and goal-driven search.
•
Data-driven search, also known as forward chaining, starts from an initial state and uses actions that are allowed to move forward until a goal is reached.
•
Goal-driven search, also known as backward chaining, starts at the goal and works back toward a start state, by seeing what moves could have led to the goal state.
51
Brute Force Search•
Search methods that examine every node in the search tree –
also called exhaustive.•
Generate and test is the simplest brute force search method:–
Generate possible solutions to the problem.
–
Test each one in turn to see if it is a valid solution.–
Stop when a valid solution is found.
•
The method used to generate possible solutions must be carefully chosen.
52
Depth-First Search (DFS)
•
Depth-first search is a search algorithm that follows each path to its greatest depth before moving on to the next path.
•
It is an example of brute-force search, or exhaustive search.
•
Depth-first search is often used by computers for search problems such as locating files on a disk, or by search engines for spidering the Internet.
53
•
An exhaustive search method.•
Follows each path to its deepest node, before backtracking to try the next path.
Depth-First Search (DFS)
54
Add root to queue of partial pathsUntil queue is empty or goal is attained
If first queue element equals the goal then do nothing
Else remove the first queue elementadd its children to the front of the queue of the partial paths
If goal is attained thenannounce success
Depth-First Search (DFS)
55
(defun depth (start finish) (depth1 (list (list start)) finish))
(defun depth1 (queue finish)(cond ((null queue) nil)
((equal finish (caar queue))(print queue) (reverse (car queue)))
(t (print queue) (depth1 (append (expand (car queue))(cdr queue)) finish))))
Depth-First Search (DFS)
56
Lisp program for the water jug problem (5)
•
DFS(defun
dfs
(state depth limit)
(setf
*node* 0)
(setf
*expanded* 0)
(setf
*branches* 0)
(setf
*limit* limit)
(setf
*result* (dfs1 state depth))
(print (list *node* *expanded* *branches*)) *result*)
(defun
dfs1 (state depth)(setf
*node* (+ 1 *node*))(cond
((goalp
state) (list state))((zerop
depth) nil)((> *node* *limit*) nil)((let ((children (new-states state)))
(setf
*expanded* (+ 1 *expanded*))(setf
*branches* (+ (length children) *branches*))(let ((result (dfs2 children (-
depth 1))))(and result (cons state result)))))))
(defun
dfs2 (states depth)(cond
((null states) nil)((dfs1 (car states) depth))((dfs2 (cdr
states) depth))))
57
Breadth-First Search (BFS)
•
Breadth-first search involves traversing a tree by breadth rather than by depth.
•
It is used when examining game trees.
58
Breadth-First Search (BFS)
•
An exhaustive search method.•
Follows each path to a given depth before moving on to the next depth.
59
Breadth First Search (BFS)Add root to queue of partial pathsUntil queue is empty or goal is attained
If first queue element equals the goal then do nothing
Else remove the first queue elementadd its children to the
rear of the queue of the partial paths
If goal is attained thenannounce success
60
Breadth First Search (BFS)
(defun breadth (start finish)(breadth1 (list (list start)) finish))
(defun breadth1 (queue finish)(cond ((null queue) nil)
((equal finish (caar queue)) (print queue)(reverse (car queue)))
(t (print queue) (breadth1 (append (cdr queue)
(expand (car queue)))finish))))
61
Lisp program for the water jug problem (6)
•
BFS(defun
bfs
(state limit)
(setf
*node* 0)
(setf
*expanded* 0)
(setf
*branches* 0)
(setf
*limit* limit)
(setf
*result* (bfs1 (list (list
state))))
(print (list *node* *expanded* *branches*))
(reverse *result*))
(defun bfs1 (queue)(setf *node* (+ 1 *node*))(cond
((null queue) nil)((goalp (caar queue))(car queue))((> *node* *limit*) nil)((let ((children (new-states (caar queue))))
(setf *expanded* (+ 1 *expanded*))(setf *branches* (+ (length children) *branches*))(bfs1
(append (cdr queue)(mapcar #'(lambda (state)
(cons state (car queue)))children)))))))
62
Comparison of DFS and BFS
•
It is important to choose the correct search method for a given problem.
•
In some situations, for example, depth first search will never find a solution, even though one exists.
63
Implementations•
Depth-first search (DFS) can be implemented using a queue to store states–
But a stack
makes more sense
–
And enables us to create a recursive depth-first search function
•
Breadth-first search (BFS) implementations are almost identical to depth-first–
Except that they place states on the back of the queue instead of on the front.
64
Water jug, DFS, and BFS
•
Lisp programs(dribble “d:/class-notes/2012spring/w-j-test.txt”)
w-j-test.txt
65
Depth-First Iterative Deepening•
Depth-First Iterative Deepening, or DFID (also called Iterative Deepening Search or IDS), is an exhaustive search technique that combines depth-first with breadth-first search.
•
Carries out depth-first search to depth of 1, then to depth of 2, 3, and so on until a goal node is found.
•
Efficient in memory use, and can cope with infinitely long branches.
•
Not as inefficient in time as it might appear, particularly for very large trees, in which it only needs to examine the largest row (the last one) once.
66
Iterative Deepening Search L = 0• Limit = 0
67
Iterative Deepening Search L = 1• Limit = 1
68
Iterative Deepening Search L = 2• Limit = 2
69
Iterative Deepening Search L = 3• Limit = 3
70
QUESTIONS?