PDDL新手编写带变迁触发功能的Petri网领域文件遇语法错误,寻求基于已有Token迁移逻辑的实现方案
解答你的PDDL Petri网问题
一、第一个领域文件的报错分析与修复
你提到的报错出现在fire-transition动作的前置条件部分,我们逐一排查并修复问题:
1. 函数定义缺失返回类型
PDDL要求函数必须明确指定返回的数值类型,你的number-of-tokens函数遗漏了这一点。修改后的函数定义应为:
(:functions (number-of-tokens ?p - place) - number)
2. 转义符号问题
代码里的>是HTML转义字符,PDDL解析器无法识别,需要替换为原生的>符号。
3. Forall前置条件的语法修正
你的逻辑(所有输入该变迁的库所都有至少1个token)是正确的,但需要确保forall的括号结构合规,同时把多个forall效果用and包裹起来。修复后的完整动作定义:
(:action fire-transition :parameters (?t - transition) :preconditions (forall (?p - place) (or (not (incoming ?p ?t)) (> (number-of-tokens ?p) 0))) :effects (and (forall (?p - place) (when (incoming ?p ?t) (decrease (number-of-tokens ?p) 1))) (forall (?p - place) (when (outgoing ?t ?p) (increase (number-of-tokens ?p) 1))) ) )
关于谓词中place和transition的定义
你已经在:types块里定义了place和transition类型,并且在谓词incoming、outgoing的参数中正确指定了类型约束(?p - place、?t - transition),这部分完全符合PDDL规范,不需要额外修改。
二、复用现有代码逻辑实现Petri网变迁触发
你现有的代码是基于单个token移动的模型,现在要改成基于库所token数量的Petri网模型,核心是把个体token的移动转换成库所token数量的增减,同时用number-of-tokens判断变迁触发条件。以下是具体改造方案:
1. 调整领域文件核心元素
- 类型:保留
place,新增transition,移除token类型(我们不再跟踪单个token,而是跟踪库所的token总量) - 谓词:替换为Petri网核心关系:
incoming(库所到变迁的输入弧)、outgoing(变迁到库所的输出弧) - 函数:用
number-of-tokens ?p - place替换原来的initial-token和total-tokens-used,新增arc-weight函数表示弧的权重(对应你原来的required-token)
2. 改造fire-transition动作(对应原move动作)
原move动作是移动单个token,现在的fire-transition动作需要:
- 前置条件:所有输入库所的token数≥对应弧的权重
- 执行效果:输入库所减少对应权重的token,输出库所增加对应权重的token
改造后的完整领域文件:
(define (domain petri) (:requirements :strips :typing :fluents) (:types place transition) (:predicates (incoming ?p - place ?t - transition) (outgoing ?t - transition ?p - place) ) (:functions (number-of-tokens ?p - place) - number (arc-weight ?p - place ?t - transition) - number ; 输入弧权重 (arc-weight ?t - transition ?p - place) - number) ; 输出弧权重 (:action fire-transition :parameters (?t - transition) :precondition (forall (?p - place) (or (not (incoming ?p ?t)) (>= (number-of-tokens ?p) (arc-weight ?p ?t)))) :effect (and (forall (?p - place) (when (incoming ?p ?t) (decrease (number-of-tokens ?p) (arc-weight ?p ?t)))) (forall (?p - place) (when (outgoing ?t ?p) (increase (number-of-tokens ?p) (arc-weight ?t ?p)))) ) ) )
3. 对应改造问题文件
将原问题中单个token的位置跟踪,改为初始化库所token数量、定义变迁的输入输出弧和权重。以你原来的季节循环为例:
(define (problem petriproblem) (:domain petri) (:objects spring summer fall winter - place t1 t2 t3 t4 - transition) (:init ;; 初始化库所token数量:spring有3个token (= (number-of-tokens spring) 3) (= (number-of-tokens summer) 0) (= (number-of-tokens fall) 0) (= (number-of-tokens winter) 0) ;; 定义变迁的输入输出弧 (incoming spring t1) (outgoing t1 summer) (incoming summer t2) (outgoing t2 fall) (incoming fall t3) (outgoing t3 winter) (incoming winter t4) (outgoing t4 spring) ;; 定义所有弧的权重为1 (= (arc-weight spring t1) 1) (= (arc-weight t1 summer) 1) (= (arc-weight summer t2) 1) (= (arc-weight t2 fall) 1) (= (arc-weight fall t3) 1) (= (arc-weight t3 winter) 1) (= (arc-weight winter t4) 1) (= (arc-weight t4 spring) 1) ) ;; 目标:winter库所至少有1个token (:goal (>= (number-of-tokens winter) 1)) ;; 优化目标:最小化消耗的token总数 (:metric minimize (sum (?p - place) (- 3 (number-of-tokens ?p)))) )
关键逻辑对应说明
- 原
connected token ?from ?to→ 现在的incoming ?from ?t+outgoing ?t ?to(每个移动路径对应一个变迁) - 原
required-token ?from ?to→ 现在的arc-weight ?from ?t(输入弧的权重) - 原
initial-token token→ 现在的number-of-tokens spring(初始token所在库所的数量) - 原
total-tokens-used→ 通过初始token总数减去剩余token总数计算(如目标metric中的写法)
这样改造后,既复用了你原来的"消耗token完成路径"逻辑,又转换成了标准的Petri网变迁触发模型。
内容的提问来源于stack exchange,提问作者Ann
相关产品推荐
相关产品推荐

