Skip to content

Commit

Permalink
Merge pull request #83 from AI-Planning/fix/formula-formatting
Browse files Browse the repository at this point in the history
Fix printing of empty Ands and Ors
  • Loading branch information
haz committed Jun 23, 2023
2 parents 79c0d24 + eac7882 commit f54e187
Show file tree
Hide file tree
Showing 8 changed files with 17 additions and 107 deletions.
16 changes: 1 addition & 15 deletions pddl/_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@
from pddl.exceptions import PDDLValidationError
from pddl.helpers.base import check, ensure, ensure_set, find_cycle
from pddl.logic import Predicate
from pddl.logic.base import (
BinaryOp,
FalseFormula,
QuantifiedCondition,
TrueFormula,
UnaryOp,
)
from pddl.logic.base import BinaryOp, QuantifiedCondition, UnaryOp
from pddl.logic.effects import AndEffect, Forall, When
from pddl.logic.predicates import DerivedPredicate, EqualTo
from pddl.logic.terms import Term
Expand Down Expand Up @@ -261,14 +255,6 @@ def _(self, formula: BinaryOp) -> None:
"""Check types annotations of a PDDL binary operator."""
self.check_type(formula.operands)

@check_type.register
def _(self, formula: TrueFormula) -> None:
"""Check types annotations of a PDDL true formula."""

@check_type.register
def _(self, formula: FalseFormula) -> None:
"""Check types annotations of a PDDL false formula."""

