Automated Planning Domain-Configurable Planning: Hierarchical Task Networks

advertisement
Automated Planning
Domain-Configurable Planning:
Hierarchical Task Networks
Jonas Kvarnström
Automated Planning Group
Department of Computer and Information Science
Linköping University
jonas.kvarnstrom@liu.se – 2015

2
Recall the fundamental assumption that we only specify
 Structure: Objects and state variables
 Initial state and goal
 Physical preconditions and physical effects of actions
We only specify what can be done
The planner must decide what should be done
But even the most sophisticated heuristics and domain analysis methods
lack our intuitions and background knowledge…
jonkv@ida
Assumptions
How can we make a planner take advantage
of what we know?
 Planners taking advantage of additional knowledge can be called:
▪ Knowledge-rich
▪ Domain-configurable
▪ (Sometimes incorrectly called “domain-dependent”)
3
jonkv@ida
Domain-Configurable Planners
4
jonkv@ida
Comparisons (1)
Higher
performance
More effort
Domain-specific
Must write an entire planner
Can specialize the planner for very high performance
Domain-configurable
High-level (but sometimes complex) domain definition
Can provide more information for high performance
“Domain-independent”
Provide minimal information about actions
Less efficient
5
Larger problem classes
can be handled efficiently
Domain-configurable
Easier to improve expressivity and efficiency
 Often practically useful for a larger set of domains!
“Domain-independent”
Should be useful for a wide range of domains
Domain-specific
Only works in a single domain
jonkv@ida
Comparisons (2)

6
Classical Planning vs. Hierarchical Task Networks:
Objective is to achieve a goal:
Objective is to perform a task:
at(TimesSquare)
{ on(A,B), on(C,D) }
…
travel-to(TimesSquare)
place-blocks-correctly
…
Find any sequence of actions
that achieves the goal
Use "templates"
to incrementally refine the task
until you reach primitive actions
travel-to(TimesSquare) 
taxi-to(airport); fly-to(JFK); …
Provides guidance but still requires planning
jonkv@ida
HTNs: Ideas
A simple form of Hierarchical Task Network,
as defined in the book

A primitive task is an operator / action
 As in classical planning, what is primitive depends on the execution system
and on how detailed you want your plans to be
▪ For you, fly(here,there) may be a primitive task
▪ For the pilot, it may be decomposed into many smaller steps
stack(A,B)
load(crane1, loc3, cont5, …)
point(camera4, obj4)
Dark green
(in this presentation):
"Done", no need to think further
 Can be ground or non-ground: stack(A,x)
▪ There is no separate terminology, as in operator/action
8
jonkv@ida
Terminology 1: Primitive Task

A non-primitive task:
 Cannot be directly executed
 Must be decomposed into 0 or more subtasks
put-all-blocks-in-place()
make-tower(A,B,C,D,E)
move-stack-of-blocks(x, y)
Should be decomposed to
pickup, putdown, stack, unstack
actions!
Orange:
There's a "problem"
that we need to solve
9
jonkv@ida
Terminology 2: Non-Primitive Task

10
A method specifies one way to decompose a non-primitive task
 Can have many methods per non-primitive task

travel(from, to)
travel(from, to)
go-by-plane(from, to)
foot-travel(from, to)
Light green: A potential
template for a solution
The decomposition is a graph <N,E> (also known as network)
 Nodes in N correspond to subtasks to perform
 Edges in E correspond to ordering relations

Task: travel(x,y)  Decomposition:
buy-ticket (airport(x), airport(y))
fly(airport(x), airport(y))
travel (x, airport(x))
travel (airport(y), y)
jonkv@ida
Terminology 3: Method
11
jonkv@ida
Totally Ordered STNs
In Totally Ordered Simple Task Networks (STN),
each method must specify a sequence of subtasks

Can still be modeled as a graph <N,E>
buy-ticket (airport(x), airport(y))

travel (x, airport(x))
fly(airport(x), airport(y))
Alternatively: A sequence <t1,…,tk>
 <buy-ticket (airport(x), airport(y)), travel (x, airport(x)),
