Automated Planning and PDDL

What is Planning?#

Planning is the art and practice of thinking before acting. - Patrik Haslum

“Planning” is the name used in AI for computational problems that have to do with choosing a course of action. This may be for the purpose of creating a “plan”, e.g., for a pair of robots to assemble a (simulated) IKEA table, for moving a sheet of paper through a printer, or exploiting IT security weaknesses. However, problems like model checking or computing genome edit distance are, in a computational sense, essentially the same.1

Planning Domain Description Language#

PDDL was originally developed by Drew McDermott and the 1998 planning competition committee. It was inspired by the need to encourage the empirical comparison of planning systems and the exchange of planning benchmarks within the community. Its development improved the communication of research results and triggered an explosion in performance, expressivity and robustness of planning systems.

PDDL has become a de facto standard language for describing planning domains, not only for the competition but more widely, as it offers an opportunity to carry out empirical evaluation of planning systems on a growing collection of generally adopted standard benchmark domains. The emergence of a language standard will have an impact on the entire field, influencing what is seen as central and what peripheral in the development of planning systems.

  • Used by almost all implemented systems for deterministic planning
  • Supports a language comparable to what we have defined above (including schematic operators and quantification)
  • Syntax inspired by the Lisp programming language: e.g. prefix notation for formulae

Example: Rock Collecting Rover#

There are several waypoints on the planet, some of which are connected. A rover can navigate between two waypoints A and B when A and B are connected. Interesting rocks can be found at any waypoint.

The rover can only analyze the rocks of a waypoint when it is at the waypoint. After the rover has analyzed a rock sample, it can transmit the results of this particular analysis to Earth. The transmission of the results of analysed rock samples can only be carried out at certain waypoints where the connection to Earth is good enough.

Each result is to be transferred via an individual action.

All actions have unit costs.

The goal is to analyze all rock samples and transfer the results to Earth.

Rover Path Diagram

Domain file#

