CS 540 | Lecture Notes | Fall 1996 |
Partial-Order Planning (Chapter 11)
S1 --------> S2 ----------> S5 |\ ^ | \----------------| | | v | ------> S3 ------> S4 ------
graphically represents the temporal constraints S1 < S2, S1 < S3, S1 < S4, S2 < S5, S3 < S4, and S4 < S5. This partial-order plan implicitly represents the following three total-order plans, each of which is consistent with all of the given constraints: [S1,S2,S3,S4,S5], [S1,S3,S2,S4,S5], and [S1,S3,S4,S2,S5]
P: none E: all positive literals defining the initial state
P: literals defining the conjunctive goal to be achieved E: none
and then creating the initial plan as: Start ---------> Finish
So, define a set of plan modification operators that detect and fix these problems.
P: clear(Table) E: on(Tablecloth), ~clear(Table)
P: none E: out(x), ~clear(Table)
Start -----------> Finish
on(Tablecloth) Start ------> S1: Lay-tablecloth ------------------------->Finish \ \ \ out(Glasses) ^ ^ ^ \ \ \----> S2: Put-out(Glasses) -----------------| | | \ \ out(Plates) / / \ \-----> S3: Put-out(Plates) ------------------/ / \ out(Silverware) / \------> S4: Put-out(Silverware) ---------------/
clear(Table) on(Tablecloth) Start -----------> S1: Lay-tablecloth ----------------------->Finish \ \ \ out(Glasses) ^ ^ ^ \ \ \---------> S2: Put-out(Glasses) ----------------| | | \ \ out(Plates) | | \ \----------> S3: Put-out(Plates) ------------------/ | \ out(Silverware) / \-----------> S4: Put-out(Silverware) ---------------/
clear(Table) on(Tablecloth) Start -----------> S1: Lay-tablecloth ---------------------->Finish | | | |\--|---| ^ ^ ^ | | | | | v out(Glasses) | | | | | |--------------+---+-> S2: Put-out(Glasses) --------------/ | | | | | v out(Plates) / | | |----------------+-> S3: Put-out(Plates) --------------------/ | | v out(Silverware) / |---------------> S4: Put-out(Silverware) ----------------------/
Given a conjunctive goal, G1 ^ G2, if the steps that solve G1 must either all come before or all come after the steps that solve G2, then the planner is called a non-interleaving planner. Otherwise, the planner allows interleaving of sub-plan steps. This constraint is different from the issue of partial-order vs. total-order planners. STRIPS is a non-interleaving planner because of its use of a stack to order goals to be achieved.
While a pure non-interleaving planner cannot solve the Sussman Anomaly, an interleaving planner can solve it by interleaving the steps associated with solving the two goals, on(A,B) and on(B,C). For example, the following plan solves this problem: unstack(C,A), Pickup(B), Stack(B,C), Stack(A,B). Notice that the first and last steps of this plan were created as part of the sub-plan to solve on(A,B), and the middle two steps are used to solve on(B,C).
function pop(initial-state, conjunctive-goal, operators) ;; non-deterministic algorithm plan = make-initial-plan(initial-state, conjunctive-goal) loop: begin if solution?(plan) then return(plan) (S-need, c) = select-subgoal(plan) ; choose an unsolved goal choose-operator(plan, operators, S-need, c) ; select an operator to solve that goal and revise plan resolve-threats(plan) ; fix any threats created end end function solution?(plan) if causal-links-establishing-all-preconditions-of-all-steps(plan) and all-threats-resolved(plan) and all-temporal-ordering-constraints-consistent(plan) and all-variable-bindings-consistent(plan) then return(true) else return(false) end function select-subgoal(plan) pick a plan step S-need from steps(plan) with a precondition c that has not been achieved return(S-need, c) end procedure choose-operator(plan, operators, S-need, c) ;; solve "open precondition" of some step choose a step S-add by either Step Addition: adding a new step from operators that has c in its Add-list Simple Establishment: picking an existing step in Steps(plan) that has c in its Add-list if no such step, then return(fail) add causal link S-add --->c S-need to Links(plan) add temporal ordering constraint S-addc Sj in Links(plan) begin ; "declobber" threat choose either Demotion: add S-threat
-------> S1 --------->p S2 | | -------> S3 ~p
That is, step S3 has effect ~p and from the temporal links could possibly occur in-between steps S1 and S2, which have a causal link between them. If this occurred, then S3 would "clobber" the goal p "produced" by S1 before it can be "consumed" by S2. Fix by ensuring that S3 cannot occur in the "protection interval" in between S1 and S2 by doing either of the following:
Demotion
Force threatening step to come before the
causal link. I.e., add temporal link S3 < S1.
Example -- Solving the Sussman Anomaly using the POP Algorithm
In the following plans, links shown as -----> are causal links and are labeled with the open precondition that is solved by this link. Links shown as ++++++> are temporal links, though most of these are not shown in order to keep the figures neater.
Start +++++++++++++> Finish P: none P: on(A,B) E: on(C,A) on(B,C) handempty ontable(A) ontable(B) clear(B) clear(C)
on(A,B) Start +++++++++++++> Stack(A,B) ------------> Finish P: none P: holding(A) P: on(A,B) E: on(C,A) clear(B) on(B,C) handempty E: on(A,B) ontable(A) clear(A) ontable(B) handempty clear(B) ~holding(A) clear(C) ~clear(B)
on(A,B) Start +++++++++++++> Stack(A,B) ------------> Finish P: none P: holding(A) ^ P: on(A,B) E: on(C,A) clear(B) | on(B,C) handempty E: on(A,B) | ontable(A) clear(A) | ontable(B) handempty | clear(B) ~holding(A) | clear(C) ~clear(B) | | on(B,C) | Stack(B,C) ------------| P: holding(B) clear(C) E: on(B,C) clear(B) handempty ~holding(B) ~clear(C)
on(A,B) Start +++++++++++++> Stack(A,B) ------------> Finish P: none P: holding(A) ^ P: on(A,B) E: on(C,A) clear(B) | on(B,C) handempty E: on(A,B) | ontable(A) clear(A) | ontable(B) handempty | clear(B) ~holding(A) |on(B,C) clear(C) ~clear(B) | | holding(B) | Pickup(B) -----------> Stack(B,C) P: ontable(B) P: holding(B) clear(B) clear(C) handempty E: on(B,C) E: holding(B) clear(B) ~ontable(B) handempty ~clear(B) ~holding(B) handempty ~clear(C)
holding(A) on(A,B) Start ++++++++> Pickup(A) ----------> Stack(A,B) --------> Finish P: none P: ontable(A) P: holding(A) ^ P: on(A,B) E: on(C,A) clear(A) clear(B) | on(B,C) handempty handempty E: on(A,B) | ontable(A) E: holding(A) clear(A) | ontable(B) ~clear(A) handempty | clear(B) ~ontable(A) ~holding(A) |on(B,C) clear(C) ~handempty ~clear(B) | | |---------| holding(B) | Pickup(B) -----------> Stack(B,C) P: ontable(B) P: holding(B) clear(B) clear(C) handempty E: on(B,C) E: holding(B) clear(B) ~ontable(B) handempty ~clear(B) ~holding(B) handempty ~clear(C)
Start P: none E: on(C,A) handempty ontable(A) ontable(B) clear(B) clear(C) clear(A) holding(A) on(A,B) Unstack(C,A) ----> Pickup(A) ----------> Stack(A,B) -------> Finish P: clear(C) P: ontable(A) P: holding(A) ^ P: on(A,B) on(C,A) clear(A) clear(B) | on(B,C) handempty handempty E: on(A,B) | E: holding(C) E: holding(A) clear(A) | clear(A) ~clear(A) handempty | ~clear(C) ~ontable(A) ~holding(A) |on(B,C) ~on(C,A) ~handempty ~clear(B) | ~handempty | |-----------| holding(B) | Pickup(B) -----------> Stack(B,C) P: ontable(B) P: holding(B) clear(B) clear(C) handempty E: on(B,C) E: holding(B) clear(B) ~ontable(B) handempty ~clear(B) ~holding(B) handempty ~clear(C)
Start P: none E: on(C,A) handempty ontable(A) ontable(B) clear(B) clear(C) clear(A) holding(A) on(A,B) Unstack(C,A) ----> Pickup(A) ----------> Stack(A,B) -------> Finish P: clear(C) P: ontable(A) P: holding(A) ^ P: on(A,B) on(C,A) clear(A) clear(B) | on(B,C) handempty handempty E: on(A,B) | E: holding(C) E: holding(A) clear(A) | clear(A) ~clear(A) handempty | ~clear(C) ~ontable(A) ~holding(A) |on(B,C) ~on(C,A) ~handempty ~clear(B) | ~handempty | |-----------| handempty holding(B) | Putdown(C) --------> Pickup(B) -----------> Stack(B,C) P: holding(C) P: ontable(B) P: holding(B) E: ontable(C) clear(B) clear(C) clear(C) handempty E: on(B,C) handempty E: holding(B) clear(B) ~holding(C) ~ontable(B) handempty ~clear(B) ~holding(B) handempty ~clear(C)
Open Precond | in Step | Solved by Step |
---|---|---|
clear(C) | Unstack(C,A) | Start |
on(C,A) | Unstack(C,A) | Start |
handempty | Unstack(C,A) | Start |
For each of the above, add a causal link from Start to Unstack(C,A).
Start ---------- P: none | E: on(C,A) | handempty |clear(C) ontable(A) |on(C,A) ontable(B) |handempty clear(B) | clear(C) | | |----------| | V clear(A) holding(A) on(A,B) Unstack(C,A) ----> Pickup(A) ----------> Stack(A,B) -------> Finish P: clear(C) + P: ontable(A) P: holding(A) ^ P: on(A,B) on(C,A) + clear(A) clear(B) | on(B,C) handempty + handempty E: on(A,B) | E: holding(C) + E: holding(A) clear(A) | clear(A) + ~clear(A) handempty | ~clear(C) + ~ontable(A) ~holding(A) |on(B,C) ~on(C,A) ++++ ~handempty ~clear(B) | ~handempty ++++++++++++++++++++++++++ | + |-----------| handempty holding(B) v | Putdown(C) --------> Pickup(B) -----------> Stack(B,C) P: holding(C) P: ontable(B) P: holding(B) E: ontable(C) clear(B) clear(C) clear(C) handempty E: on(B,C) handempty E: holding(B) clear(B) ~holding(C) ~ontable(B) handempty ~clear(B) ~holding(B) handempty ~clear(C)
Open Precond | in Step | Solved by Step |
---|---|---|
Holding(C) | Putdown(C) | Unstack(C,A) |
ontable(B) | Pickup(B) | Start |
clear(B) | Pickup(B) | Start |
handempty | Pickup(B) | Putdown(C) |
For each of the above, add a causal link.
Note: This fix means there is no threat at step
Stack(A,B) to causal link from Start to Pickup(B) because now
Stack(A,B) is after Pickup(A) which is after Pickup(B), so Stack(A,B)
must occur after Pickup(B).
Start ---------- P: none | E: on(C,A) | handempty |clear(C) ontable(A) |on(C,A) ontable(B) |handempty clear(B) | clear(C) | | |----------| | V clear(A) holding(A) on(A,B) Unstack(C,A) ----> Pickup(A) ----------> Stack(A,B) -------> Finish | P:clear(C) + ^ P: ontable(A) P: holding(A) ^ P: on(A,B) | on(C,A) + + clear(A) clear(B) | on(B,C) | handempty + + handempty E: on(A,B) | | E:holding(C) + + E: holding(A) clear(A) | | clear(A) + + ~clear(A) handempty | | ~clear(C) + + ~ontable(A) ~holding(A) |on(B,C) | ~on(C,A) ++++ ~handempty ~clear(B) | | ~handempty + +++++++++++++++++++++++++ | | + + | |holding(C) ++++ + |------------| | + + | v handempty + holding(B) v | Putdown(C) --------> Pickup(B) -----------> Stack(B,C) P: holding(C) P: ontable(B) P: holding(B) E: ontable(C) clear(B) clear(C) clear(C) handempty E: on(B,C) handempty E: holding(B) clear(B) ~holding(C) ~ontable(B) handempty ~clear(B) ~holding(B) handempty ~clear(C)
Open Precond | in Step | Solved by Step |
---|---|---|
clear(C) | Stack(B,C) | Putdown(C) |
ontable(A) | Pickup(A) | Start |
handempty | Pickup(A) | Stack(B,C) |
clear(B) | Stack(A,B) | Stack(B,C) |
For each of the above, add a causal link.
Start ---------------------- P: none | | E: on(C,A) | | handempty |clear(C) |ontable(A) ontable(A) |on(C,A) | ontable(B) |handempty | clear(B) | | clear(C) | | | |------| |----------| | | | V clear(A) v holding(A) on(A,B) Unstack(C,A) ----> Pickup(A) ----------> Stack(A,B) -------> Finish | P:clear(C) + ^ ^P: ontable(A) ^ P: holding(A) ^ P: on(A,B) | on(C,A) + + | clear(A) | clear(B) | on(B,C) | handempty + + | handempty | E: on(A,B) | | E:holding(C) + + |E: holding(A) | clear(A) | | clear(A) + + | ~clear(A) | handempty | | ~clear(C) + + | ~ontable(A) | ~holding(A) |on(B,C) | ~on(C,A) + + | ~handempty | ~clear(B) | | ~handempty + + |------| |--------| | | + + | handempty | | | +++++++++ |--------------------| | | | + + | |clear(B) | |holding(C) +++++ ++++++++++++++++++++++ | | | | + + | | |--------| v handempty + holding(B) v | | | Putdown(C) --------> Pickup(B) -----------> Stack(B,C) P: holding(C) \ P: ontable(B) ^ P: holding(B) E: ontable(C) \ clear(B) | clear(C) clear(C) \ handempty | E: on(B,C) handempty \ E: holding(B) | clear(B) ~holding(C) \ ~ontable(B) | handempty | ~clear(B) | ~holding(B) | handempty | ~clear(C) | | | clear(C) | |------------------------
Last modified November 5, 1996
Copyright © 1996 by Charles R. Dyer. All rights reserved.