lisp general problem solver n.
Skip this Video
Loading SlideShow in 5 Seconds..
????? Lisp General Problem Solver PowerPoint Presentation
Download Presentation
????? Lisp General Problem Solver

Loading in 2 Seconds...

play fullscreen
1 / 44

????? Lisp General Problem Solver - PowerPoint PPT Presentation

  • Uploaded on

שיעור Lisp General Problem Solver. בינה מלאכותית יעל נצר. נושאים לפרוייקט. האם מכונות יכולות לחשוב? מבחן טיורינג החדר הסיני מודעות של מכונות Computation and representation סמלים ומערכות סמלים ייצוג ידע ב- AI מודל חישובי של ה- mind האם המוח הוא מכונת חישוב?. Antibugging Tools.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
Download Presentation

PowerPoint Slideshow about '????? Lisp General Problem Solver' - gari

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
lisp general problem solver

שיעור LispGeneral Problem Solver

בינה מלאכותית

יעל נצר

נושאים לפרוייקט
  • האם מכונות יכולות לחשוב?
    • מבחן טיורינג
    • החדר הסיני
    • מודעות של מכונות
  • Computation and representation
    • סמלים ומערכות סמלים
    • ייצוג ידע ב-AI
  • מודל חישובי של ה-mind
  • האם המוח הוא מכונת חישוב?
antibugging tools
Antibugging Tools
  • error / continuable errors

