Skip to content

Commit

Permalink
implement __str__ for Domain and Problem
Browse files Browse the repository at this point in the history
  • Loading branch information
ssardina committed Feb 14, 2024
1 parent 4ee8d63 commit aec63e5
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 53 deletions.
50 changes: 50 additions & 0 deletions pddl/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
from pddl.logic.terms import Constant
from pddl.requirements import Requirements

from pddl.formatter import sort_and_print_collection, print_types_or_functions_with_parents, print_predicates_with_types, remove_empty_lines, print_constants, print_function_skeleton, indent


class Domain:
"""A class for a PDDL domain file."""
Expand Down Expand Up @@ -148,6 +150,36 @@ def __eq__(self, other):
and self.actions == other.actions
)

def __str__(self) -> str:
"""Print a PDDL domain object."""
result = f"(define (domain {self.name})"
body = ""
indentation = " " * 4
body += sort_and_print_collection("(:requirements ", self.requirements, ")\n")
body += print_types_or_functions_with_parents("(:types", self.types, ")\n")
body += print_constants("(:constants", self.constants, ")\n")
if self.predicates:
body += f"(:predicates {print_predicates_with_types(self.predicates)})\n"
if self.functions:
body += print_types_or_functions_with_parents(
"(:functions", self.functions, ")\n", print_function_skeleton
)
body += sort_and_print_collection(
"",
self.derived_predicates,
"",
to_string=lambda obj: str(obj) + "\n",
)
body += sort_and_print_collection(
"",
self.actions,
"",
to_string=lambda obj: str(obj) + "\n",
)
result = result + "\n" + indent(body, indentation) + "\n)"
result = remove_empty_lines(result)
return result


class Problem:
"""A class for a PDDL problem file."""
Expand Down Expand Up @@ -331,3 +363,21 @@ def __eq__(self, other):
and self.goal == other.goal
and self.metric == other.metric
)

def __str__(self) -> str:
"""Print a PDDL problem object."""
result = f"(define (problem {self.name})"
body = f"(:domain {self.domain_name})\n"
indentation = " " * 4
body += sort_and_print_collection("(:requirements ", self.requirements, ")\n")
if self.objects:
body += print_constants("(:objects", self.objects, ")\n")
body += sort_and_print_collection(
"(:init ", self.init, ")\n", is_mandatory=True
)
body += f"{'(:goal ' + str(self.goal) + ')'}\n"
body += f"{'(:metric ' + str(self.metric) + ')'}\n" if self.metric else ""
result = result + "\n" + indent(body, indentation) + "\n)"
result = remove_empty_lines(result)
return result

66 changes: 13 additions & 53 deletions pddl/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,19 @@
from textwrap import indent
from typing import Callable, Collection, Dict, List, Optional, TypeVar

from pddl.core import Domain, Problem
from pddl.custom_types import name
from pddl.logic.functions import NumericFunction
from pddl.logic.terms import Constant

T = TypeVar("T", name, NumericFunction)


def _remove_empty_lines(s: str) -> str:
def remove_empty_lines(s: str) -> str:
"""Remove empty lines from string."""
return "\n".join(filter(str.strip, s.splitlines()))


def _sort_and_print_collection(
def sort_and_print_collection(
prefix,
collection: Collection,
postfix,
Expand All @@ -41,7 +40,7 @@ def _sort_and_print_collection(
return ""


def _print_types_or_functions_with_parents(
def print_types_or_functions_with_parents(
prefix: str,
types_dict: Dict[T, Optional[name]],
postfix: str,
Expand All @@ -53,10 +52,10 @@ def _print_types_or_functions_with_parents(
name_by_obj.setdefault(parent_type, []).append(obj_name) # type: ignore
if not bool(name_by_obj):
return ""
return _print_typed_lists(prefix, name_by_obj, postfix, to_string)
return print_typed_lists(prefix, name_by_obj, postfix, to_string)


def _print_constants(
def print_constants(
prefix, constants: Collection[Constant], postfix, to_string: Callable = str
):
"""Print constants in a PDDL domain."""
Expand All @@ -65,10 +64,10 @@ def _print_constants(
term_by_type_tags.setdefault(c.type_tag, []).append(c.name)
if not bool(term_by_type_tags):
return ""
return _print_typed_lists(prefix, term_by_type_tags, postfix, to_string)
return print_typed_lists(prefix, term_by_type_tags, postfix, to_string)


def _print_predicates_with_types(predicates: Collection):
def print_predicates_with_types(predicates: Collection):
result = ""
for p in sorted(predicates):
if p.arity == 0:
Expand All @@ -89,7 +88,7 @@ def _print_predicates_with_types(predicates: Collection):
return result.strip()


def _print_function_skeleton(function: NumericFunction) -> str:
def print_function_skeleton(function: NumericFunction) -> str:
"""Callable to print a function skeleton with type tags."""
result = ""
if function.arity == 0:
Expand All @@ -106,7 +105,7 @@ def _print_function_skeleton(function: NumericFunction) -> str:
return result


def _print_typed_lists(
def print_typed_lists(
prefix,
names_by_obj: Dict[Optional[T], List[name]],
postfix,
Expand Down Expand Up @@ -139,50 +138,11 @@ def _print_typed_lists(
return result


def domain_to_string(domain: Domain) -> str:
def domain_to_string(domain) -> str:
"""Print a PDDL domain object."""
result = f"(define (domain {domain.name})"
body = ""
indentation = " " * 4
body += _sort_and_print_collection("(:requirements ", domain.requirements, ")\n")
body += _print_types_or_functions_with_parents("(:types", domain.types, ")\n")
body += _print_constants("(:constants", domain.constants, ")\n")
if domain.predicates:
body += f"(:predicates {_print_predicates_with_types(domain.predicates)})\n"
if domain.functions:
body += _print_types_or_functions_with_parents(
"(:functions", domain.functions, ")\n", _print_function_skeleton
)
body += _sort_and_print_collection(
"",
domain.derived_predicates,
"",
to_string=lambda obj: str(obj) + "\n",
)
body += _sort_and_print_collection(
"",
domain.actions,
"",
to_string=lambda obj: str(obj) + "\n",
)
result = result + "\n" + indent(body, indentation) + "\n)"
result = _remove_empty_lines(result)
return result
return str(domain)


def problem_to_string(problem: Problem) -> str:
def problem_to_string(problem) -> str:
"""Print a PDDL problem object."""
result = f"(define (problem {problem.name})"
body = f"(:domain {problem.domain_name})\n"
indentation = " " * 4
body += _sort_and_print_collection("(:requirements ", problem.requirements, ")\n")
if problem.objects:
body += _print_constants("(:objects", problem.objects, ")\n")
body += _sort_and_print_collection(
"(:init ", problem.init, ")\n", is_mandatory=True
)
body += f"{'(:goal ' + str(problem.goal) + ')'}\n"
body += f"{'(:metric ' + str(problem.metric) + ')'}\n" if problem.metric else ""
result = result + "\n" + indent(body, indentation) + "\n)"
result = _remove_empty_lines(result)
return result
return str(problem)

0 comments on commit aec63e5

Please sign in to comment.