University of Wisconsin - Madison | CS 540 Lecture Notes | C. R. Dyer |
S1 +++++++++> S2
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
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) ----------------------/
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 or 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 < S-need" to Orderings(plan); if S-add is a newly added step then begin add S-add to Steps(plan); add "Start < S-add" and "S-add < Finish" to Orderings(plan); end end procedure resolve-threats(plan) foreach S-threat that threatens link "Si --->c Sj" in Links(plan) begin // "declobber" threat choose either Demotion: add "S-threat < Si" to Orderings(plan) or Promotion: add "Sj < S-threat" to Orderings(plan); if not(consistent(plan)) then return fail; end end
-------> S1 --------->p S2 | | -------> S3 ~pThat 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.
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 |
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) |
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) |
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) | |------------------------
Copyright © 1996-2003 by Charles R. Dyer. All rights reserved.