Lisp program for the water jug problem

Preview:

Citation preview

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?

Recommended