Skip to content

Commit 77f97c9

Browse files
committed
Document extension interfaces.
1 parent bb8cf9c commit 77f97c9

File tree

6 files changed

+228
-8
lines changed

6 files changed

+228
-8
lines changed

docs/make.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ makedocs(
1414
"Tutorials" => [
1515
"tutorials/getting_started.md",
1616
"tutorials/writing_planners.md",
17-
"tutorials/speeding_up.md",
18-
"tutorials/extending.md"
17+
"tutorials/speeding_up.md"
1918
],
2019
"Reference" => [
2120
"ref/overview.md",
@@ -25,6 +24,7 @@ makedocs(
2524
"ref/interpreter.md",
2625
"ref/compiler.md",
2726
"ref/absint.md",
27+
"ref/extensions.md",
2828
"ref/utilities.md"
2929
]
3030
]

docs/src/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ Learn how to install and use PDDL.jl by following these tutorials:
2121
Pages = [
2222
"tutorials/getting_started.md",
2323
"tutorials/writing_planners.md",
24-
"tutorials/speeding_up.md",
25-
"tutorials/extending.md"
24+
"tutorials/speeding_up.md"
2625
]
2726
Depth = 1
2827
```
@@ -40,6 +39,7 @@ Pages = [
4039
"ref/interpreter.md",
4140
"ref/compiler.md",
4241
"ref/absint.md",
42+
"ref/extensions.md",
4343
"ref/utilities.md"
4444
]
4545
Depth = 1

docs/src/ref/absint.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,11 @@ PDDL.BooleanAbs
2929
PDDL.IntervalAbs
3030
PDDL.SetAbs
3131
```
32+
33+
When introducing a new global datatype using the PDDL.jl extension interfaces, a default abstraction can be associated with the type by defining a new method for [`PDDL.default_abstype`](@ref):
34+
35+
```@docs
36+
PDDL.default_abstype
37+
```
38+
39+
The [`PDDL.@register`](@ref) macro can also be used to register new default abstractions.

docs/src/ref/extensions.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# Extension Interfaces
2+
3+
PDDL.jl provides a set of extension interfaces for adding new global predicates, functions, and types. Extensions can be added on a per-predicate or per-function basis, or by registering *theories* that provide a class of related functionality.
4+
5+
## Built-in Types, Predicates and Functions
6+
7+
PDDL.jl stores mappings from (global) names to their implementations by making use of [value-based dispatch](https://github.com/ztangent/ValSplit.jl). These mappings are stored by defining methods for the following functions:
8+
9+
```@docs
10+
PDDL.datatype_def
11+
PDDL.predicate_def
12+
PDDL.function_def
13+
PDDL.modifier_def
14+
```
15+
16+
These mappings can also be accessed in dictionary form with the following utility functions:
17+
18+
```@docs
19+
PDDL.global_datatypes()
20+
PDDL.global_predicates()
21+
PDDL.global_functions()
22+
PDDL.global_modifiers()
23+
```
24+
25+
### Datatypes
26+
27+
By default, PDDL.jl supports fluents with Boolean and numeric values. These correspond to the PDDL datatypes named `boolean`, `integer`, `number` and `numeric`, and are implemented in Julia with the `Bool`, `Int` and `Float64` types:
28+
29+
```julia
30+
PDDL.datatype_def(::Val{:boolean}) = (type=Bool, default=false)
31+
PDDL.datatype_def(::Val{:integer}) = (type=Int, default=0)
32+
PDDL.datatype_def(::Val{:number}) = (type=Float64, default=1.0)
33+
PDDL.datatype_def(::Val{:numeric}) = (type=Float64, default=1.0)
34+
```
35+
36+
When declaring a function in a PDDL domain, it is possible to denote its (output) type as one of the aforementioned types. For example, the `distance` between two cities might be declared to have a `number` type:
37+
38+
```pddl
39+
(distance ?c1 - city ?c2 - city) - number
40+
```
41+
42+
### Predicates and Functions
43+
44+
PDDL.jl also supports built-in predicates and functions for comparisons and arithmetic operations. Since these functions can be used in any PDDL domain, they are called *global* functions. Global predicates and functions are implemented by mapping them to Julia functions:
45+
46+
```julia
47+
# Built-in predicates
48+
PDDL.predicate_def(::Val{:(==)}) = PDDL.equiv
49+
PDDL.predicate_def(::Val{:<=}) = <=
50+
PDDL.predicate_def(::Val{:>=}) = >=
51+
PDDL.predicate_def(::Val{:<}) = <
52+
PDDL.predicate_def(::Val{:>}) = >
53+
54+
# Built-in functions
55+
PDDL.function_def(::Val{:+}) = +
56+
PDDL.function_def(::Val{:-}) = -
57+
PDDL.function_def(::Val{:*}) = *
58+
PDDL.function_def(::Val{:/}) = /
59+
```
60+
61+
### Modifiers
62+
63+
Finally, PDDL.jl supports modifier expressions such as `(increase fluent val)`, which modifies the current value of `fluent` by `val`, setting the new value of `fluent` to the modified `value`. Like global functions, modifiers are implemented by mapping their names to corresponding Julia functions:
64+
65+
```julia
66+
PDDL.modifier_def(::Val{:increase}) = :+
67+
PDDL.modifier_def(::Val{:decrease}) = :-
68+
PDDL.modifier_def(::Val{Symbol("scale-up")}) = :*
69+
PDDL.modifier_def(::Val{Symbol("scale-down")}) = :/
70+
```
71+
72+
## Adding Types, Predicates and Functions
73+
74+
To add a new global datatype, predicate, function, or modifier to PDDL, it is enough to define a new method of [`PDDL.datatype_def`](@ref), [`PDDL.predicate_def`](@ref), [`PDDL.function_def`](@ref), or [`PDDL.modifier_def`](@ref) respectively. Alternatively, one can use the [`@register`](@ref) macro to register new implementations at compile-time:
75+
76+
```@docs
77+
PDDL.@register
78+
```
79+
80+
In scripting contexts, run-time registration and de-registration can be achieved using [`PDDL.register!`](@ref) and [`PDDL.deregister!`](@ref):
81+
82+
```@docs
83+
PDDL.register!
84+
PDDL.deregister!
85+
```
86+
87+
## Defining and Registering Theories
88+
89+
Similar to [Satisfiability Modulo Theories (SMT) solvers](https://en.wikipedia.org/wiki/Satisfiability_modulo_theories), PDDL.jl provides support for [*planning* modulo theories](https://dl.acm.org/doi/10.5555/3038546.3038555). By registering a new theory, developers can extend the semantics of PDDL to handle new mathematical objects such as sets, arrays, and tuples.
90+
91+
A new theory can be implemented by writing a (sub)module annotated with the [`@pddltheory`](@ref) macro:
92+
93+
```@docs
94+
@pddltheory
95+
```
96+
97+
For example, a theory for how to handle sets of PDDL objects can be written as follows (adapting the example by [Gregory et al (2012)](https://dl.acm.org/doi/10.5555/3038546.3038555)):
98+
99+
```julia
100+
@pddltheory module Sets
101+
102+
using PDDL
103+
using PDDL: SetAbs
104+
105+
construct_set(xs::Symbol...) = Set{Symbol}(xs)
106+
empty_set() = Set{Symbol}()
107+
cardinality(s::Set) = length(s)
108+
member(s::Set, x) = in(x, s)
109+
subset(x::Set, y::Set) = issubset(x, y)
110+
union(x::Set, y::Set) = Base.union(x, y)
111+
intersect(x::Set, y::Set) = Base.intersect(x, y)
112+
difference(x::Set, y::Set) = setdiff(x, y)
113+
add_element(s::Set, x) = push!(copy(s), x)
114+
rem_element(s::Set, x) = pop!(copy(s), x)
115+
116+
set_to_term(s::Set) = isempty(s) ? Const(Symbol("(empty-set)")) :
117+
Compound(Symbol("construct-set"), PDDL.val_to_term.(collect(s)))
118+
119+
const DATATYPES = Dict(
120+
"set" => (type=Set{Symbol}, default=Set{Symbol}())
121+
)
122+
123+
const ABSTRACTIONS = Dict(
124+
"set" => SetAbs{Set{Symbol}}
125+
)
126+
127+
const CONVERTERS = Dict(
128+
"set" => set_to_term
129+
)
130+
131+
const PREDICATES = Dict(
132+
"member" => member,
133+
"subset" => subset
134+
)
135+
136+
const FUNCTIONS = Dict(
137+
"construct-set" => construct_set,
138+
"empty-set" => empty_set,
139+
"cardinality" => cardinality,
140+
"union" => union,
141+
"intersect" => intersect,
142+
"difference" => difference,
143+
"add-element" => add_element,
144+
"rem-element" => rem_element
145+
)
146+
147+
end
148+
```
149+
150+
This theory introduces a new PDDL type called `set`, implemented as the Julia datatype `Set{Symbol}`. Sets can be modified with functions such as `union` or `add-element`, and can also serve as arguments to predicates like `subset`. The default abstraction for a set is specified to be a [`SetAbs`](@ref), which means that the abstract interpreter will use a set of sets to represent the abstract value of a set-valued variable.
151+
152+
After defining a new theory, we can *register* it by calling the `@register` macro for that module, and make use of the new functionality in PDDL domains and problems:
153+
154+
```julia
155+
Sets.@register()
156+
157+
domain = pddl"""
158+
(define (domain storytellers)
159+
(:requirements :typing :fluents)
160+
(:types storyteller audience story)
161+
(:functions (known ?t - storyteller) - set
162+
(heard ?a - audience) - set
163+
(story-set) - set
164+
)
165+
(:action entertain
166+
:parameters (?t - storyteller ?a - audience)
167+
:precondition (true)
168+
:effect ((assign (heard ?a) (union (heard ?a) (known ?t))))
169+
)
170+
)
171+
"""
172+
173+
problem = pddl"""
174+
(define (problem storytellers-problem)
175+
(:domain storytellers)
176+
(:objects
177+
jacob wilhelm - storyteller
178+
hanau steinau - audience
179+
snowwhite rumpelstiltskin - story
180+
)
181+
(:init
182+
(= (story-set) (construct-set snowwhite rumpelstiltskin))
183+
(= (known jacob) (construct-set snowwhite))
184+
(= (known wilhelm) (construct-set rumpelstiltskin))
185+
(= (heard hanau) (empty-set))
186+
(= (heard steinau) (empty-set))
187+
)
188+
(:goal (and
189+
; both audiences must hear all stories
190+
(= (heard hanau) (story-set))
191+
(= (heard steinau) (story-set))
192+
))
193+
)
194+
"""
195+
196+
state = initstate(domain, problem)
197+
```
198+
199+
As is the case for registering new predicates and functions, the `@register` macro is preferred whenever packages that depend on PDDL.jl need to be precompiled. However, it is also possible register and deregister theories at runtime with `register!` and `deregister!`:
200+
201+
```julia
202+
Sets.register!()
203+
Sets.deregister!()
204+
```
205+
206+
## Predefined Theories
207+
208+
Alongside the `Sets` example shown above, a theory for handling `Arrays` is predefined as part of PDDL.jl:
209+
210+
```julia
211+
PDDL.Sets
212+
PDDL.Arrays
213+
```
214+
215+
These theories are not registered by default, and should be registered with the `@register` macro before use.

docs/src/ref/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ Given this interface-centered design, PDDL.jl itself does not include any applic
3737

3838
## Other Components
3939

40-
In addition to implementations of its interface, PDDL.jl also provides a PDDL [**parser**](parser_writer.md#General-Parsing), [**writer**](parser_writer.md#General-Writing), and a set of [**utilities**](utilities.md) to help analyze and work with PDDL domains. Collectively, these components allow researchers, developers, and engineers to use symbolic planning in a wide variety of application contexts.
40+
In addition to implementations of its interface, PDDL.jl also provides a PDDL [**parser**](parser_writer.md#General-Parsing), [**writer**](parser_writer.md#General-Writing), and a set of [**utilities**](utilities.md) to help analyze and work with PDDL domains. [**Extension interfaces**](extensions.md) also make it easier to support new functionality in PDDL.jl. Collectively, these components allow researchers, developers, and engineers to use symbolic planning in a wide variety of application contexts.

docs/src/tutorials/extending.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)