@check_type.register
def _(self, formula: QuantifiedCondition) -> None:
"""Check types annotations of a PDDL quantified condition."""
Expand Down
4 changes: 2 additions & 2 deletions pddl/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from pddl.custom_types import name as name_type
from pddl.custom_types import namelike, parse_name, to_names, to_types # noqa: F401
from pddl.helpers.base import assert_, check, ensure, ensure_set
from pddl.logic.base import Formula, TrueFormula, is_literal
from pddl.logic.base import And, Formula, is_literal
from pddl.logic.predicates import DerivedPredicate, Predicate
from pddl.logic.terms import Constant
from pddl.requirements import Requirements
Expand Down Expand Up @@ -172,7 +172,7 @@ def __init__(
] = self._parse_requirements(domain, requirements)
self._objects: AbstractSet[Constant] = ensure_set(objects)
self._init: AbstractSet[Formula] = ensure_set(init)
self._goal: Formula = ensure(goal, TrueFormula())
self._goal: Formula = ensure(goal, And())
validate(
all(map(is_literal, self.init)),
"Not all formulas of initial condition are literals!",
Expand Down
7 changes: 1 addition & 6 deletions pddl/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from pddl.core import Domain, Problem
from pddl.custom_types import name
from pddl.logic.base import TRUE
from pddl.logic.terms import Constant


Expand Down Expand Up @@ -153,11 +152,7 @@ def problem_to_string(problem: Problem) -> str:
body += _sort_and_print_collection(
"(:init ", problem.init, ")\n", is_mandatory=True
)
body += (
f"{'(:goal ' + str(problem.goal) + ')'}\n"
if problem.goal != TRUE
else "(:goal (and))\n"
)
body += f"{'(:goal ' + str(problem.goal) + ')'}\n"
result = result + "\n" + indent(body, indentation) + "\n)"
result = _remove_empty_lines(result)
return result
72 changes: 5 additions & 67 deletions pddl/logic/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,66 +115,6 @@ class Atomic(Formula):
"""Atomic formula."""


class TrueFormula(Formula):
"""A tautology."""

def __str__(self) -> str:
"""Get the string representation."""
return "(true)"

def __repr__(self) -> str:
"""Get an unambiguous string representation."""
return "TrueFormula()"

def __eq__(self, other):
"""Compare with another object."""
return isinstance(other, TrueFormula)

def __hash__(self):
"""Hash the object."""
return hash(TrueFormula)

def __invert__(self) -> Formula:
"""Negate the formula."""
return FALSE

def __neg__(self) -> Formula:
"""Negate."""
return FALSE


class FalseFormula(Formula):
"""A contradiction."""

def __str__(self) -> str:
"""Get the string representation."""
return "(false)"

def __repr__(self) -> str:
"""Get an unambiguous string representation."""
return "FalseFormula()"

def __eq__(self, other):
"""Compare with another object."""
return isinstance(other, FalseFormula)

def __hash__(self):
"""Hash the object."""
return hash(FalseFormula)

def __invert__(self) -> Formula:
"""Negate the formula."""
return TRUE

def __neg__(self) -> Formula:
"""Negate."""
return TRUE


TRUE = TrueFormula()
FALSE = FalseFormula()


class MonotoneOp(type):
"""Metaclass to simplify monotone operator instantiations."""

Expand All @@ -192,14 +132,14 @@ def __call__(cls, *args, **kwargs):
class And(BinaryOp, metaclass=MonotoneOp):
"""And operator."""

_absorbing = FALSE
_absorbing = False
SYMBOL = "and"


class Or(BinaryOp, metaclass=MonotoneOp):
"""Or operator."""

_absorbing = TRUE
_absorbing = True
SYMBOL = "or"


Expand Down Expand Up @@ -296,10 +236,10 @@ def ensure_formula(f: Optional[Formula], is_none_true: bool) -> Formula:
Ensure the argument is a formula.
:param f: the formula, or None.
:param is_none_true: if true, None reduces to TrueFormula; FalseFormula otherwise.
:param is_none_true: if true, None reduces to And(); FalseFormula otherwise.
:return: the same set, or an empty set if the arg was None.
"""
return f if f is not None else TrueFormula() if is_none_true else FalseFormula()
return f if f is not None else And() if is_none_true else Or()


def is_literal(formula: Formula) -> bool:
Expand All @@ -323,11 +263,9 @@ def is_literal(formula: Formula) -> bool:
def _simplify_monotone_op_operands(cls, *operands):
operands = list(dict.fromkeys(operands))
if len(operands) == 0:
return [~cls._absorbing]
return []
elif len(operands) == 1:
return [operands[0]]
elif cls._absorbing in operands:
return cls._absorbing

# shift-up subformulas with same operator. DFS on expression tree.
new_operands = []
Expand Down
15 changes: 3 additions & 12 deletions pddl/parser/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,7 @@
from pddl.custom_types import name
from pddl.exceptions import PDDLMissingRequirementError, PDDLParsingError
from pddl.helpers.base import assert_
from pddl.logic.base import (
And,
ExistsCondition,
FalseFormula,
ForallCondition,
Imply,
Not,
OneOf,
Or,
)
from pddl.logic.base import And, ExistsCondition, ForallCondition, Imply, Not, OneOf, Or
from pddl.logic.effects import AndEffect, Forall, When
from pddl.logic.predicates import DerivedPredicate, EqualTo, Predicate
from pddl.logic.terms import Constant, Variable
Expand Down Expand Up @@ -138,7 +129,7 @@ def action_parameters(self, args):
def emptyor_pregd(self, args):
"""Process the 'emptyor_pregd' rule."""
if len(args) == 2:
return FalseFormula()
return Or()
else:
assert_(len(args) == 1)
return args[0]
Expand Down Expand Up @@ -217,7 +208,7 @@ def gd(self, args):
def emptyor_effect(self, args):
"""Process the 'emptyor_effect' rule."""
if len(args) == 2:
return FalseFormula()
return Or()
else:
return args[0]

Expand Down
4 changes: 2 additions & 2 deletions tests/test_domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pddl.core import Domain
from pddl.exceptions import PDDLValidationError
from pddl.logic import Constant, Variable
from pddl.logic.base import Not, TrueFormula
from pddl.logic.base import And, Not
from pddl.logic.helpers import constants, variables
from pddl.logic.predicates import DerivedPredicate, Predicate
from pddl.parser.symbols import Symbols
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_derived_predicate_type_not_available() -> None:
"""Test that when a type of a term of a derived predicate is not declared we raise error."""
x = Variable("a", type_tags={"t1", "t2"})
p = Predicate("p", x)
dp = DerivedPredicate(p, TrueFormula())
dp = DerivedPredicate(p, And())

my_type = "my_type"
type_set = {my_type: None}
Expand Down
2 changes: 1 addition & 1 deletion tests/test_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,6 @@ def test_typed_objects_formatting_in_problem() -> None:
(:requirements :typing)
(:objects a b c - type_1 d e f - type_2 g h i - type_3 j k l)
(:init )
(:goal (and))
(:goal (and ))
)"""
)
4 changes: 2 additions & 2 deletions tests/test_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import pytest

from pddl.core import Domain, Problem
from pddl.logic.base import Not, TrueFormula
from pddl.logic.base import And, Not
from pddl.logic.helpers import constants, variables
from pddl.logic.predicates import Predicate
from tests.conftest import pddl_objects_problems
Expand Down Expand Up @@ -64,7 +64,7 @@ def test_init(self):

def test_goal(self):
"""Test the goal getter."""
assert self.problem.goal == TrueFormula()
assert self.problem.goal == And()


def test_build_simple_problem():
Expand Down

0 comments on commit f54e187

Please sign in to comment.