fly(airport(x), airport(y)), travel (airport(y), y) >
travel (airport(y), y)
12
jonkv@ida
Totally Ordered STNs (2)
We can illustrate the entire decomposition in this way
(horizontal arrow  sequence)
The “travel” task has a method
called “go-by-plane”
buy-ticket (airport(x), airport(y))
travel (x, airport(x))
travel(x,y)
Task
go-by-plane(x,y)
Method
fly(airport(x), airport(y))
Each method can also have a precondition
(exemplified later)
travel (airport(y), y)

13
Since a non-primitive task can have many methods:
 You still need to search, to determine which method to use
get-taxi-at(x)
travel(x,y)
Task
taxi-travel(x,y)
Method
ride-taxi(x, y)
pay-driver
travel(x,y)
Task
foot-travel(x,y)
Method
walk(x, y)
 …and to determine parameters (shown later)
Non-primitive
subtasks
Primitive
subtask
jonkv@ida
Multiple Methods

14
jonkv@ida
Composition
Properties of these plans:
 Hierarchical
 Consist of tasks
 Based on graphs ≈ networks
buy-ticket (airport(x), airport(y))
travel (x, airport(x))
travel(x,y)
Task
go-by-plane(x,y)
Method
fly (airport(x), airport(y))
foot-travel(x,y)
taxi-travel(x,airport(x))
get-taxi-at(x)
ride-taxi(x, airport(x))
travel (airport(y), y)
pay-driver
walk(x, y)

15
Let’s switch to Dock Worker Robots…
c3
c1
p1
p2
loc1
jonkv@ida
DWR

16
jonkv@ida
Methods
To move the topmost container from one pile to another:
 task:
move-topmost-container(pile1, pile2)
 method:
take-and-put(cont, crane, loc, pile1, pile2, c1, c2)
 precond: attached(pile1, loc), attached(pile2, loc),
belong(crane, loc),
top(cont, pile1), on(cont, c1),
top(c2, pile2)
The task has parameters
given from above
A method can have
additional parameters,
whose values are
chosen by the planner –
just as in classical planning!
The precond adds constraints:
crane must be some crane
in the same loc as the piles,
cont must be the topmost
container of pile1, …
Interpretation:
If you are asked to move-topmost-container(pile1, pile2),
check all possible values for cont, crane, loc, c1, c2 where the preconds are satisfied

17
To move the topmost container from one pile to another:
 task:
move-topmost-container(pile1, pile2)
 method:
take-and-put(cont, crane, loc, pile1, pile2, c1, c2)
 precond: attached(pile1, loc), attached(pile2, loc),
belong(crane, loc),
top(cont, pile1), on(cont, c1),
top(c2, pile2)
 subtasks: <take(crane, loc, cont, c1, pile1),
put(crane, loc, cont, c2, pile2)>
move-topmost-container(pile1, pile2)
take-and-put(…)
take(…)
put(…)
cont
c1
c2
pile1
pile2
jonkv@ida
Methods (2)

18
Suppose want to move three entire stacks of containers
 But preserve the order of the containers!
 Call this task move-three-stacks()
Initial state, with 3 locations, 3 piles to move
Corresponding goal, all piles moved
jonkv@ida
Example

19
How do we do it?
 First move all containers to another pile,
so they end up in inverse order
 Then move them to the real destination
C3
C1
C3
C2
C2
C2
C1
C3
C1
Pile 1
Pile 2
Pile 3
jonkv@ida
Example

20
A total-order method using this technique:
 Task:
▪ method:
▪ precond:
▪ subtasks:
move-three-stacks()
move-each-twice()
; no preconditions apart from the subtasks'
; move each stack twice:
<move-stack(p1a, p1b), move-stack(p1b, p1c),
move-stack(p2a, p2b), move-stack(p2b, p2c),
move-stack(p3a, p3b), move-stack(p3b, p3c) >
No parameters:
Hardcoded which
stacks to move
Tuple:
All subtasks are
sequentially
ordered
jonkv@ida
Example 2: move-each-twice

21
jonkv@ida
Example 2b: move-each-twice
Alternative:
 Task:
▪ method:
▪ precond:
move-three-stacks()
move-each-twice-choosing-interm(loc1, interm1, loc2, interm2, …)
top(pallet, interm1), top(pallet, interm2), top(pallet, interm3),
attached(…),
Let the planner choose intermediate piles
…
(there might be several alternatives)!
▪ subtasks: ; move each stack twice:
<move-stack(p1a, interm1), move-stack(interm1, p1c),
move-stack(p2a, interm2), move-stack(interm2, p2c),
move-stack(p3a, interm3), move-stack(interm3, p3c) >

22
How can we implement the task move-stack(pile1, pile2)?
 Must move all containers in a stack, but we don’t know how many…
 HTN planning allows recursion
▪ Move the topmost container (we know how to do that!)
▪ Then move the rest
 First attempt:
▪ task:
▪ method:
▪ precond:
▪ subtasks:
move-stack(pile1, pile2)
recursive-move(pile1, pile2)
true
<move-topmost-container(pile1, pile2), move-stack(pile1, pile2)>
move-stack(pile1, pile2)
recursive-move(pile1, pile2, …)
move-topmost-container(pile1, pile2)
move-stack(pile1, pile2)
take-and-put(…)
recursive-move(pile1, pile2, …)
jonkv@ida
Recursion (1)

23
But consider the BW and DWR "pile models"…
BW
A
B
C
DWR
clear(A)
on(A,B)
on(B,C)
ontable(C)
The bottom block
is not "on" anything
A
B
C
top(A, pile1)
on(A,B)
on(B,C)
on(C,pallet)
The bottom block
is "on" the pallet, a "special container"
We don't want to move
the pallet!
jonkv@ida
Recursion (2)

To fix this:
24
Add two
method params
 Task: move-stack(pile1, pile2)
▪ method:
recursive-move(pile1, pile2, cont, x)
▪ precond:
top(cont, pile1), on(cont, x)
▪ subtasks:
<move-topmost-container(pile1, pile2), move-stack(pile1, pile2)>
cont is on top of something (x), so cont can’t be the pallet
jonkv@ida
Recursion (3)

25
The planner can now create a structure like this:
move-stack(pile1, pile2)
recursive-move(pile1, pile2, …)
move-topmost-container(pile1, pile2)
move-stack(pile1, pile2)
take-and-put(…)
recursive-move(pile1, pile2, …)
take(…)
put(…)
move-topmost-container(pile1, pile2)
move-stack(pile1, pile2)
take-and-put(…)
recursive-move(pile1, pile2, …)
take(…)
put(…)
move-topmost
But when will the recursion end?
move-stack
jonkv@ida
Recursion (4)

26
At some point, only the pallet will be left in the stack
 Then recursive-move will not be applicable
 But we specified that we must execute some form of move-stack!
move-stack(pile1, pile2)
recursive-move(pile1, pile2, …)
move-topmost-container(pile1, pile2)
move-stack(pile1, pile2)
take-and-put(…)
recursive-move(pile1, pile2, …)
take(…)
put(…)
move-topmost-container(pile1, pile2)
take-and-put(…)
take(…)
put(…)
move-stack(pile1, pile2)
pile1 is empty!
No applicable methods…
Planner would backtrack!
jonkv@ida
Recursion (5)

27
We need a method that terminates the recursion
 Task:
▪ method:
▪ precond:
▪ subtasks:
Unique pallet object –
not a variable!
move-stack(p, q)
already-moved(p, q)
move-stack(pile1, pile2)
top(pallet, p)
<>
recursive-move(pile1, pile2, …)
move-topmost-container(pile1, pile2)
move-stack(pile1, pile2)
take-and-put(…)
recursive-move(pile1, pile2, …)
take(…)
put(…)
move-topmost-container(pile1, pile2)
move-stack(pile1, pile2)
take-and-put(…)
already-moved(pile1,pile2)
take(…)
put(…)
Method preconds satisfied
Zero subtasks!
jonkv@ida
Recursion (6)

An STN planning domain specifies:
 A set of operators used as primitive tasks
 A set of methods