(defun average (numbers)

(if (null numbers)

(error “Average of the empty list is undefined”)

(/ (reduce #’+ numbers)

(length numbers))))

  • check-type:

(defun sqr (x)

(check-type x number)

(* x x))

  • assert:

(defun sqr (x)

(assert (numberp x) (x))

(* x x))

  • Timing

(defun f (n) (dotimes (i n) nil))

(time (f 100))

  • Functions carry their environment with them.

(mapcar #'(lambda (x) (+ x x))

'(1 2 3)) --> (2 4 6)

(defun adder (c)

#'(lambda (x) (+ x c)))

(mapcar (adder 3) '(1 2 3)) --> (4 5 6)

(mapcar (adder 10) '(1 2 3)) --> (11 12 13)

special variables
Special Variables
  • Note scope is not the same thing as extent:
    • scope as in other languages (part of code where variable is defined)
    • Extent – lifetime of a variable: possible to exit from scope and have variable still alive in a closure.
  • Ex:

(defun bank-account (balance)

#'(lambda (action amount)

(case action


(setf balance (+ balance amount)))


(setf balance (- balance amount))))))

special variables cont
Special variables cont.
  • Special variables: indefinite scope (like global variables).
  • BUT: special variable can be shadowed by a local binding.

(defvar *counter* 0)

(defun report ()

(format t "Counter = ~d" *counter*))

(report) ==> Counter = 0

(let ((*counter* 100)) (report)) ==> Counter = 100

(report) ==> Counter = 0

Let did not create a new local variable distinct from the special -
  • instead it locally shadowed the binding of the same special var.
  • Name of special variable is available at runtime:

(symbol-value '*counter*)

  • Lexical scoping: variables have lexical scope and indefinite extent.
  • Dynamic (special) variables: indefinite scope and dynamic extent.
multiple values
Multiple Values
  • Functions can return more than 1 value.

(round 5.1) ==> 5 .1

(* 2 (round 5.1)) ==> 10

(defun show-both (x)

(multiple-value-bind (int rem)(round x)

(format t "~f = ~d + ~f" x int rem)))

(show-both 5.1) ==> 5.1 = 5 + 0.1

(values 1 2 3) ==> 1 2 3 ;; return 3 values.

(values) ==> ;; nothing is returned (procedures)


equal and non case/type sensitive

Exact same object

Either eq or same number

Either eql or lists/strings with eql elements

  • optional, defaults, rest, by keyword.
  • Most CLisp functions have interesting keyword arguments

(find 6 '(1 2 3 4 5 6.0)) ==> nil (eql as default)

(find 6 '(1 2 3 4 5 6.0) :test #'equalp) ==> 6.0

(find 5 '(1 2 3 4 5 6.0) :test #'<) ==> 6.0

(find 5 '((a 1) (b 2) (c 3) (d 4) (e 5)) :key #'second) ==> (e 5)

  • Common key arguments (on matching and sequence built-in functions):

:test, :key, :start, :end, :from-end

  • Define functions find-all and find-all-if that return all elts from a list matching condition.
  • Note how similar to remove-if-not (built-in) and to remove.


(symbol-function find-all-if) #’remove-if-not)

Not exactly the right thing to do find-all - need to add something:

(defun complement (fn)

"If fn returns y, then (complement fn) returns (not y)."

#'(lambda (&rest args)

(not (apply fn args))))

(defun find-all (item sequence &rest keyword-args

&key (test #'eql) test-not


"Find all those elements of sequence that match item, according to the keywords. Doesn't alter sequence."

(if test-not

(apply #'remove item sequence

:test-not (complement test-not) keyword-args)

(apply #'remove item sequence

:test (complement test) keyword-args)))

  • Note: if same keyword appears twice, only first one is taken into account.
gps the general problem solver
GPS: The General Problem Solver
  • Developed in 1957 by Alan Newell and Herbert Simon.
  • The "first AI program". General theory of problem solving.
  • First to separate problem-solving strategy from knowledge (declarative).


1. Describe problem in vague terms

2. Specify problem in algorithmic terms

3. Implement problem in a programming language

4. Test the program on representative examples

5. Debug and analyze the resulting program, repeat the process.

description means end analysis and problem solving
Description: Means-end analysis and problem-solving.

I want to take my son to nursery school. What's the difference between what I have and what I want? One of distance. What changes distance? My automobile. My automobile won't work. What is needed to make it work? A new battery. What has new batteries? An auto repair shop. I want the repair shop to put in a new battery; but the shop doesn't know I need one. What is the problem? One of communication. What allows communication? A telephone...and so on. [Newell & Simon 72 - Human Problem Solving]

Solve a problem = find a way to eliminate the difference between what I have and what I want.
  • Other possibility: forward chaining from original situation.
  • Some actions require solving preconditions as subproblems.
  • Need description of allowable actions and their preconditions, plus description of situation.
  • Description of the world and of the goal: list of conditions.
  • List of allowable operators. Constant but a parameter.
  • Description of operators: action, preconditions, effects.
  • Effects can be simply described as add-list and delete-list (STRIPS).
  • Calling form: (GPS init-state goal-state list-of-ops)
  • Output: sequence of operators.
  • To satisfy a list of goals: satisfy each goal.
  • To satisfy a single goal: either goal already in current state, or find appropriate operator.
  • An operator is appropriate for a goal if it has goal in its add-list.
  • Can apply operator if preconditions hold - that is, precond becomes goal.
  • Toplevel Functions:

GPS: toplevel function.

  • Special Variables:

*state*: current state - list of conditions

*ops*: list of operators

  • Data Types:

op: operation with preconds, add-list and del-list.

  • Functions:

achieve: achieve an individual goal.

appropriate-p: decide if operator is appropriate for a goal.

apply-op: apply operator to current state.

  • Utilities:

member, set-difference, union, every, some, find-all.

code version 1
Code Version 1

(defvar *state* nil "The current state: a list of conditions.")

(defvar *ops* nil "A list of available operators.")

(defstruct op "An operation"

(action nil) (preconds nil) (add-list nil) (del-list nil))

(defun GPS (*state* goals *ops*)

"General Problem Solver: achieve all goals using *ops*."

(if (every #'achieve goals) 'solved))

(defun achieve (goal)

"A goal is achieved if it already holds,

or if there is an appropriate op for it that is applicable."

(or (member goal *state*)

(some #'apply-op

(find-all goal *ops* :test #'appropriate-p))))

(defun appropriate-p (goal op)

"An op is appropriate to a goal if it is in its add list."

(member goal (op-add-list op)))

(defun apply-op (op)

"Print a message and update *state* if op is applicable."

(when (every #'achieve (op-preconds op))

(print (list 'executing (op-action op)))

(setf *state* (set-difference *state* (op-del-list op)))

(setf *state* (union *state* (op-add-list op)))


(make-op :action 'drive-son-to-school

:preconds '(son-at-home car-works)

:add-list '(son-at-school)

:del-list '(son-at-home))

;;; ==============================

(defparameter *school-ops*


(make-op :action 'drive-son-to-school

:preconds '(son-at-home car-works)

:add-list '(son-at-school)

:del-list '(son-at-home))

(make-op :action 'shop-installs-battery

:preconds '(car-needs-battery shop-knows-problem shop-has-money)

:add-list '(car-works))

(make-op :action 'tell-shop-problem

:preconds '(in-communication-with-shop)

:add-list '(shop-knows-problem))

(make-op :action 'telephone-shop

:preconds '(know-phone-number)

:add-list '(in-communication-with-shop))

(make-op :action 'look-up-number

:preconds '(have-phone-book)

:add-list '(know-phone-number))

(make-op :action 'give-shop-money

:preconds '(have-money)

:add-list '(shop-has-money)

:del-list '(have-money))))

(gps '(son-at-home car-needs-battery have-money have-phone-book)

'(son-at-school) *school-ops*)








(gps '(son-at-home cat-needs-battery have-money)

'(son-at-school) *school-ops*)


(gps '(son-at-home car-works)

'(son-at-school) *school-ops*)



analysis how general
Analysis: How General?
  • First version crucial to understand problem better.
  • Running around the block problem: limit of KR formalism.
    • How to represent action "running around the block"? No add or delete.
  • Clobbered Sibling Goal Problem:

(gps '(son-at-home car-needs-battery have-money have-phone-book)

'(have-money son-at-school) *school-ops*)








But not true! Money is spent!

(every #'achieve goals) --> each goal have been satisfied in sequence, but not necessarily holds at the end!

  • Fix:

(defun achieve-all (goals)

(and (every #'achieve goals) (subsetp goals *state*)))

  • Checks that goal is reached, but does not force backtracking to find a solution if not.
leaping before you look
Leaping before you look
  • Same example, fixed function. Replies NIL after having spent the money!

(gps '()

'(jump-off-cliff land-safely) *ops*)




  • Planning and execution are interleaved.
recursive subgoal problem
Recursive Subgoal Problem
  • How to get a phone number? Look up phone book
  • Add option "Ask someone".


(make-op :action 'ask-phone-number



:add-list '(know-phone-number))


--> Infinite loop!

a more general problem solver
A More General Problem Solver
  • Solve the problems: "running around the block", "prerequisite clobbers sibling goal", "leaping before you look" and "recursive subgoal" problems.
  • Top-level function: GPS
  • Special variables: *ops*
  • Data types: op
  • Major functions:

achieve-all - achieve a list of goals

achieve - achieve an individual goal

appropriate-p - decide if an operator is appropriate for a goal

apply-op- apply operator to current state

Auxiliary functions:

executing-p: Is a condition an executing form?

starts-with: is the argument a list starting with a given atom?

convert-op: convert an operator to use the executing convention

use: use a list of operators

improvement 1
Improvement 1:
  • Instead of just printing a message whenever executing an action, GPS returns the resulting state with a list of "messages" indicating which actions have been taken
  • This solves the "running around the block" problem:

(GPS '((executing running-around-the-block)))

(defun executing-p (x)

"Is x of the form (executing ...)?"

(starts-with x 'executing))

(defun starts-with (list x)

"Is this a list whose first element is x?"

(and (consp list) (eql (first list) x)))

(defun convert-op (x)

"Make op conform to the (EXECUTING op) convention."

(unless (some #'executing-p (op-add-list op))

(push (list 'executing (op-action op)) (op-add-list op)))


(defun op (action &key preconds add-list del-list)

"Make a new operator that obeys the (EXECUTING op) convention."


(make-op :action action :preconds preconds

:add-list add-list :del-list del-list)))

improvement 2
Improvement 2
  • To solve the "leaping before you look" problem - do not update a global variable *state* before you know you will succeed.

(defun GPS

(state goals &optional (*ops* *ops*))

"From state, achieve goals using *ops*."

(remove-if #'atom


(cons '(start) state) goals nil)))

Semi-predicates: why do we add (start) in state?

If GPS returns nil, is it because it failed or because it is an empty

state? NIL is now ambiguous between failure and empty list of

actions. Solve ambiguity by representing state with lists of at

least one element.

  • Why do we remove atoms?

The executing convention means that we keep track of the actions in the state as pairs (EXECUTING op), all the other elements are atoms.

In the result, we only want the plan of actions, not the state.

improvement 3
Improvement 3
  • Use an explicit goal-stack
  • To solve the "recursive subgoal problem": keep a stack of goals being solved, immediately fail if a goal appears as a subgoal of itself.
  • To solve the "clobber sibling goal" problem, update achieve-all to test for final satisfaction.
(defun achieve-all (state goals goal-stack)

"Achieve each goal, and make sure they still hold at the end"

(let ((current-state state))

(if (and (every #'(lambda (g)

(setf current-state

(achieve current-state g goal-stack)))


(subsetp goals current-state :test #'equal))


(defun achieve (state goal goal-stack)

"A goal is achieved if it already holds, or if there is an

appropriate op for it that is applicable."

(dbg-indent :gps (length goal-stack) "Goal: ~a" goal)

(cond ((member-equal goal state) state)

((member-equal goal goal-stack) nil)

(t (some #'(lambda (op) (apply-op state goal op goal-stack))

(find-all goal *ops* :test #'appropriate-p)))))

Why do we use member-equal?
  • Default test in member is eq.

Must test for lists because of

(executing op)convention.

(defun member-equal (item list)

(member item list

:test #'equal))

Why can't we use union and set-difference in new apply-op?

(defun apply-op (state goal op goal-stack)

"Return a new state if op is applicable."

(dbg-indent :gps (length goal-stack) "Consider: ~a" (op-action op))

(let ((state2 (achieve-all state (op-preconds op) (cons goal goal-stack))))

(unless (null states)

;; Return updated state

(dbg-indent :gps (length goal-stack) "Action: ~a" (op-action op))

(append (remove-if #'(lambda (x) (member-equal x (op-del-list op)))


(op-add-list op)))))

State is now an ordered list of actions (to preserve order of (EXECUTING op) elements).
  • Functions union and set-difference do not preserve order of sets (they use sort). Functions append and remove-if are guaranteed to preserve order.
improvement 4
Improvement 4
  • Make program environment a parameter that can be declared easily and switched.
  • Do NOT depend on global state for any aspect.

(defun use (oplist)

"Use oplist as the default list of operators."

(length (setf *ops* oplist)))

the maze searching domain1
The MAZE searching domain
  • We don't have variables... so we need many operators.
  • We still don't need to write them down ourselves...

(defun make-maze-ops (pair)

"Make maze-op in both directions."

(list (make-maze-op (first pair) (second pair))

(make-maze-op (second pair) (first pair))))

(defun make-maze-op (here there)

"Make an operator to move between 2 places."

(op `(move from ,here to ,there)

:preconds `((at ,here))

:add-list `((at ,there))

:del-list `((at ,here))))

(defparameter *maze-ops*

(mappend #'make-maze-ops

'((1 2) (2 3) (3 4) (4 9) (9 14) (9 8) ...)))

(use *maze-ops*) ==> 48

> (gps '((at 1)) '((at 25)))





(AT 25))

Also return the state: (AT 25) when we only wanted the actions!

(remove-if #'atom ...) is the culprit: use

(find-all-if #'action-p...)

(defun action-p (x)

(or (equal x '(start)) (executing-p x)))

(defun find-path (start end)

"Search a maze for a path from start to end."

(let ((result (GPS `((at ,start)) `((at ,end)))))

(unless (null result)

(cons start

(mapcar #'destination

(remove '(start) results :test #'equal))))))

(defun destination (action)

"Find the Y in (executing (move from X to Y))"

(fifth (second action)))

(use *maze-ops*) --> 48

(find-path 1 25) --> (1 2 3 4 9 8 7 12 11 16 17 22 23 24 19 20 25)

(find-path 1 1) --> (1)