You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python PDDL框架实现TSP时遇递归深度超限错误求助

递归深度超限错误排查:基于pddl Python框架的TSP实现问题

我使用pddl Python框架实现旅行商问题(Travelling Salesman Problem,TSP),该框架可将Python代码转换为PDDL语言,再通过Fast-Downward执行。简单案例中领域与问题文件的生成及执行均正常,但新增TSPBasic类后触发递归深度超限错误。以下是相关代码及报错信息,恳请帮忙排查:

相关代码

main.py

from pddl_domain_problem import PDDL
from tsp_basic import TSPBasic
import subprocess
from io_parser import parse_fast_downward_output

connections = [("Boston", "NewYork"),
               ("NewYork", "Boston"),
               ("Pittsburgh", "Boston"),
               ("Boston", "Pittsburgh"),
               ("Pittsburgh", "NewYork"),
               ("NewYork", "Pittsburgh"),
               ("Toronto", "Pittsburgh"),
               ("Toronto", "NewYork"),
               ("NewYork", "Toronto"),
               ("NewYork", "Albany"),
               ("Albany", "NewYork"),
               ("Albany", "Toronto"),
               ("Toronto", "Albany")]

start_city = "NewYork"

pddl = PDDL()
tsp = TSPBasic(connections, start_city)

# 获取领域和问题描述
domain = tsp.get_domain()
problem = tsp.get_problem()

# 将领域保存到domain.pddl文件
with open('domain.pddl', 'w') as domain_file:
    domain_file.write(domain)

# 将问题保存到problem.pddl文件
with open('problem.pddl', 'w') as problem_file:
    problem_file.write(problem)

# 定义要执行的命令
command = ["/home/mihai/tools/downward/fast-downward.py", "./domain.pddl", "./problem.pddl",
           "--heuristic", "h=ff()", "--search", "astar(h)"]

# 执行命令
process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

# 检查执行是否成功
if process.returncode == 0:
    print("命令执行成功!")
    print(process.stdout)
else:
    print("命令执行出错。")
    print("错误输出:\n", process.stderr)

pddl_domain_problem.py

# 基础领域与问题示例

from pddl.logic import Predicate, constants, variables
from pddl.core import Domain, Problem
from pddl.action import Action
from pddl.formatter import domain_to_string, problem_to_string
from pddl.requirements import Requirements


class PDDL:

    def __init__(self):
        # 变量与常量
        self.x, self.y, self.z = variables("x y z", types=["type_1"])
        self.a, self.b, self.c = constants("a b c", type_="type_1")

        # 谓词
        self.p1 = Predicate("p1", self.x, self.y, self.z)
        self.p2 = Predicate("p2", self.x, self.y)

        # 领域与问题
        self.domain = self.create_domain()
        self.problem = self.create_problem()

    def create_actions(self):
        a1 = Action(
            "action-1",
            parameters=[self.x, self.y, self.z],
            precondition=self.p1(self.x, self.y, self.z) & ~self.p2(self.y, self.z),
            effect=self.p2(self.y, self.z)
        )
        return [a1]

    def create_domain(self):
        requirements = [Requirements.STRIPS, Requirements.TYPING]
        return Domain("my_domain",
                      requirements=requirements,
                      types={"type_1": None},
                      constants=[self.a, self.b, self.c],
                      predicates=[self.p1, self.p2],
                      actions=self.create_actions())

    def create_problem(self):
        requirements = [Requirements.STRIPS, Requirements.TYPING]
        return Problem(
            "problem-1",
            domain=self.domain,
            requirements=requirements,
            objects=[],
            init=[self.p1(self.a, self.b, self.c), ~self.p2(self.b, self.c)],
            goal=self.p2(self.b, self.c)
        )

    def get_domain(self):
        return domain_to_string(self.domain)

    def get_problem(self):
        return problem_to_string(self.problem)

tsp_basic.py

# 旅行商问题基础领域与问题实现

from pddl.logic import Predicate, variables
from pddl.core import Domain, Problem
from pddl.action import Action
from pddl.formatter import domain_to_string, problem_to_string
from pddl.requirements import Requirements


