PDDL basic¶
TDDC17这是好的PDDL简介入门内容,这个也很好 在PDDL中编写计划领域和问题
PDDL问题定义的各个部分。
基本包括domain.pddl+problemX.pddl两个文件,虽然可以写在一个文件中,但是大多数计划人员都要求这两部分位于单独的文件中。
domain¶
The format of a (simple) domain definition is:
(define (domain DOMAIN_NAME)
(:requirements [:strips] [:equality] [:typing] [:adl])
(:predicates (PREDICATE_1_NAME ?A1 ?A2 ... ?AN)
(PREDICATE_2_NAME ?A1 ?A2 ... ?AN)
...)
(:action ACTION_1_NAME
[:parameters (?P1 ?P2 ... ?PN)]
[:precondition PRECOND_FORMULA]
[:effect EFFECT_FORMULA]
)
(:action ACTION_2_NAME
...)
...)
[]中的元素是可选的。
名称(域,谓词,动作*等*)通常由字母数字字符,连字符(“ -
”)和下划线(“ _
”)组成,但可能有些计划者不允许使用。
谓词和操作的参数通过以问号(“?”)开头来区分。
谓词声明(:predicates
部分)中使用的参数除指定谓词应具有的参数数量外没有其他功能,*即*参数名称无关紧要(只要它们是不同的)。谓词可以具有零个参数(但在这种情况下,谓词名称仍必须写在括号内)。
除了特殊谓词=之外
,域定义中的谓词*没有内在含义*。域定义的:predicates
部分仅指定域中使用的谓词名称及其参数数量(如果域使用键入,则为参数类型)。谓词的“含义”在某种意义上可以是正确的参数组合以及它与其他谓词的关系,是由域中的动作可以对谓词产生的影响以及谓词的哪些实例决定的在问题定义的初始状态中,谓词被列为true。
在*静态*谓词和 *动态*谓词之间进行区分是很常见的:静态谓词不会因任何操作而改变。因此,在问题中,静态谓词的正确和错误实例将始终恰好是问题定义的初始状态规范中列出的那些实例。请注意,PDDL中的静态和动态谓词在语法上没有区别:它们在域的:predicates
声明部分看起来完全相同。但是,某些计划者可能会围绕静态和动态谓词支持不同的构造,例如,允许将静态谓词否定为动作前提,而不是动态谓词。
根据PDDL规范,除了名称之外,动作定义的所有部分都是可选的(尽管如此,没有效果的动作几乎没有用)。但是,对于没有先决条件的操作,某些计划人员可能需要使用:precondition()
或:precondition(and)
形式的“空”前提 条件
,而某些计划人员也可能要求针对没有参数的操作使用空的:parameter
列表。注意:一些计划者要求操作的参数都不同,即同一对象不能实例化两个参数。如果一个人不知道,可能会造成一些困难(*例如,*问题变得无法解决)。
:requirements¶
version 2.1相关requirement
Requirement Description
:strips Basic STRIPS style adds and deletes
:typing Allow type names in declarations of variables
:disjunctive-preconditions Allow or in goal descriptions
:equality Support=as built-in predicate
:existential-preconditions Allow exists in goal descriptions
:universal-preconditions Allow forall in goal descriptions
:quantified-preconditions =:existential-preconditions
+:universal-preconditions
:conditional-effects Allow when in action effects
:action-expansions Allow actions to have expansions
:foreach-expansions Allow actions expansions to use foreach implies :action-expansions
:dag-expansions Allow labeled subactions implies :action-expansions
:domain-axioms Allow domains to have axioms
:subgoal-through-axioms Given axioms p \supset q and goal q generate subgoal p
:safety-constraints Allow safety conditions for a domain
:expression-evaluation Supportevalpredicateinaxioms implies :domain-axioms
:fluents Support type fluentt Implies:expression-evaluation
:open-world Don't make the closed-world assumption forall predicates i.e. if an atomic formula is not known to be true it is not necessarily assumed false
:true-negation Don't handle not using negation as failure but treat it as in first-order logic implies:open-world
:adl =:strips+typing
+:disjunctive-preconditions"
+:equality
+:quantified-preconditions"
+:conditional-effects
:ucpop! =:adl"
+:domain-axioms"
+:safety-constraints
The most commonly used requirements are:
:strips
The most basic subset of PDDL, consisting of STRIPS only.
:equality
The domain uses the predicate =
, interpreted as equality.
:typing
The domain uses object types (see below).
:adl
The domain uses some or all of ADL (i.e. disjunctions and quantifiers in preconditions and goals, and quantified and conditional effects).
大部分solvers仅仅支持部分特性进行parser进而逻辑处理求解,自定义特性关键字只需要:mineKeyWords
自定义修改parser处理这部分requirements并且定义(myfeatures ...)
进行解析输入处理。严谨的PDDL版本迭代规范看前文IPC的文档,具体问题具体分析,下面说些比较通用的:
:typing
PDDL具有(非常)特殊的语法,用于声明参数和对象类型。如果要在域中使用类型,则域首先应声明要求:typing。
其次,必须在使用类型名称之前声明它们(通常是在:predicates 声明之前)。这是通过声明完成的
(:types NAME1 ... NAME_N) 然后,要声明谓词或操作的参数类型,可以写?X-TYPE_OF_X。相同类型的参数列表可以缩写为?X?Y?Z-TYPE_OF_XYZ。请注意,参数和类型名称之间的连字符必须是“独立的”,即被空白包围。
在问题定义中声明对象类型的语法相同
universally quantified
(forall (?v1 ... ?vn)<effect>)
conditional:
(when<condition><effect>)
Example on the web: crazy-switches.pddl
类型定义¶
在大多数当前的计划人员中,可以将对象声明为具有特定类型,例如“容器”,“位置”,“车辆”等。如果要在域中使用对象类型,则域首先应声明要求:typing
。
所有类型名称都必须在使用前声明(通常是在:predicates
声明之前)。这是通过以下声明完成的:
(:types NAME1 ... NAME_N)
Dock Worker机器人域的示例:
(define (domain dock-worker-robots)
(:requirements
:strips
:typing )
(:types
location ; there are several connected locations in the harbor
pile ; attached to a location, holds a pallet + a stack of containers
robot ; holds at most 1 container, only 1 robot per location
crane ; belongs to a location to pickup containers
container)
)
在讨论谓词定义,动作定义和对象规范时,我们将返回对象类型。
谓词定义¶
在:predicates下
,您定义要在域中使用的所有谓词(“布尔状态变量”)。每个谓词声明中使用的参数变量除了指定谓词应具有的参数数量外没有其他功能,*即*参数名称无关紧要(只要它们是不同的)。谓词可以具有零个参数(但在这种情况下,谓词名称仍必须写在括号内)。
如果要使用类型化的参数,则每个参数都写为 ?X-TYPE_OF_X
。相同类型的参数列表可以缩写为?X?Y?Z-TYPE_OF_XYZ
。请注意,参数和类型名称之间的连字符必须由空格包围。Dock Worker机器人域的示例:
(define (domain dock-worker-robots)
(:requirements ...)
(:types ...)
(:predicates
(adjacent ?l1 ?l2 - location) ; can move from ?l1 directly to ?l2
(attached ?p - pile ?l - location) ; pile ?p attached to location ?l
(belong ?k - crane ?l - location) ; crane ?k belongs to location ?l
(at ?r - robot ?l - location) ; robot ?r is at location ?l
(occupied ?l - location) ; there is a robot at location ?l
(loaded ?r - robot ?c - container ) ; robot ?r is loaded with container ?c
(unloaded ?r - robot) ; robot ?r has no cargo
(holding ?k - crane ?c - container) ; crane ?k is holding container ?c
(empty ?k - crane) ; crane ?k is not holding anything
(in ?c - container ?p - pile) ; container ?c is somewhere in pile ?p
(top ?c - container ?p - pile) ; container ?c is on top of pile ?p
(on ?k1 ?k2 - container ) ; container ?k1 is on container ?k2
)
动作定义¶
如上所示,通常将操作指定如下:
(:action ACTION_1_NAME
[:parameters (?P1 ?P2 ... ?PN)]
[:precondition PRECOND_FORMULA]
[:effect EFFECT_FORMULA]
)
根据规范,除了名称之外,动作定义的所有部分都是可选的(尽管如此,没有效果的动作几乎没有用)。但是,对于没有先决条件的操作,某些计划人员可能需要使用:precondition()
形式的“空”前提条件
(某些计划人员对于不带参数的操作可能也需要空的:parameter
列表)。**注意:**一些solver要求操作的参数都不同,*即*同一对象不能实例化两个参数。如果一个人不知道,可能会造成一些困难(*例如,*问题变得无法解决)。例子:
(define (domain dock-worker-robots)
...
(:action move
:parameters (?r - robot ?from ?to - location)
:precondition (and (adjacent ?from ?to)
(at ?r ?from)
(not (occupied ?to)))
:effect (and (at ?r ?to) (not (occupied ?from))
(occupied ?to) (not (at ?r ?from))
)
)
参数类型的声明方式与谓词规范中的声明方式相同。这样可以确保计划人员不要尝试使用意外的对象类型来执行操作。例如,在Dock Worker机器人中,我们不希望起重机能够举起机器人并将其放在一堆容器的顶部。起重机只能起吊集装箱。
**注意:**有些计划人员仅尝试在所有参数都不同的情况下应用操作,*即*不能将同一对象用作同一动作的两个不同参数的值。这样的计划者可能会使用诸如move(A,B)和move(B,A)之类的动作,但不会将move(A,A)或move(B,B)视为有效动作。在此特定示例中,禁止从一个位置移动到相同位置似乎是很合理的,但是对于其他动作,可能会带来一些困难。例如考虑动作moveto(?piece,?destcolumn,?destrow)。如果我们用常数A / B / C / D / E / F / G / H表示列和行,则这里讨论的类型的计划器将永远不会使用诸如moveto(bishop1,A,A)之类的动作。或moveto(pawn2,C,C),使其无法移动到对角线上的某个位置,并使某些问题无法解决。请参阅SlideTile域定义以及两个问题的定义eight01.pddl
和eight01x.pddl
,以作为此问题及其解决方案的示例。
前提条件公式¶
在**STRIPS**域中,前提条件公式可以是以下条件之一(另请参见上面的示例):
- 原子公式:
(PREDICATE_NAME ARG1 ... ARG_N)
predicate arguments必须是操作的参数(或域中声明的 constants,如果域具有 constants)。 - 原子公式的结合:
(and ATOM1 ... ATOM_N)
如果域使用:adl
或:negated-precondition
,则原子公式也可以采用以下形式(不是(PREDICATE_NAME ARG1 ... ARG_N))
,表示给定的事实必须为false。
如果域使用:equality
,则原子公式也可以采用(= ARG1 ARG2)
的形式 。许多支持equality的solvers也允许使用否定的相等性,即书面形式(not(= ARG1 ARG2))
,即使他们不允许在definition的任何其他部分中进行negation也是如此。
在用:adl
指定的**ADL**域中,前提还可以是:
- 一般的否定,合取,析取或逻辑蕴含A general negation, conjunction, disjunction, or implication:
(not CONDITION_FORMULA)
(and CONDITION_FORMULA1 ... CONDITION_FORMULA_N)
(or CONDITION_FORMULA1 ... CONDITION_FORMULA_N)
(imply CONDITION_FORMULA1 CONDITION_FORMULA_2)
- 量化公式quantified formula:
(forall(?V1?V2 ...)CONDITION_FORMULA)
(exists(?V1?V2 ...)CONDITION_FORMULA)
效果公式¶
在PDDL中,不像其他某些计划语言那样将操作的效果明确地分为“adds添加”和“deletes删除”。取而代之的是,使用否定运算符negation operator指定负面影响(删除)negative effects (deletes)。
在**STRIPS**域中,效果公式可能包含以下内容(另请参见上面的示例):
- An added atom:
(PREDICATE_NAME ARG1 ... ARG_N)
谓词参数必须是操作的参数(或域中声明的常量,如果域具有常量)。 - A deleted atom:(
不是(PREDICATE_NAME ARG1 ... ARG_N))
- A conjunction of effects效果的合取:(
和ATOM1 ... ATOM_N)
当然,等式谓词(=
)不能出现在效果公式中;任何动作都不能使两个相同的事物变得不相同,反之亦然!
在**ADL**域中,效果公式还可以包含:
- 条件效果:
(when CONDITION_FORMULA EFFECT_FORMULA)
解释为,只有在执行动作的状态下指定的条件公式为true时,才会发生指定的效果。条件效应通常但并非总是置于量词之内。 - 通用量化公式:
(forall(?V1?V2 ...)EFFECT_FORMULA)
problem¶
问题定义首先指定其名称和所属的域。然后,它指定问题实例中存在的对象,世界的初始状态和目标。
(简单的)问题定义的格式为:
(define (problem PROBLEM_NAME)
(:domain DOMAIN_NAME)
(:objects OBJ1 OBJ2 ... OBJ_N)
(:init ATOM1 ATOM2 ... ATOM_N)
(:goal CONDITION_FORMULA)
)
The object list can be typed or untyped. Dock Worker机器人的一个示例:
(define (problem dwr-problem-1)
(:domain dock-worker-robots)
(:objects
r1 - robot
loc1 loc2 - location
k1 - crane
p1 p2 - pile
c1 c2 c3 pallet - container)
...
)
初始状态描述(:init
部分)只是所有在初始状态下为true的 a list of all the ground (variable-free) atoms 。 All other没写出来的 atoms are by definition false.例如:
(define (problem dwr-problem-1)
(:domain dock-worker-robots)
(:objects ...)
(:init
(attached p1 loc1) (in c1 p1) (on c1 pallet) (in c3 p1) (on c3 c1) (top c3 p1)
(attached p2 loc1) (in c2 p2) (on c2 pallet) (top c2 p2)
(belong crane1 loc1) (empty crane1)
(at r1 loc2) (unloaded r1) (occupied loc2)
(adjacent loc1 loc2) (adjacent loc2 loc1)
)
)
目标描述不是状态或文字列表,而是表示为 a formula of the same form as an action precondition。例子:
(define (problem dwr-problem-1)
(:domain dock-worker-robots)
(:objects ...)
(:init ...)
(:goal (and (in c1 p2) (in c3 p2))))
Plan Quality Criterion¶
就像是我要用planning学习一段程序,怎么评价很多种规划解中我找到的程序写法是好是坏?递归总是很短,但是时间效率不一定高。Linked list Domain链表类似于声明临时指针数量不是越多越好的,因为时序关系经常迭代用同一个寄存器指针暂时缓存pre cur next的对象位置,进而实现迭代器的作用,比如for(int i =0;i<n;i++)就能看做i是数组的迭代器指针类似物,临时缓存寄存器指针。
PDDL的最新版本具有一种机制,用于表达计划者应尝试优化的计划质量度量。但是,大多数计划者只会优化一个特定的度量标准,而许多计划者根本不会尝试进行任何优化(只是尽可能快地找到任何计划)。
Sum of Action Costs¶
为了指定行动成本,有必要添加一个“fluent”来跟踪成本。A fluent就像state variable/predicate,但其值为number而不是true/false。同样,请注意,PDDL‘s fluent syntax 非常有表现力,并且most planners will only accept a limited use.
To declare fluents, add the following section to the domain specification:
(:functions (total-cost) )
Specifying that the cost of an action isC
is done by stating that the action has the effect of increasing the total-cost
fluent.
:effect (and
...
(increase (total-cost) C)
)
The fluent must be initialised必须初始化.
In the :init
section of the problem.pddl definition, add
(= (total-cost) 0)
Finally, 如果想最小化行动成本总和为目标, a :metric
section is added to the problem definition:
(define (problem ..)
. . .
(:metric minimize (total-cost))
)
比如我们LLdomain代码自动规划的时候如果不想有多少链表节点就声明多少个链表临时缓存,那就在每个声明新临时缓存指针的动作后续effect加一个消耗,最后最小化这个动作的执行次数。
注意: PDDL计划验证器(VAL)要求,只要在域中使用fluents,就在域的:requirements
部分中存在关键字 :fluents
。相反,一些计划人员将要求它包含:action-costs
,而一些计划者将不承认其中任何一个。
有时候为了让cost取决于其arguments, 可以声明static functions,并use those static functions in the increase
effect.
比如:
(define (domain travel)
.
.
(:functions
(distance ?from ?to)
(total-cost)
)
(:action go
:parameters (?from ?to)
:precondition (and (in ?from) (road ?from ?to))
:effect (and (not (in ?from)) (in ?to)
(increase (total-cost) (distance ?from ?to)))
)
)
常见地图搜索最短路径在problem.pddl中:init里声明地图上节点之间的距离,AB距离10,AC距离35等问题规范的初始状态部分列出了static functions的值(就像static predicates的值一样):
(define (problem ..)
.
.
(:init ...
(= (distance A B) 10)
(= (distance A C) 35)
...
)
.
.
)
理论上原则上,PDDL允许函数,常量和算术运算(+
,-
,*
,/
)的任意组合在increase
效果的left-hand side以及problem的 :metric
部分中使用。However, many planners require that the metric fluent is called total-cost
, and accept only constants, and perhaps static functions, in increase
effects.也就是说大部分solvers在实践中其实只实现了上述介绍的功能。
issues¶
- 如果您的域中存在错误或问题定义,某些计划者可能会默默地接受它们,但会带来不可预测的结果。如果您在查找计划时遇到问题,请尝试对定义运行“快速向下” –它可能指出其他计划者遗漏的常见错误。
/courses/TDDC17/sw/fdlog/fast-downward.py DOMAIN PROBLEM CONFIGURATION [FLAGS]
- 注意不要混淆(类型谓词 和*类型* )type predicates and types。类型谓词和类型是不应该一起使用的两个不同的解决方案,并且没有从一个流到另一个的信息流。这可能导致无法找到计划的情况,因为您已声明对象为
block
类型 而未声明其满足*谓词类型*(block?b)
,反之亦然。
总结来说就是如果你想表示A BC都**是**积木block,
可以使用type 类型在(:types block - object)定义定义积木类型,然后problem.pddl中声明ABC-block
也可以在声明类型谓词属性(:predicate (block?b)),然后problem.pddl中声明`(block A)(block B)(block C)。
如上所述,许多计划人员都支持实际类型,它们的工作方式与编程语言中的类型非常相似:将参数变量声明为特定类型,将对象定义为属于特定类型,依此类推。如果使用实际类型,并且将对象列表声明为(例如)B1 B2 B3-block
,那么这将*不会*导致您可以将其用作(block?b)
的类型谓词。
并且如果确实使用类型谓词,则通过声明一个称为block
的谓词,则必须在普通的初始状态下通过诸如(block B1)(block B2)(block B3)
的声明来初始化该谓词。