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 – 2016

2
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
4
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
5
jonkv@ida
Terminology 2: Non-Primitive Task

6
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
7
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)
8
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)

9
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

10
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)

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

11
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:
<travel(home,work); do-work(); travel(work,home)>

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
12
jonkv@ida
Domains, Problems, Solutions
A simple "template expansion"

14
Let’s switch to Dock Worker Robots…
c3
c1
p1
p2
loc1
jonkv@ida
DWR

15
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

16
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)
Iteration with no predetermined bound

18
How can we implement the task move-stack(pile1, pile2)?
 Should move all containers in a stack
 There is no limit on how many there might be…
A
B
C
top(A, pile1)
on(A,B)
on(B,C)
on(C,pallet)
C
B
A
top(A, pile2)
on(C,B)
on(B,A)
on(A,pallet)
jonkv@ida
Moving a Stack of Containers

19
We need a loop with a termination condition
 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)

20
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"
What if the pallet is "topmost"?
We don't want to move it!
jonkv@ida
Recursion (2)

To fix this:
21
Add two method params –
"non-natural", as in "ordinary" planning;
does not give the planner a real choice
 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)

22
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)

23
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)

24
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)
Letting the planner choose parameters

26
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
Moving Stacks (1)

27
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
Moving Stacks (2)

28
Example: We choose an intermediate pile
 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
Moving Stacks (3): We choose intermediate

29
jonkv@ida
Moving Stacks (4): Planner Chooses
Example: The planner chooses intermediate piles
 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) >
Why do the intermediate piles have to be empty initially?
Because the second move-stack moves all containers from the intermediate pile…
Modeling "conditional" actions

Delivery:
 A single truck
 Pick up a package, drive to its destination, unload
 Task:
▪ method:
▪ precond:
▪ subtasks:
deliver(package, dest)
move(package, packageloc, dest)
at(package, packageloc)
<driveto(packageloc), load(package),
driveto(dest), unload(package)>
What if the truck is already at the package location?
First driveto is unnecessary!
31
jonkv@ida
Delivery 1: First Variation

Alternative: Two alternative methods for deliver
 Task:
▪ method:
▪ precond:
deliver(package, dest)
 Task:
▪ method:
▪ precond:
deliver(package, dest)
move1(package, packageloc, truckloc, dest)
at(truck, truckloc), at(package, packageloc),
packageloc = truckloc
▪ subtasks: <load(package), driveto(dest), unload(package)>
▪ subtasks:
move2(package, packageloc, truckloc, dest)
at(truck, truckloc), at(package, packageloc),
packageloc != truckloc
<driveto(packageloc),
load(package), driveto(dest), unload(package)>
Do we really have to repeat the entire task?
Many "conditional" subtasks  combinatorial explosion
32
jonkv@ida
Delivery 2: Second Variation

33
Make the choice in the subtask instead!
 Task:
▪ method:
▪ precond:
▪ subtasks:
deliver(package, dest)
 Task:
▪ method:
▪ precond:
▪ subtasks:
be-at(loc)
 Task:
▪ method:
▪ precond:
▪ subtasks:
be-at(loc)
move1(package, packageloc, truckloc, dest)
at(truck, truckloc), at(package, packageloc)
<be-at(packageloc), load(package), be-at(dest), unload(package)>
drive(loc)
!at(truck,loc)
<driveto(loc)>
already-there
at(truck,loc)
<>
jonkv@ida
Delivery 3: Third variation

Total Order Forward Decomposition:
s0
35
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

36
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
37
jonkv@ida
Solving Total-Order STN Problems (1)
38
 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
▪
▪
39
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)
40
 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)
41
 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)
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
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)
43
 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)

45
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

46
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
47
jonkv@ida
Alternative Methods

49
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.

50
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

51
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
52
jonkv@ida
Solving Partial-Order STN Problems (1)
53
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 σ(u) 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.π
54
 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) = σ(u) 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)

55
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)

56
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)

57
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))
bus(b(x), b(y))
travel (b(y), y)
jonkv@ida
The Delta Function (3)

58
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)

59
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)

60
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)

61
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
62
jonkv@ida
Partially Ordered Methods

Control Rules or Hierarchical Task Networks?
 Both can be very efficient and expressive
 If you have ”recipes” for everything, HTN can be more convenient
▪ Can be modeled with control rules, but not intended for this purpose
▪ You have to forbid everything that is ”outside” the recipe
 If you have knowledge about ”some things that shouldn’t be done”:
▪ With control rules, the default is to ”try everything”
▪ Can more easily express localized knowledge
about what should and shouldn’t be done
▪ Doesn’t require knowledge of all the ways in which the goal can be reached
64
jonkv@ida
Conclusion
Download