▪ These indirectly specify the available non-primitive tasks

28
jonkv@ida
Domains, Problems, Solutions
General HTNs:
Can have additional
constraints to be
enforced
An STN problem instance specifies:
 An STN planning domain
 An initial state
 An initial task network, which should be ground (no variables)
▪ Total Order STN example: <move-three-stacks(); move-stack(p5a, p5c)>
▪ (Can also be represented as a graph with ordering constraints between task nodes)
No goals to be achieved!
We should perform tasks.

A solution is any executable action sequence
that can be generated from the initial task network
by recursively applying
 methods to non-primitive tasks
 operators to primitive tasks

The planner uses only the methods specified for a given task
 Will not try arbitrary actions…
 For this to be useful, you must have useful “recipes” for all tasks
29
jonkv@ida
Domains, Problems, Solutions
Added during the lecture…

task deliver(package, dest)
 method:
move1(package, packageloc, truckloc, dest)
 precond: at(truck, truckloc) & at(package, packageloc) &
packageloc = truckloc
 subtasks: <load(package),
driveto(dest), unload(package)>

task deliver(package, dest)
 method:
move1(package, packageloc, truckloc, dest)
 precond: at(truck, truckloc) & at(package, packageloc) &
packageloc != truckloc
 subtasks: <driveto(packageloc), load(package),
driveto(dest), unload(package)>
jonkv@ida
31

task deliver(package, dest)
 method:
move1(package, packageloc, truckloc, dest)
 precond: at(truck, truckloc) & at(package, packageloc)
 subtasks: <be-at(packageloc), load(package),
driveto(dest), unload(package)>

task be-at(loc)
 method:
drive(loc)
 precond: !at(truck,loc)
 subtasks: <driveto(loc)>

task be-at(loc)
 method:
already-there
 precond: at(truck,loc)
 subtasks: <>
jonkv@ida
32

Total Order Forward Decomposition:
s0
34
move-stack(pile1, pile2)
Task to perform, specified in the
problem instance
recursive-move(pile1, pile2, …)
Check preconds in s0 first!
jonkv@ida
Total Order Forward Decomposition
move-stack(pile1, pile2)
mtc(pile1, pile2)
s0
take-and-put(…)
s2
Check
preconds…
recursive-move(pile1, pile2, …)
mtc(pile1, pile2)
s0
take(…)
Check
preconds…
s1
put(…)
Check
preconds…
s2
s2
s2
take-and-put(…)
take(…)
Like forward search, TFD generates actions
in the same order in which they’ll be executed
 When we plan the next task, we know the
current state of the world
s3
put(…)
s4
move-stack(pile1, pile2)
s4
recursive-move(pile1, pile2, …)
move-topmost
move-stack

35
Primitive Tasks vs. Operators:
mtc(pile1, pile2)
 We've said…
▪ A primitive task is an action
Primitive task = action
 The book says…
▪ A primitive task is decomposed to a single action
take-and-put(…)
take(…)
put(…)
mtc(pile1, pile2)
take-and-put(…)
Primitive task
take(…)
put(…)
Action
take(…)
put(…)
Not an essential difference,
as long as you are consistent!
jonkv@ida
Definitions

TFD takes an STN problem instance:
– the current state
 <t1,…,tk> – a list of tasks to be achieved in the specified order
 O
– the available operators (with params, preconds, effects)
 M
– the available methods (with params, preconds, subtasks)
 s

Returns:
 A sequential plan
▪ Loses the hierarchical structure of the final plan
▪ Simplifies the presentation – but the structure could also be kept!
 TFD(s, <t1,…,tk>, O, M):
▪ // If we have no tasks left to do…
if (k = 0) then return the empty plan
36
jonkv@ida
Solving Total-Order STN Problems (1)
37
 TFD(s, <t1,…,tk>, O, M):
