gps: the general problem solverarti.vub.ac.be/cursus/2011-2012/lcas/material/2.pdf · [human...
TRANSCRIPT
GPS: The general problem solver
developed in 1957 by Alan Newel and Herbert Simon
(H. Simon, 1957)
GPS: The general problem solver
developed in 1957 by Alan Newel and Herbert Simon
- Was the first program to separate its problem solving strategyfrom its knowledge of particular problems
- Spurred much further research in problem solving
- Written in IPL (Information processing language)
GPS: The general problem solver
developed in 1957 by Alan Newel and Herbert Simon
- Was the first program to separate its problem solving strategyfrom its knowledge of particular problems
- Spurred much further research in problem solving
- Written in IPL (Information processing language)
Example case of developing a (symbolic) AI program
1) Describe the problem (in plain language) 2) Specify the program 3) Implement the program 4) Test the program 5) Debugging and analysis
[Human problem solving, Newell and Simon, 1972]
[Human problem solving, Newell and Simon, 1972]
[Aristotle “The nature of deliberation and ist objects”, Nicomachean Ethics (book II.3,1112b]
→ Theory of means-ends analysis
[Aristotle “The nature of deliberation and ist objects”, Nicomachean Ethics (book II.3,1112b]
→ Theory of means-ends analysis
→ Theory of means-ends analysis
=> I can solve a problem if I can find some way to eliminate “the difference between what I have and what I want”
Remarks:
- Means-ends approach is a choice: it is also possible to start from the current situation and search forward to a goal, or employ a mixture of strategies
- Some actions have preconditions: subproblems that need to be solved first (e.g. getting the car to work before driving)
- So we will need some description of the current state of the world, of the allowable actions on it, of the appropriate actions, of action preconditions, and of action effects.
→ Refine all notions closer to lisp
(1) World state? → “What we have” and “what we want”
→ Sets of predicates or “truths about the world”
→ Sets can be implemented with lists
Example current state: '(poor unknown)Example goal description: '(rich famous)
→ Refine all notions closer to lisp
(2) actions or operators? → “change the world state”
→ Each action specifies a set of preconditions (predicates that need to be true in the current world state) and a set of effects (predicates that become true after taking the action)
→ The list of effects will be split into an add-list and a delete-list (cf. STRIPS)
→ Example: action “drive-son-to-school”
Preconds: '(son-at-home car-works)Add-list: '(son-at-school)Del-list: '(son-at-home)
→ List of possible actions
→ Refine all notions closer to lisp
(3) Complete problem specification?
→ Starting state (how the world is initially)e.g. '(unknown poor)
→ Goal state (how we would like the world to be)e.g. '(rich famous)
→ List of operations
→ (GPS '(unknown poor) '(rich famous) List-of-ops)
“Starting from the state of being poor and unknown, find any combination of actions that yield a state of being rich and famous”
→ Refine all notions closer to lisp
(4) A single goal can be achieved in two ways:
→ If it is in the current state, then it is trivially achieved→ Otherwise, we need to find an appropriate action and
apply it
(5) An action is appropriate if one of it's effects adds the goal in question (if it has the goal in it's add-list)
(6) An action can be taken if all it's preconditions are satisfied or achieved in the current state
=> Recursion!
(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 appropriate-p (goal op) "An op is appropriate if the goal is in its add-list.” (member goal (op-add-list op)))
(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 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))) t))
(defun GPS (*state* goals *ops*) "General Problem Solver: achieve all goals using *ops*." (if (every #'achieve goals) 'solved))
(1) The “clobbered sibling goal” problem
(2) The “leaping before you look” problem
(3) The “recursive subgoal” problem
(4) The “running around the block” problem
Suppose the goal is both son-at-school and have-money
Case 1:
Wrong!!
Suppose the goal is both son-at-school and have-money
Case 2:
The goals are “siblings”: One of the prerequisites for the plan for son-at-school is car-works, and achieving that goal clobbers the have-money goal
Suppose the goal is both son-at-school and have-money
First achieve have-money, Then achieve son-at-school=/=
Achieve both goals simultaneously
(defun GPS (*state* goals *ops*) "General Problem Solver: achieve all goals using *ops*." (if (every #'achieve goals) 'solved))
Suppose the goal is both son-at-school and have-money
First achieve have-money, Then achieve son-at-school=/=
Achieve both goals simultaneously
→ We replace every by achieve-all (twice)
(defun GPS (*state* goals *ops*) "General Problem Solver: achieve all goals using *ops*." (if (every #'achieve goals) 'solved))
Suppose the goal is '(jump-at-cliff land-safely)
→ Planning and execution are inter-weaved!
→ If an operator is “tried”, *state* is irreversibly changed
→ Introduce local *state* variables (see later)
(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))) t))
Suppose we add another way to get a phone number besides looking it up:
=> Infinite recursion
→ In order to call the shop, we need their phone number, which we can get by calling them, for which we need their phonenumber etc.
→ Newel and Simon: “Oscillating among ends, functions required, and means that that perform them”
→ Aristotle: “If we are to be always deliberating, we shall have to go on to infinity”
→ Possible solution: keep track of all goals that are currently being worked on and give up if a loop occurs
→ Suppose we want to add an operation for “running around the block”
→ There is no net “location change”
→ Perhaps put “feel tired” in the add-list? Or “got some Exercise”?
→ Perhaps a more general solution, e.g. represent “experiencing running around the block”?
→ Clobbering Sibling Goal: Check if previously achieved goals continue to hold.
→ Leap before you look: Introduce local state
→ Recursive sub-goal: keep track of a goal stack
→ Running around the block: add an (executing op-name) to the add-list of operators
→ Running around the block: add an (executing op-name) to the add-list of operators
→ Let GPS return a plan, i.e. an ordered list
((executing op-1) (executing op-2) …)
→ “Exploratory programming”: use lisp to change what we have
→ Running around the block: add an (executing op-name) to the add-list of operators
→ Let GPS return a plan, i.e. an ordered list
((executing op-1) (executing op-2) …)
→ Is NIL an empty plan or a failure?
=> represent empty plan as '((start))
(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 appropriate-p (goal op) "An op is appropriate if the goal is in its add-list.” (member-equal goal (op-add-list op)))
same
same
almost the same
(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." (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))))
(defun apply-op (state goal op goal-stack) "Return a new, transformed state if op is applicable." (let ((state2 (achieve-all state (op-preconds op) (cons goal goal-stack)))) (unless (null state2) ;; Return an updated state (append (remove-if #'(lambda (x) (member-equal x (op-del-list op))) state2) (op-add-list op)))))
(defun apply-op (state goal op goal-stack) "Return a new, transformed state if op is applicable." (let ((state2 (achieve-all state (op-preconds op) (cons goal goal-stack)))) (unless (null state2) ;; Return an updated state (append (remove-if #'(lambda (x) (member-equal x (op-del-list op))) state2) (op-add-list op)))))
→ Local state
→ Add current goal to goal stack when recursing down
→ State is ordered => Use append and remove-if instead of set-difference and union
→ differentiate between failure (NIL) and anything else (see later)
(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))) goals) (subsetp goals current-state :test #'equal)) current-state)))
(defun GPS (state goals &optional (*ops* *ops*)) "General Problem Solver: from state, achieve goals using *ops*." (remove-if #'atom (achieve-all (cons '(start) state) goals nil)))
→ Local state update and return
→ Differentiate between empty plan and failure from the beginning
→ Note: functions that return NIL as an indication of failure and something useful otherwise are semi-predicates
→ Not without danger:
(1) Could NIL be a meaningful value itself?
=> No because the empty plan contains “(start)”
(2) Could the user corrupt the program by providing NIL?
=> No because added by the top-level GPS
(3) Can the program corrupt the program
=> No, every new state will have at least one element
→ A debugging tool
→ A debugging tool
→ A debugging tool
(See file “dbg.lisp”)
Sow how general is GPS?
→ Can we handle different problems and problem domains?
"Classic" AI problem 1: Monkeys and bananas
“a hungry monkey is standing at the doorway to a room. In the middle of the room is a bunch of bananas suspended from the ceiling by a rope, well out of the monkey's reach. There is a
chair near the door, which is light enough for the monkey to push and tall enough to reach almost to the bananas. Just to
make things complicated, assume the monkey is holding a toy ball and can only hold one thing at a time.”
[Saul Amarel, 1968]
Sow how general is GPS?
"Classic" AI problem 1: Monkeys and bananas→ Plenty of ways to represent this problem
Sow how general is GPS?
"Classic" AI problem 1: Monkeys and bananas→ Plenty of ways to represent this problem
Get chair
Sow how general is GPS?
"Classic" AI problem 1: Monkeys and bananas→ Plenty of ways to represent this problem
Move chair
Sow how general is GPS?
"Classic" AI problem 1: Monkeys and bananas→ Plenty of ways to represent this problem
Get banana
"Classic" AI problem 1: Monkeys and bananas
"Classic" AI problem 2: “Maze searching”
"Classic" AI problem 2: “Maze searching”
Note: Back-quote `
“subtle bug”
(defun GPS (state goals &optional (*ops* *ops*)) "General Problem Solver: from state, achieve goals using *ops*." (find-all-if #'action-p (achieve-all (cons '(start) state) goals nil)))
(defun action-p (x) "Is x something that is (start) or (executing ...)?" (or (equal x '(start)) (executing-p x)))
We removed “atoms” in GPS, when we really want to remove everything except (START) and (EXECUTING action)
(When we use such “puns” – what is convenient instead of what is actually meant – there is bound to be trouble)
=> Solution:
How to move a number of blocks from a starting configuration to a goal configuration?
→ Each block can only have on other block directly on top of it→ A block can be moved only if there is no other block on top → The only possible action is to move a “free” block to
Another free block or onto the table
"Classic" AI problem 3: “The blocks world”
(defun make-block-ops (blocks) (let ((ops nil)) (dolist (a blocks) (dolist (b blocks) (unless (equal a b) (dolist (c blocks) (unless (or (equal c a) (equal c b)) (push (move-op a b c) ops))) (push (move-op a 'table b) ops) (push (move-op a b 'table) ops)))) ops))
(defun move-op (a b c) "Make an operator to move A from B to C." (op `(move ,a from ,b to ,c) :preconds `((space on ,a) (space on ,c) (,a on ,b)) :add-list (move-ons a b c) :del-list (move-ons a c b)))
(defun move-ons (a b c) (if (eq b 'table) `((,a on ,c)) `((,a on ,c) (space on ,b))))
(use (make-block-ops '(a b)))(gps '((a on table) (b on table) (space on a) (space on b) (space on table)) '((a on b) (b on table)))
=> ((START) (EXECUTING (MOVE A FROM TABLE TO B)))
A B
start
A
B
goal
=>
(gps '((a on b) (b on table) (space on a) (space on table)) '((b on a)))
=> ((START) (EXECUTING (MOVE A FROM B TO TABLE))
(EXECUTING (MOVE B FROM TABLE TO A)))
A
B
start
B
A
goal
=>
B
C
start
B
A
goal
=>
A C
(use (make-block-ops '(a b c)))
(gps '((a on b) (b on c) (c on table) (space on a) (space on table)) '((b on a) (c on b)))
=> ((START) (EXECUTING (MOVE A FROM B TO TABLE))
(EXECUTING (MOVE B FROM C TO A)) (EXECUTING (MOVE C FROM TABLE TO B)))
B
C
start
B
A
goal
=>
A C
!!HOWEVER!!
(use (make-block-ops '(a b c)))
(gps '((a on b) (b on c) (c on table) (space on a) (space on table)) '((c on b) (b on a)))
=> NIL
!!HOWEVER!!
(use (make-block-ops '(a b c)))
(gps '((a on b) (b on c) (c on table) (space on a) (space on table)) '((c on b) (b on a)))
=> NIL
→ First, “c on b” is achieved
→ But then solving for “b on a” clobbers that achievement again
→ The “prerequisite clobbers sibling goal” is recognized, but the program doesn't do anything about it!
→ Can you think of an “easy” solution?
Related problem: Efficiency of solution
BA
start
BA
goal
=>
C
C
Same problem: Efficiency of solution
→ Solution: Order the available operations so that those with fewer unfulfilled preconditions are tried first
The Sussman Anomaly
→ There is a “prerequisite clobbers sibling goal” problem regardless of the ordering of conjuncts!
→ A “full” solution requires a full-fledged search (chapter 6)
And more problems...
Uses the money!
→ Try all possible solutions (search again, PROLOG)
→ Protect goals
And more problems...
→ Need more powerful search
→ Need more general and abstract problem specifications
→ variables
→ Constraints on goal state (“checkmate”)→ Action costs→ Time constraints
→ “Real World” actions and states are not as crisp
→ Actions do not always succeed (e.g. getting “rich” by playing the lottery)→ Simultaneous goals, Undesirable states, Partial achievement, …
→ Lethal: Many problems are NP-hard and thus, in practice, simply unsolvable with “G”PS
Drew McDermott, 1967,“Artificial Intelligence Meets Natural Stupidity”
→ Homework: read this paper ←Hand in a 1-page essay on it by next week