class TSPBasic:
    def __init__(self, connections, start_city):
        self.connections = connections  # 表示城市间连接的元组列表
        self.start_city = start_city  # TSP的起始城市

        # 从连接中提取唯一城市
        unique_cities = set()
        for start, end in connections:
            unique_cities.update([start, end])
        self.cities = variables(" ".join(unique_cities), types=["position"])

        # 动作使用的单个城市变量
        self.start = variables("start", types=["position"])[0]  # 提取单个城市变量
        self.finish = variables("finish", types=["position"])[0]  # 提取单个城市变量

        # 谓词
        self.at = Predicate("at", self.start)
        self.connected = Predicate("connected", self.start, self.finish)
        self.visited = Predicate("visited", self.finish)

        self.domain = self.create_domain()
        self.problem = self.create_problem()

    def create_actions(self):
        move = Action(
            "move",
            parameters=[self.start, self.finish],
            precondition=self.at(self.start) & 
                         self.connected(self.start, self.finish) & 
                         ~self.visited(self.finish),
            effect="&".join([
                str(self.at(self.finish)),
                str(self.visited(self.finish)),
                "~" + str(self.at(self.start))
            ])
        )
        return [move]

    def create_domain(self):
        requirements = [Requirements.STRIPS, Requirements.TYPING, Requirements.NEG_PRECONDITION]

        domain = Domain(
            "tsp_basic_domain",
            requirements=requirements,
            types={"position": None},
            constants=[],
            predicates=[self.at, self.connected, self.visited],
            actions=self.create_actions()
        )

        return domain

    def create_problem(self):
        requirements = [Requirements.STRIPS, Requirements.TYPING]

        # 基于唯一城市定义对象
        objects = self.cities

        # 初始状态
        init = [self.at(variables(self.start_city, types=["position"])[0])]
        for start, finish in self.connections:
            init.append(self.connected(variables(start, types=["position"])[0],
                                       variables(finish, types=["position"])[0]))

        # 目标状态:所有城市必须被访问且返回起始城市
        goal_conditions = [self.visited(city) for city in self.cities if city.name != self.start_city]
        goal_conditions.append(self.at(variables(self.start_city, types=["position"])[0]))
        goal = "&".join(goal_conditions)

        problem = Problem(
            "tsp_basic_problem",
            domain=self.domain,
            requirements=requirements,
            objects=objects,
            init=init,
            goal=goal
        )

        return problem

    def get_domain(self):
        return domain_to_string(self.domain)

    def get_problem(self):
        return problem_to_string(self.problem)

报错信息

回溯(最近的调用最后):
  文件 "/home/user/project/main.py", 第23行, 在 <module>
    tsp = TSPBasic(connections, start_city)
  文件 "/home/user/project/tsp_basic.py", 第30行, 在 __init__
    self.domain = self.create_domain()
  文件 "/home/user/project/tsp_basic.py", 第51行, 在 create_domain
    domain = Domain(
  文件 "/usr/local/lib/python3.10/dist-packages/pddl/core.py", 第77行, 在 __init__
    self._check_consistency()
  文件 "/usr/local/lib/python3.10/dist-packages/pddl/core.py", 第84行, 在 _check_consistency
    type_checker.check_type(self._actions)
  文件 "/usr/lib/python3.10/functools.py", 第926行, 在 _method
    return method.__get__(obj, cls)(*args, **kwargs)
  文件 "/usr/local/lib/python3.10/dist-packages/pddl/_validation.py", 第231行, 在 _
    self.check_type(obj)
  文件 "/usr/lib/python3.10/functools.py", 第926行, 在 _method
    return method.__get__(obj, cls)(*args, **kwargs)
  文件 "/usr/local/lib/python3.10/dist-packages/pddl/_validation.py", 第309行, 在 _
    self.check_type(action.effect)
  文件 "/usr/lib/python3.10/functools.py", 第926行, 在 _method
    return method.__get__(obj, cls)(*args, **kwargs)
  文件 "/usr/local/lib/python3.10/dist-packages/pddl/_validation.py", 第231行, 在 _
    self.check_type(obj)
递归错误: 调用Python对象时超过最大递归深度

内容的提问来源于stack exchange,提问作者Mihai Daian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 21:18:10