For simplicity: The case where
all tasks are ground
▪ if (k = 0) then return the empty plan
▪ if (t1 is primitive) then
// A primitive task is decomposed into a single action!
// May be many to choose from (e.g. method has more params than task).
actions  ground instances of operators in O
candidates  { a | a ∈ actions and
a is relevant for t1 and
// Achieves the task
a is applicable in s }
if (candidates = ∅) return failure
s
t1 = take(…)
a = take(…)
t2 = put(…)
Waiting in line
to be decomposed
in the next step
jonkv@ida
Solving Total-Order STN Problems (2)
 TFD(s, <t1,…,tk>, O, M):
For simplicity: The case where
all tasks are ground
▪ if (k = 0) then return the empty plan
▪ if (t1 is primitive) then
// A primitive task is decomposed into a single action!
// May be many to choose from (e.g. method has more params than task).
actions  ground instances of operators in O
candidates
{a|
a ∈ actions and
a is relevant for t1 and
// Achieves the task
a is applicable in s }
if (candidates = ∅) return failure
▪
▪
38
nondeterministically choose any a ∈ candidates // Or use backtracking
newstate
 γ(s,a)
// Apply the action, find the new state
remaining
 <t2,…,tk>
π  TFD(newstate, remaining, O, M)
if (π = failure) return failure
else return a.π
// Concatenation: a + the rest of the plan
s
t1 = take(…)
a = take(…)
newstate
t2 = put(…)
remaining
jonkv@ida
Solving Total-Order STN Problems (3)
39
 TFD(s, <t1,…,tk>, O, M):
The case where tasks are nonground: move(container1,X)
▪ if (k = 0) then return the empty plan
▪ if (t1 is primitive) then
// A primitive task is decomposed into a single action!
// May be many to choose from (e.g. method has more params than task).
actions  ground instances of operators in O
candidates  { (a,σ) | a ∈ actions and
σ is a substitution s.t. action a achieves σ(t1) and
a is applicable in s }
Basically, σ can specify variable
if (candidates = ∅) return failure
bindings for parameters of t1…
(italics = variables)
s
candidates
t1 = take(crane, loc1, cont2, cont, pile8)
take(crane1, loc1, cont2, cont5, pile8)
take(crane2, loc1, cont2, cont5, pile8)
t2=put(crane, …)
σ = { crane↦crane1, cont↦cont5 }
σ = { crane↦crane2, cont↦cont5 }
jonkv@ida
Solving Total-Order STN Problems (4)
40
 TFD(s, <t1,…,tk>, O, M):
▪ if (k = 0) then return the empty plan
▪ if (t1 is primitive) then
actions  ground instances of operators in O
candidates
 { (a,σ) |
a ∈ actions and
σ is a substitution s.t. action a achieves σ(t1) and
a is applicable in s }
if (candidates = ∅) return failure
▪
▪
nondeterministically choose any (a,σ) ∈ candidates// Or use backtracking
newstate
 γ(s,a)
// Apply the action, find the new state
remaining
 σ(<t2,…,tk>) // Must have the same variable bindings!
π  TFD(newstate, remaining, O, M)
// Handle the remaining tasks
if (π = failure) return failure
else return a.π
σ(t2) =
put(crane1, …)
(italics = variables)
s
t1 = take(crane, loc1, cont2, cont, pile8)
chosen: a = take(crane1, loc1, cont2, cont5, pile8)
take(crane2, loc1, cont2, cont5, pile8)
t2=put(crane, …)
σ = { crane↦crane1, cont↦cont5 }
{ crane↦crane2, cont↦cont5 }
jonkv@ida
Solving Total-Order STN Problems (5)
41
 TFD(s, <t1,…,tk>, O, M):
▪ if (k = 0) then return the empty plan
▪ if (t1 is primitive) then …
▪ else // t1 is travel(LiU, Resecentrum), for example
// A non-primitive task is decomposed into a new task list.
// May have many methods to choose from: taxi-travel, bus-travel, walk, …
ground
 ground instances of methods in M
As before,
candidates  { (m,σ) | m ∈ ground and
but
σ is a substitution s.t. task(m) = σ(t1) and
methods
m is applicable in s } // Methods have preconds!
instead of
if (candidates = ∅) return failure
actions
nondeterministically choose any (m,σ) ∈ active // Or use backtracking
travel(x,y)
taxi-travel(x,y)
get-taxi-at(x)
ride-taxi(x, y)
pay-driver
jonkv@ida
Solving Total-Order STN Problems (6)
42
 TFD(s, <t1,…,tk>, O, M):
