Getting Started with PDDL
注:本指南译自 LearnPDDL 。
Introduction
PDDL 是为数不多的旨在创建人工智能 (AI) 规划标准的语言之一,它于 1998 年开发并在 ICAPS 引入,多年来一直在改进和扩展。
目前最流行的 PDDL 是 PDDL 2.1,它是 PDDL 的扩展,用于表达时域; PDDL 3 为 PDDL 2.1 添加了轨迹约束和偏好,而 PDDL+ 则允许在 PDDL 中对混合离散连续域进行建模。
Components of PDDL
在开始编写 PDDL 之前,我们需要了解如何在 PDDL 中对“世界”进行建模。
一个“世界”由一组状态描述,每个状态包含一个事实和/或对象列表。 一个“世界”从一个初始状态开始,并受一组规则和约束的约束,这些规则和约束限制了在每个状态下可以采取的行动,每个行动通常代表到不同状态的转换。
在这个“世界”中,我们需要跟踪以下事物:
- 对象(Objects):“世界”中我们所感兴趣的事物。
- 谓词(Predicates):我们感兴趣的事实(例如对象的属性),可以是真或假。
- 初始状态(An Initial State):我们开始所处的“世界”状态,即开始时为真的事物。
- 目标规范(Goal Specification):我们期望的结束时的世界状态,即我们希望最终成为真实的事物。
- 行为/操作(Actions/Operators):改变世界状态的方式,即发生后能改变事实(真与假)的事情。
PDDL Syntax
首先你需要知道的是,通常 PDDL 文件的扩展名为 .pddl
.
您需要学习以下两个 PDDL 文件的语法:
The Domain File(域文件)
Domain 文件建立了世界的背景。 它决定了状态可以包含哪些细节(谓词),以及我们可以做些什么来在世界上的状态之间移动(动作)。
Domain 文件的基本语法是:
(define (domain <domain-name>)
(:predicates
<predicate-list>
)
(:action
<action-details>
)
)
The Problem/Fact File
Problem 文件代表我们在域中建立的世界的一个实例。 它决定了计划开始时什么是真的(初始状态),以及我们希望在计划结束时是什么(目标状态)。
Problem 文件的基本语法是:
(define (problem <title>)
(:domain <domain-name>)
(:objects
<object-list>
)
(:init
<predicates>
)
(:goal
<predicates>
)
)
注意: <title>
是 problem 的标题; <domain-name>
是对应的 domain 名称,需要与 domain 文件中定义的 <domain-name>
一致,而非 domain 文件名。
简单示例:Let’s Eat!
假设我们有一个机械手、一个纸杯蛋糕和一个盘子。 夹子是空的,纸杯蛋糕在桌子上,我们想把纸杯蛋糕放在盘子上。
在我们用 PDDL 建模之前,让我们看一下 PDDL 问题的组成部分:
首先我们定义 domain :
(define (domain letseat)
然后我们定义 objects :盘子、抓手、纸杯蛋糕。 我们还将纸杯蛋糕和手臂标记为可定位,这是一个小技巧,可以帮助我们使用稍后创建的谓词查询这些对象的位置。
(:requirements :typing)
(:types
location locatable - object
bot cupcake - locatable
robot - bot
)
我们还需要定义一些 predicates 。 夹臂是空的吗? 纸杯蛋糕在哪里?
(:predicates
(on ?obj - locatable ?loc - location)
(holding ?arm - locatable ?cupcake - locatable)
(arm-empty)
(path ?location1 - location ?location2 - location)
)
我们还必须定义 actions/operators 。 我们需要能够拿起和放下纸杯蛋糕,以及在桌子和盘子之间移动手臂。
(:action pick-up
:parameters
(?arm - bot
?cupcake - locatable
?loc - location)
:precondition
(and
; Note how we use the same variable loc
; in both lines below. This is to make
; sure it's looking at the same location.
(on ?arm ?loc)
(on ?cupcake ?loc)
(arm-empty)
)
:effect
(and
(not (on ?cupcake ?loc))
(holding ?arm ?cupcake)
(not (arm-empty))
)
)
(:action drop
:parameters
(?arm - bot
?cupcake - locatable
?loc - location)
:precondition
(and
(on ?arm ?loc)
(holding ?arm ?cupcake)
)
:effect
(and
(on ?cupcake ?loc)
(arm-empty)
(not (holding ?arm ?cupcake))
)
)
(:action move
:parameters
(?arm - bot
?from - location
?to - location)
:precondition
(and
(on ?arm ?from)
(path ?from ?to)
)
:effect
(and
(not (on ?arm ?from))
(on ?arm ?to)
)
)
将以上所有内容放入一个文件中,您就有了一个 domain 文件 !
现在我们来看看 problem 文件。 我们将首先让它知道它与哪个域相关联,并定义世界上存在的对象。
(define (problem letseat-simple)
(:domain letseat)
(:objects
arm - robot
cupcake - cupcake
table - location
plate - location
)
然后,我们将定义 initial state :抓手是空的,纸杯蛋糕在桌子上,手臂可以在两者之间移动。
(:init
(on arm table)
(on cupcake table)
(arm-empty)
(path table plate)
)
最后,我们定义 goal specification :盘子里的纸杯蛋糕。
(:goal
(on cupcake plate)
)
组合以上部分,你就会得到 problem 文件 !
如果你使用 OPTIC 运行它,你会得到如下解决方案:
Initial heuristic = 3
Initial stats: t=0s, 4299060kb
b (2 @ n=3, t=0s, 4300084kb)b (1 @ n=6, t=0s, 4308276kb)
;;;; Solution Found
; Time 0.00
; Peak memory 4308276kb
; Nodes Generated: 5
; Nodes Expanded: 3
; Nodes Evaluated: 6
; Nodes Tunneled: 1
; Nodes memoised with open actions: 0
; Nodes memoised without open actions: 6
; Nodes pruned by memoisation: 0
0: (pick-up arm cupcake table) [1]
1: (move arm table plate) [1]
2: (drop arm cupcake plate) [1]
练习
请思考以下任务,其中的场景更加复杂,这将有助于加深你的理解:
- 在桌子上添加第二个蛋糕,并将其添加到目标规划中,以确保它也放在盘子上。
- 向域中添加一个独角兽对象,并为独角兽定义吃蛋糕的目标。 独角兽只能吃盘子里的蛋糕。
稍难示例
如果想查看更复杂的内容,请查看 driverlog domain 。
基础之上
如果你是初学者,请在充分理解基础知识之后再阅读这部分。
Durative Actions
为了在时域中工作,可以给动作定义持续时间。
每个条件(condition)和结果(effect)都给出了它们应该发生的时间。
几种类型的时间约束:
(at start (<condition/effect>))
:必须为真或在动作开始时发生。(at end (<condition/effect>))
:必须为真或发生在动作结束时。(over all (<condition>))
:在操作的整个持续时间内这必须为真。
以下是上文示例中的(move
)动作转换为持续性动作的示例:
(:durative-action move
:duration (= ?duration 10) ; Duration goes here.
:parameters
(?arm - bot
?from - location
?to - location)
:condition ; Note how this is "condition" not "pre-condition"
(and
(at start (on ?arm ?from))
(over all (path ?from ?to))
)
:effect
(and
(at start (not (on ?arm ?from)))
(at end (on ?arm ?to))
)
)
Functions
待续
Processes & Events
待续