CS 540 Lecture Notes - Partial-Order Planning
CS 540 Lecture Notes - Partial-Order Planning
S1 ---------> S2
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]
Plan-Space Planning
2. Finish
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.
Example
Goal: Set the table, i.e., on(Tablecloth) ^ out(Glasses) ^ out(Plates) ^ out(Silverware)
Initial State: clear(Table)
Operators:
1. Lay-tablecloth
P: clear(Table)
E: on(Tablecloth), ~clear(Table)
2. Put-out(x)
P: none
E: out(x), ~clear(Table)
2. Solve 4 unsolved goals in Finish by adding 4 new steps with the minimal temporal constraints
possible:
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) ---------------/
4. Fix threats caused by steps S2, S3, and S4 on the link from Start to S1. That is, clear(Table) is
a necessary precondition of S1 that is created by step Start. But S2 causes clear(Table) to be
deleted (negated), so if S2 came before S1, clear(Table) wouldn't be true and step S1 couldn't be
performed. Therefore, add a temporal constraint that forces S2 to come anytime after S1. That is,
add constraint S1 . Similarly, add S1 , and S1 , resulting in the new plan:
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) ----------------------/
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 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-add c Sj in Links(plan)
begin ; "declobber" threat
choose either
Demotion: add S-threat
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:
Promotion
Force threatening step to come after the causal link. I.e., add temporal link S2 < S3.
Demotion
Force threatening step to come before the causal link. I.e., add temporal link S3 < S1.
1. Create initial-plan:
Start +++++++++++++> Finish
P: none P: on(A,B)
E: on(C,A) on(B,C)
handempty
ontable(A)
ontable(B)
clear(B)
clear(C)
2. Solve open precondition on(A,B) in step Finish by Step Addition using Stack(A,B).
Notes:
a. Stack is the only operator that can be used to solve this open precondition.
b. The figure below should include a temporal link from the new step to Finish, but it is not
included in order to keep the figure more readable. Also, the temporal link connecting Start to
Finish has been omitted for the same reason.
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)
3. Solve open precondition on(B,C) in step Finish by Step Addition using Stack(B,C).
Notes:
a. Stack is the only operator applicable here.
b. The figure below should include temporal links from Start to the new step, as well as from the
new step to Finish, but these are not explicitly shown in order to keep the figure more readable.
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)
4. Solve open precondition holding(B) in step Stack(B,C) by Step Addition using Pickup(B).
Notes:
a. There are two possible operators (Pickup and Unstack) that could be used to solve this open
precondition, so this is a choice point for the algorithm.
b. The figure below should include temporal links from Start to the new step, as well as from the
new step to Stack(B,C), but these are not explicitly shown in order to keep the figure more
readable.
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)
5. Solve open precondition holding(A) in step Stack(A,B) by Step Addition using Pickup(A).
Notes:
a. There are two possible operators (Pickup and Unstack) for solving this open precondition, so
this is a choice point for the algorithm.
b. The figure below should include temporal links from Start to the new step, as well as from the
new step to Stack(A,B), but these are not explicitly shown in order to keep the figure more
readable.
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)
6. Solve open precondition clear(A) in step Pickup(A) using Step Addition with Unstack(C,A):
Start
P: none
E: on(C,A)
handempty
ontable(A)
ontable(B)
clear(B)
clear(C)
7. Solve open precondition handempty in Pickup(B) using Step Addition with Putdown(C):
Start
P: none
E: on(C,A)
handempty
ontable(A)
ontable(B)
clear(B)
clear(C)
8. Solve open preconditions using Simple Establishment for each of the following:
For each of the above, add a causal link from Start to Unstack(C,A).
9. Detect threat ~clear(C) in step Stack(B,C) to causal link from Start to Unstack(C,A). Fix by
Promotion: add temporal link from Unstack(C,A) to Stack(B,C) so that Stack(B,C) forced to come
after 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)
10. Solve open preconditions using Simple Establishment for each of the following:
11. Detect threat ~handempty at step Pickup(A) to causal link from Putdown(C) to Pickup(B). Fix by
Promotion: add temporal link from Pickup(B) to Pickup(A).
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)
12. Solve open preconditions using Simple Establishment for each of the following:
POP Summary
POP algorithm is sound and complete. That is, if the algorithm returns a "complete" plan, then any
total ordering implied by it solves the planning problem (soundness). And, if there is a solution to a
planning problem, the POP algorithm will eventually solve it (completeness).
Usual implementation of POP is to maintain a queue of partial plans, and sort the queue using some
kind of ranking function.