▪ if (k = 0) then return the empty plan
▪ if (t1 is primitive) then …
▪ else // t1 is travel(LiU, Resecentrum), for example
// A non-primitive task is decomposed into a new task list.
// May have many methods to choose from: taxi-travel, bus-travel, walk, …
ground
 ground instances of methods in M
candidates
 { (m,σ) |
m ∈ ground and
σ is a substitution s.t. task(m) = σ(t1) and
m is applicable in s } // Methods have preconds!
if (candidates = ∅) return failure
// Or use backtracking
nondeterministically choose any (m,σ) ∈ active
▪
Replace
the task by
its
subtasks
// No actions are applied here, so no new state!
remaining  subtasks(m) . σ(<t2,…,tk>) // Prepend new list!
π  TFD(s, remaining, O, M)
if (π = failure) return failure
In TFD
else return π
the "origin" of a task is discarded:
travel(x,y)
No longer needed,
taxi-travel(x,y)
only the subtasks are relevant
get-taxi-at(x)
ride-taxi(x, y)
pay-driver
jonkv@ida
Solving Total-Order STN Problems (7)

44
TFD requires totally ordered methods
 Can’t interleave subtasks of different tasks

Suppose we want to fetch one object somewhere,
then return to where we are now
 Task:
▪ method:
▪ precond:
▪ subtasks:
fetch(obj)
get(obj, mypos, objpos)
robotat(mypos) & at(obj, objpos)
<travel(mypos, objpos), pickup(obj), travel(objpos, mypos)>
 Task: travel(x, y)
▪ method: walk(x, y)
▪ method: stayat(x)
I’m at A, the thing to fetch is at B
fetch(p)
get(p, a, b)
travel(a,b)
pickup(p)
travel(b,a)
jonkv@ida
Limitation of Ordered-Task Planning

45
Suppose we want to fetch two objects somewhere, and return
 (Simplified example – consider “fetching all the objects we need”)

One idea: Just “fetch” each object in sequence
 Task:
▪ method:
▪ precond:
▪ subtasks:
fetch-both(obj1, obj2)
get-both(obj1, obj2, mypos, objpos1, objpos2)
–
<fetch(obj1, mypos, objpos1), fetch(obj2, mypos, objpos2)>
I’m at A, both objects are at B
fetch-both(p, q)
get-both(p,q)
travel(a,b)
fetch(p)
fetch(q)
get(p)
get(q)
pickup(p)
travel(b,a)
Have to start with the first Fetch…
travel(a,b)
pickup(q)
travel(b,a)
I’m back at A and have to walk again!
jonkv@ida
Limitation of Ordered-Task Planning

To generate more efficient plans using total-order STNs:
 Use a different domain model!
 Task:
▪ method:
▪ precond:
▪ subtasks:
fetch-both(obj1, obj2)
 Task:
▪ method:
▪ precond:
▪ subtasks:
fetch-both(obj1, obj2)
get-both(obj1, obj2, mypos, objpos1, objpos2)
objpos1 != objpos2 & at(obj1, objpos1) & at(obj2, objpos2)
<travel(mypos, objpos1), pickup(obj1),
travel(objpos1, objpos2), pickup(obj2),
travel(objpos2, mypos)>
get-both-in-same-place(obj1, obj2, mypos, objpos)
robotat(mypos) & at(obj1, objpos) & at(obj2, objpos)
<travel(mypos, objpos), pickup(obj1), pickup(obj2),
travel(objpos, mypos)>
Or: load-all; drive-truck; unload-all
46
jonkv@ida
Alternative Methods

48
jonkv@ida
Partially Ordered Methods
Partially ordered method:
 The subtasks are a partially ordered set {t1, …, tk} – a network