A domain file consists of:2

  • (define (domain DOMAINNAME)
  • a :requirements definition (use :strips :typing by default)
  • definitions of types (each parameter has a type)
  • definitions of predicates
  • definitions of operators (actions)
(define (domain roverdomain)
    (:requirements :strips :typing :adl)
    (:types rover dish rock position)
    (:predicates
        (connected ?a ?b - position)
        (has-dish ?a - position)
        (has-rock ?a - position)
        (has-rover ?a - position)
        (occupied)
    )
    
    (:action navigate
        :parameters (?a ?b - position)
        :precondition (and
            (has-rover ?a)
            (connected ?a ?b)
        )
        :effect (and
            (not (has-rover ?a))
            (has-rover ?b)
        )
    )
    
    
    (:action collect
        :parameters (?a - position)
        :precondition (and
            (has-rover ?a)
            (has-rock ?a)
            (not (occupied))
        )
        :effect (and
            (not (has-rock ?a))
            (occupied)
        )
    
    )
    
    (:action transmit
        :parameters (?a - position)
        :precondition (and
            (occupied)
            (has-rover ?a)
            (has-dish ?a)
        )
        
        :effect (and
            (not (occupied))
        )
    )
    
)

Problem file#

A problem file consists of:3

  • (define (problem PROBLEMNAME)
  • declaration of which domain is needed for this problem
  • definitions of objects belonging to each type
  • definition of the initial state (list of state variables initially true)
  • definition of goal states (a formula like operator precondition)
(define (problem roverproblem)
    (:domain roverdomain)
    (:objects
        ; dh - dish
        ; rv - rover
        ; rk - rock
        a b c d e f g - position
    )
    
    (:init 
        (has-dish a)
        (has-rock b)
        (has-rock e)
        (has-rock c)
        (has-rock d)
        (has-rover g)
        
        (connected g f)
        (connected f a)
        (connected a b)
        (connected b g)
        (connected g b)
        (connected b c)
        (connected c b)
        (connected e g)
        (connected g e)
        (connected d e)
        (connected c d)
        (connected d c)

    )
    
    
    (:goal
        ( and
            (not (has-rock a))
            (not (has-rock b))
            (not (has-rock e))
            (not (has-rock c))
            (not (has-rock d))
            (not (occupied))
        )
    )
    
    
)

Fast Downward Planner#

Fast Downward4 is a domain-independent classical planning system.

wget https://github.com/aibasel/downward/archive/release-20.06.0.tar.gz
tar -xvzf release-20.06.0.tar.gz
cd downward-release-20.06.0
./build.py # only once
./fast-downward.py --alias lama-first /path/to/domain.pddl /path/to/problem.pddl
INFO     Running translator.
INFO     translator stdin: None
INFO     translator time limit: None
INFO     translator memory limit: None
INFO     translator command line string: /usr/bin/python3 builds/release/bin/translate/translate.py ../domain.pddl ../problem.pddl --sas-file output.sas
Parsing...
Parsing: [0.000s CPU, 0.001s wall-clock]
Normalizing task... [0.000s CPU, 0.000s wall-clock]
Instantiating...
Generating Datalog program... [0.000s CPU, 0.000s wall-clock]
Normalizing Datalog program...
Trivial rules: Converted to facts.
Normalizing Datalog program: [0.000s CPU, 0.002s wall-clock]
Preparing model... [0.000s CPU, 0.000s wall-clock]
Generated 10 rules.
Computing model... [0.000s CPU, 0.001s wall-clock]
64 relevant atoms
28 auxiliary atoms
92 final queue length
101 total queue pushes
Completing instantiation... [0.000s CPU, 0.001s wall-clock]
Instantiating: [0.000s CPU, 0.005s wall-clock]
Computing fact groups...
Finding invariants...
5 initial candidates
Finding invariants: [0.010s CPU, 0.001s wall-clock]
Checking invariant weight... [0.000s CPU, 0.000s wall-clock]
Instantiating groups... [0.000s CPU, 0.000s wall-clock]
Collecting mutex groups... [0.000s CPU, 0.000s wall-clock]
Choosing groups...
5 uncovered facts
Choosing groups: [0.000s CPU, 0.000s wall-clock]
Building translation key... [0.000s CPU, 0.000s wall-clock]
Computing fact groups: [0.010s CPU, 0.001s wall-clock]
Building STRIPS to SAS dictionary... [0.000s CPU, 0.000s wall-clock]
Building dictionary for full mutex groups... [0.000s CPU, 0.000s wall-clock]
Building mutex information...
Building mutex information: [0.000s CPU, 0.000s wall-clock]
Translating task...
Processing axioms...
Simplifying axioms... [0.000s CPU, 0.000s wall-clock]
Translator axioms removed by simplifying: 0
Computing negative axioms... [0.000s CPU, 0.000s wall-clock]
Processing axioms: [0.000s CPU, 0.000s wall-clock]
Translating task: [0.000s CPU, 0.001s wall-clock]
5 effect conditions simplified
0 implied preconditions added
Detecting unreachable propositions...
0 operators removed
0 axioms removed
1 propositions removed
Detecting unreachable propositions: [0.000s CPU, 0.000s wall-clock]
Reordering and filtering variables...
6 of 6 variables necessary.
0 of 1 mutex groups necessary.
17 of 17 operators necessary.
0 of 0 axiom rules necessary.
Reordering and filtering variables: [0.000s CPU, 0.000s wall-clock]
Translator variables: 6
Translator derived variables: 0
Translator facts: 17
Translator goal facts: 5
Translator mutex groups: 0
Translator total mutex groups size: 0
Translator operators: 17
Translator axioms: 0
Translator task size: 92
Translator peak memory: 26812 KB
Writing output... [0.000s CPU, 0.000s wall-clock]
Done! [0.010s CPU, 0.010s wall-clock]
translate exit code: 0

INFO     Running search (release).
INFO     search stdin: output.sas
INFO     search time limit: None
INFO     search memory limit: None
INFO     search command line string: builds/release/bin/downward --evaluator 'hlm=lmcount(lm_factory=lm_rhw(reasonable_orders=true),transform=adapt_costs(one),pref=false)' --evaluator 'hff=ff(transform=adapt_costs(one))' --search 'lazy_greedy([hff,hlm],preferred=[hff,hlm],cost_type=one,reopen_closed=false)' --internal-plan-file sas_plan < output.sas
[t=4.9308e-05s, 9744 KB] reading input...
[t=0.000295154s, 9744 KB] done reading input!
[t=0.0019288s, 10000 KB] Initializing landmarks count heuristic...
[t=0.00200992s, 10000 KB] Initializing Exploration...
[t=0.00207028s, 10000 KB] Generating landmarks using the RPG/SAS+ approach
approx. reasonable orders
[t=0.00226699s, 10000 KB] approx. obedient reasonable orders
[t=0.00232234s, 10000 KB] Removed 0 reasonable or obedient reasonable orders
[t=0.0024036s, 10000 KB] Landmarks generation time: 0.000434502s
[t=0.00244563s, 10000 KB] Discovered 14 landmarks, of which 0 are disjunctive and 0 are conjunctive.
[t=0.00247662s, 10000 KB] 22 edges
[t=0.0025644s, 10000 KB] Simplifying 21 unary operators... done! [21 unary operators]
[t=0.00263706s, 10000 KB] time to simplify: 0.000104331s
[t=0.00269396s, 10000 KB] Initializing additive heuristic...
[t=0.00272805s, 10000 KB] Initializing FF heuristic...
[t=0.00285032s, 10000 KB] Building successor generator...done!
[t=0.00297551s, 10000 KB] peak memory difference for successor generator creation: 0 KB
[t=0.00300687s, 10000 KB] time for successor generation creation: 1.9058e-05s
[t=0.0030427s, 10000 KB] Variables: 6
[t=0.00307538s, 10000 KB] FactPairs: 17
[t=0.00310553s, 10000 KB] Bytes per state: 4
[t=0.00322581s, 10000 KB] Conducting lazy best first search, (real) bound = 2147483647
[t=0.00330731s, 10000 KB] 6 initial landmarks, 5 goal landmarks
[t=0.00336785s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 8
[t=0.00340958s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 8
[t=0.00344425s, 10000 KB] g=0, 1 evaluated, 0 expanded
[t=0.00348597s, 10000 KB] Initial heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 8
[t=0.00352082s, 10000 KB] Initial heuristic value for ff(transform = adapt_costs(one)): 8
[t=0.00356578s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 7
[t=0.00360315s, 10000 KB] g=1, 2 evaluated, 1 expanded
[t=0.00365184s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 7
[t=0.00369002s, 10000 KB] g=2, 3 evaluated, 2 expanded
[t=0.00378585s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 6
[t=0.00382462s, 10000 KB] g=3, 9 evaluated, 8 expanded
[t=0.00398096s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 5
[t=0.00402012s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 6
[t=0.0040531s, 10000 KB] g=10, 25 evaluated, 24 expanded
[t=0.00413626s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 4
[t=0.00417406s, 10000 KB] g=12, 31 evaluated, 30 expanded
[t=0.00430784s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 5
[t=0.00435535s, 10000 KB] g=17, 43 evaluated, 42 expanded
[t=0.00439819s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 3
[t=0.0044344s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 4
[t=0.00446531s, 10000 KB] g=18, 44 evaluated, 43 expanded
[t=0.00453552s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 2
[t=0.00457285s, 10000 KB] g=21, 49 evaluated, 48 expanded
[t=0.00465162s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 3
[t=0.00468935s, 10000 KB] g=24, 56 evaluated, 55 expanded
[t=0.00473399s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 2
[t=0.00477107s, 10000 KB] g=25, 57 evaluated, 56 expanded
[t=0.00481367s, 10000 KB] New best heuristic value for lmcount(lm_factory = lm_rhw(reasonable_orders = true), transform = adapt_costs(one), pref = false): 1
[t=0.00485071s, 10000 KB] New best heuristic value for ff(transform = adapt_costs(one)): 1
[t=0.00488327s, 10000 KB] g=26, 58 evaluated, 57 expanded
[t=0.00495006s, 10000 KB] Solution found!
[t=0.00498952s, 10000 KB] Actual search time: 0.00167119s
navigate g b (1)
navigate b c (1)
navigate c d (1)
collect d (1)
navigate d e (1)
navigate e g (1)
navigate g f (1)
navigate f a (1)
transmit a (1)
navigate a b (1)
navigate b c (1)
collect c (1)
navigate c b (1)
navigate b g (1)
navigate g f (1)
navigate f a (1)
transmit a (1)
navigate a b (1)
navigate b g (1)
navigate g e (1)
collect e (1)
navigate e g (1)
navigate g f (1)
navigate f a (1)
transmit a (1)
navigate a b (1)
collect b (1)
navigate b g (1)
navigate g f (1)
navigate f a (1)
transmit a (1)
[t=0.00502718s, 10000 KB] Plan length: 31 step(s).
[t=0.00502718s, 10000 KB] Plan cost: 31
[t=0.00502718s, 10000 KB] Expanded 62 state(s).
[t=0.00502718s, 10000 KB] Reopened 0 state(s).
[t=0.00502718s, 10000 KB] Evaluated 63 state(s).
[t=0.00502718s, 10000 KB] Evaluations: 126
[t=0.00502718s, 10000 KB] Generated 125 state(s).
[t=0.00502718s, 10000 KB] Dead ends: 0 state(s).
[t=0.00502718s, 10000 KB] Number of registered states: 63
[t=0.00502718s, 10000 KB] Int hash set load factor: 63/64 = 0.984375
[t=0.00502718s, 10000 KB] Int hash set resizes: 6
[t=0.00502718s, 10000 KB] Search time: 0.00180231s
[t=0.00502718s, 10000 KB] Total time: 0.00502718s
Solution found.
Peak memory: 10000 KB
Remove intermediate file output.sas
search exit code: 0

PDDL4J#

The purpose of PDDL4J5 is to facilitate the development of JAVA tools for Automated Planning based on PDDL language (Planning Domain Description Language). Automated planning and scheduling, in the relevant literature often denoted as simply planning, is a branch of artificial intelligence that concerns the realization of strategies or action sequences, typically for execution by intelligent agents, autonomous robots and unmanned vehicles.[^1]

wget https://github.com/pellierd/pddl4j/releases/download/v3.8.3/PDDL4J-v3.8.3.zip
unzip PDDL4J-v3.8.3.zip
java -jar pddl4j-3.8.3.jar -p 0 -o domain.pddl -f problem.pddl
  • -p 0 for HSP (default planner)
  • -p 1 for FF
parsing domain file "domain.pddl" done successfully
parsing problem file "problem.pddl" done successfully

encoding problem done successfully (17 ops, 12 facts)
* starting A*
* A* succeeded

found plan as follows:

00: (navigate g e) [1]
01: (   collect e) [1]
02: (navigate e g) [1]
03: (navigate g f) [1]
04: (navigate f a) [1]
05: (  transmit a) [1]
06: (navigate a b) [1]
07: (navigate b c) [1]
08: (   collect c) [1]
09: (navigate c b) [1]
10: (navigate b g) [1]
11: (navigate g f) [1]
12: (navigate f a) [1]
13: (  transmit a) [1]
14: (navigate a b) [1]
15: (   collect b) [1]
16: (navigate b g) [1]
17: (navigate g f) [1]
18: (navigate f a) [1]
19: (  transmit a) [1]
20: (navigate a b) [1]
21: (navigate b c) [1]
22: (navigate c d) [1]
23: (   collect d) [1]
24: (navigate d e) [1]
25: (navigate e g) [1]
26: (navigate g f) [1]
27: (navigate f a) [1]
28: (  transmit a) [1]

plan total cost: 29.00


time spent:       0.11 seconds parsing 
                  0.05 seconds encoding 
                  0.05 seconds searching
                  0.20 seconds total time

memory used:     -0.00 MBytes for problem representation
                 -0.00 MBytes for searching
                 -0.00 MBytes total

Online Planner#

PDDL Editor#

editor.planning.domains6 is a fully featured PDDL editor. The functionality is continually changing, but currently it boasts features such as syntax highlighting, code folding, PDDL-specific auto-completion, multi-tab support, etc.

f Describe domain and problem in PDDL

You can switch the default satisfactory solver with an optimal solver by simply replacing the Custom Planner URL with http://fd-solver.herokuapp.com.

Solve Button

If everything goes fine, you can find the plan in a new file on the left panel.

Plan found in the left panel

GUI Planner#

PDDL4GUI#

PDDL4GUI7 is a small application written in Java that provides a graphical interface to the PDDL4J library. PDDL4GUI offers:

  • A graphical interface for solving planning problems with the PDDL4J library.
  • A graphical interface for solving planning problems through PDDL4J webservice and RESTFull API.
  • Anytime behavior for compatible planners.
  • The integration of VAL (The plan validation system) which offers the possibility to test the validity of the plans provided by PDDL4J.

After cloning the git repository, simply run java -javaagent:pddl4gui-1.0.jar -server -Xms2048m -Xmx2048m -jar pddl4gui-1.0.jar -LOCAL or run the provided shell script ./pddl4gui_loc.sh.

Overview of PDDL4GUI

Resources#


  1. Patrik Haslum @ ANU ↩︎

  2. Principles of AI Planning - domain files ↩︎

  3. Principles of AI Planning - problem files ↩︎

  4. Downward Planner Git Repository ↩︎

  5. PDDL4J Git Repository ↩︎

  6. PDDL Editor ↩︎

  7. PDDL4GUI Git Repository ↩︎