I use pddl python framework to implement the travelling salesman problem. This framwork translates from python language to pddl language and then the language is executed with fast-downward. I have tested it on a simple case and the generation of the domain and the problem and then I checked the output and worked well but when i come with a new class, TSPBasic, i got this error. I attach the main, working class and TSPBasic class with problem.
main.py:
from pddl_domain_problem import PDDLfrom tsp_basic import TSPBasicimport subprocessfrom io_parser import parse_fast_downward_outputconnections = [("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)# retrieve the domain and the problemdomain = tsp.get_domain()problem = tsp.get_problem()# Save the domain to a file named 'domain.pddl'with open('domain.pddl', 'w') as domain_file: domain_file.write(domain)# Save the problem to a file named 'problem.pddl'with open('problem.pddl', 'w') as problem_file: problem_file.write(problem)# Define the command to be executedcommand = ["/home/mihai/tools/downward/fast-downward.py", "./domain.pddl", "./problem.pddl","--heuristic", "h=ff()", "--search", "astar(h)"]# Run the commandprocess = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)# Check if the process was successfulif process.returncode == 0: print("Command executed successfully!") print(process.stdout)else: print("Error in command execution.") print("Error Output:\n", process.stderr)pddl_domain_problem.py:
# demo for a basic case with domain and problemfrom pddl.logic import Predicate, constants, variablesfrom pddl.core import Domain, Problemfrom pddl.action import Actionfrom pddl.formatter import domain_to_string, problem_to_stringfrom pddl.requirements import Requirementsclass PDDL: def __init__(self): # Variables and constants 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") # Predicates self.p1 = Predicate("p1", self.x, self.y, self.z) self.p2 = Predicate("p2", self.x, self.y) # Domain and problem 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:
# travelling salesman domain and problem basic casefrom pddl.logic import Predicate, variablesfrom pddl.core import Domain, Problemfrom pddl.action import Actionfrom pddl.formatter import domain_to_string, problem_to_stringfrom pddl.requirements import Requirementsclass TSPBasic: def __init__(self, connections, start_city): self.connections = connections # List of tuples representing connections between cities self.start_city = start_city # Starting city from the TSP # Extracting unique cities from connections unique_cities = set() for start, end in connections: unique_cities.update([start, end]) self.cities = variables(" ".join(unique_cities), types=["position"]) # Single city variables for actions self.start = variables("start", types=["position"])[0] # Extract single city variable self.finish = variables("finish", types=["position"])[0] # Extract single city variable # Predicates 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] # Define objects based on unique cities objects = self.cities # Initial state 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 state: all cities must be visited and return to start 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)And error i get:
Traceback (most recent call last): File "/home/user/project/main.py", line 23, in <module> tsp = TSPBasic(connections, start_city) File "/home/user/project/tsp_basic.py", line 30, in __init__ self.domain = self.create_domain() File "/home/user/project/tsp_basic.py", line 51, in create_domain domain = Domain( File "/usr/local/lib/python3.10/dist-packages/pddl/core.py", line 77, in __init__ self._check_consistency() File "/usr/local/lib/python3.10/dist-packages/pddl/core.py", line 84, in _check_consistency type_checker.check_type(self._actions) File "/usr/lib/python3.10/functools.py", line 926, in _method return method.__get__(obj, cls)(*args, **kwargs) File "/usr/local/lib/python3.10/dist-packages/pddl/_validation.py", line 231, in _ self.check_type(obj) File "/usr/lib/python3.10/functools.py", line 926, in _method return method.__get__(obj, cls)(*args, **kwargs) File "/usr/local/lib/python3.10/dist-packages/pddl/_validation.py", line 309, in _ self.check_type(action.effect) File "/usr/lib/python3.10/functools.py", line 926, in _method return method.__get__(obj, cls)(*args, **kwargs) File "/usr/local/lib/python3.10/dist-packages/pddl/_validation.py", line 231, in _ self.check_type(obj)RecursionError: maximum recursion depth exceeded while calling a Python objectCould anyone take a look on the error?