travel(x,y)
go-by-plane(x,y)
No horizontal arrow
ordering all tasks
buy-ticket (a(x), a(y))
travel (x, a(x))
fly (a(x), a(y))
travel (a(y), y)
method go-by-plane(x,y)
task:
travel(x,y)
precond: long-distance(x,y)
network: u1=buy-ticket(a(x),a(y)), u2= travel(x,a(x)), u3= fly(a(x), a(y))
u4= travel(a(y),y),
Precedence: u1 before u3,
{(u1,u3), (u2,u3), (u3 ,u4)}
etc.

49
With partially ordered methods, subtasks can be interleaved
fetch-both(p, q)
get-both(p,q)
travel(a,b)
walk(a,b)
pickup(p)
fetch(p)
fetch(q)
get(p)
get(q)
travel(b,b)
stay-at(b)
pickup(q)
travel(b,a)
travel(a,a)
walk(b,a)
stay-at(a)
 Requires a more complicated planning algorithm: PFD
 SHOP2: implementation of PFD-like algorithm + generalizations
jonkv@ida
Partially Ordered Methods

50
Partial-order formulation of move-each-twice:
Each stack is moved to the temp pile
 task: move-all-stacks()
before it is moved to its final pile
▪ method:
move-each-twice()
Otherwise, no ordering constraints
precond:
; no preconditions
network:
u1 = move-stack(p1a, p1b), u2 = move-stack(p1b, p1c),
u3 = move-stack(p2a, p2b), u4 = move-stack(p2b, p2c),
u5 = move-stack(p3a, p3b), u6 = move-stack(p3b, p3c),
{(u1, u2), (u3, u4), (u5, u6)}

Old total-order formulation:
 task: move-all-stacks()
▪ method:
move-each-twice()
precond:
; no preconditions
subtasks:
< move-stack(p1a, p1b), move-stack(p1b, p1c),
move-stack(p2a, p2b), move-stack(p2b, p2c),
move-stack(p3a, p3b), move-stack(p3b, p3c) >
jonkv@ida
Partial-Order and Total-Order

PFD takes four inputs:
 s
 w
 O
 M
– the current state
– a partial order of tasks to be achieved
– the available operators
– the available methods
 PFD(s, w, O, M):
▪ // If we have no tasks left to do…
if (w = emptyset) then return the empty plan
51
jonkv@ida
Solving Partial-Order STN Problems (1)
52
jonkv@ida
Solving Partial-Order STN Problems (2)
 PFD(s, w, O, M):
▪ if (w = emptyset) then return the empty plan
▪ nondeterministically choose a task u in w
A task that could be first – not
that has no predecessors
necessarily a unique ”first task”!
▪ if (u is primitive) then
actions  ground instances of operators in O
candidates  { (a,σ) | a ∈ actions and
σ is a substitution s.t. action a achieves σ(t1) and
a is applicable in s }
if (candidates = ∅) return failure
▪
nondeterministically choose any (a,σ) ∈ candidates
newstate
 γ(s,a)
// Apply the action, find the new state
remaining
 σ(w – {u})
// Must have the same variable bindings!
π  PFD(newstate, remaining, O, M)
// Handle the remaining tasks
if (π = failure) return failure
else return a.π
53
 PFD(s, w, O, M):
▪ if (w = emptyset) then return the empty plan
▪ if (u is primitive) then …
▪ else // u is travel(LiU, Resecentrum), for example
ground
 ground instances of methods in M
candidates  { (m,σ) | m ∈ ground and
σ is a substitution s.t. task(m) = σ(t1) and
m is applicable in s } // Methods have preconds!
if (candidates = ∅) return failure
nondeterministically choose any (m,σ) ∈ active // Or use backtracking
▪
// No actions are applied here!
remaining  δ(w, u, m, σ)
π  PFD(s, remaining, O, M)
if (π = failure) return failure
else return π
Replacing the task by its subtasks
is more complicated here!
travel(x,y)
taxi-travel(x,y)
get-taxi-at(x)
ride-taxi(x, y)
pay-driver
jonkv@ida
Solving Partial-Order STN Problems (3)

54
What does δ(w, u, m, σ) mean?
 Suppose we started with a network w
