CS 540 Lecture Notes Fall 1996

Partial-Order Planning (Chapter 11)


Partial-Order Planning

Plan-Space Planning

Example

Interleaving vs. Non-Interleaving of Sub-Plan Steps

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).

Partial-Order Planner (POP) Algorithm

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-add c Sj in Links(plan)
    begin     ; "declobber" threat
      choose either
	Demotion: add S-threat 

Plan Modification Operations

The above algorithm uses four basic plan modification operations to revise a plan, two for solving a goal and two for fixing a threat:

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.

  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:
    1. Stack is the only operator that can be used to solve this open precondition.
    2. 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:
    1. Stack is the only operator applicable here.
    2. 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:
    1. 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.
    2. 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:
    1. There are two possible operators (Pickup and Unstack) for solving this open precondition, so this is a choice point for the algorithm.
    2. 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)
    
               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)
    

  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)
    
               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)
    

  8. Solve open preconditions using Simple Establishment for each of the following:

    Open Precondin StepSolved by Step
    clear(C)Unstack(C,A)Start
    on(C,A)Unstack(C,A)Start
    handemptyUnstack(C,A)Start

    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:

    Open Precondin StepSolved by Step
    Holding(C)Putdown(C)Unstack(C,A)
    ontable(B)Pickup(B)Start
    clear(B)Pickup(B)Start
    handemptyPickup(B)Putdown(C)

    For each of the above, add a causal link.

  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:

    Open Precondin StepSolved by Step
    clear(C)Stack(B,C)Putdown(C)
    ontable(A)Pickup(A)Start
    handemptyPickup(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)      |
    		  |------------------------
    

  13. No open preconditions and no threats, so halt. The only consistent total ordering that is implied from the final complete partial-order plan is: Unstack(C,A), Putdown(C), Pickup(B), Stack(B,C), Pickup(A), Stack(A,B). Notice that this interleaves the steps in the solutions to the two original goals, on(A,B) and on(B,C).

POP Summary


Last modified November 5, 1996
Copyright © 1996 by Charles R. Dyer. All rights reserved.