teach()
 This task has a method:
teach()
containing a single task:
teach-by-lecture()
prepare-lecture()
travel (home, liu)
do-lecture()
 Only one task in w  applying the method is easy – leaves this network:
remaining =
δ(w, u, m, σ)
prepare-lecture()
travel (home, liu)
do-lecture()
jonkv@ida
The Delta Function (1)

55
Now we recurse:
prepare-lecture()
w=
travel (home, liu)
do-lecture()
travel (home, liu)
do-lecture()
 Two tasks could possibly be first:
u is one of…
 We pick one:
u = travel (home, liu)
prepare-lecture()
jonkv@ida
The Delta Function (2)

56
u = task to
decompose
We have:
w=
prepare-lecture()
 Method chosen for this task:
travel (home, liu)
do-lecture()
travel(x,y)
bus-travel(x,y)
buy-ticket (x, y)
travel (x, b(x))
fly (b(x), b(y))
travel (b(y), y)
jonkv@ida
The Delta Function (3)

57
First, we replace the selected task with its expansion
 Applying the substitution
prepare-lecture()
travel (home, liu)
do-lecture()
bus-travel(x,y)
buy-ticket (home, liu)
travel (home, b(home))
go(b(home), b(liu))
travel (b(liu), liu)
Now the old and new tasks need to be connected –
and not by placing all new tasks before all existing ones in w!
jonkv@ida
The Delta Function (4)

58
Every ordering constraint for the decomposed task
now applies to its subtasks
 Must travel before do-lecture
prepare-lecture()
travel (home, liu)
do-lecture()
 So we have:
prepare-lecture()
buy-ticket (home, liu)
travel (home, b(home))
do-lecture()
go(b(home), b(liu))
travel (b(liu), liu)
jonkv@ida
The Delta Function (5)

59
And: The method itself can have preconditions
 We have tested the preconditions, and they hold
 We must make sure they still hold when the first subtask is executed
prepare-lecture()
do-lecture()
bus-travel
buy-ticket (home, liu)

travel (home, b(home))
go(b(home), b(liu))
travel (b(liu), liu)
Must do u’s first subtask before the first subtask of every ti ≠ u
 The first subtask of bus-travel
before the first subtask of prepare-lecture
jonkv@ida
The Delta Function (6)

60
Which subtask of bus-travel is first?
 Partially ordered  several alternatives!
 So δ creates one alternative for each possible “first” subtask of u
▪ Here, buy-ticket or travel (x, b(x))
▪ Then we nondeterministically choose between these alternatives
prepare-lecture()
buy-ticket (home, liu)
travel (home, b(home))
go(b(home), b(liu))
prepare-lecture()
buy-ticket (home, liu)
travel (home, b(home))
go(b(home), b(liu))
do-lecture()
travel (b(liu), liu)
do-lecture()
travel (b(liu), liu)
jonkv@ida
The Delta Function (7)

Note that only methods are partially ordered
 The problem specification does not have to define
the exact execution order in advance

The final plan is totally ordered!
 The planner chooses an order
61
jonkv@ida
Partially Ordered Methods
Any classical problem
Polynomial-time
transformation
63
Corresponding
STN problem
For some STN problems,
there exists no classical problem with the same set of solutions!
Even Simple Task Networks
are strictly more expressive than classical planning
jonkv@ida
Comparison to Classical Planning

64
Artificial example:
 Two primitive tasks, a and b
 Two STN methods:
a
aNbN
aNbN
continue()
terminate()
aNbN
b
 s0 = {}
 Initial task:
aNbN
a
b
jonkv@ida
Comparison to Classical Planning

65
Possible solutions:
 {anbn | n > 0}
 No classical problem has this set of solutions!
▪ Corresponds to a finite-state automaton,
which cannot recognize {anbn | n > 0}
▪ STNs can even express undecidable problems
aNbN
aNbN
continue()
a
aNbN
continue()
a
aNbN
a
continue()
aNbN
b
a
aNbN
terminate()
terminate()
b
a
b
b
terminate()
b
a
b
jonkv@ida
Comparison to Classical Planning
Download