Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial pass on quantified conditions. #50

Merged
merged 8 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pddl/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ class Requirements(Enum):
TYPING = RS.TYPING.strip()
NEG_PRECONDITION = RS.NEG_PRECONDITION.strip()
DIS_PRECONDITION = RS.DIS_PRECONDITION.strip()
UNIVERSAL_PRECONDITION = RS.UNIVERSAL_PRECONDITION.strip()
EXISTENTIAL_PRECONDITION = RS.EXISTENTIAL_PRECONDITION.strip()
QUANTIFIED_PRECONDITION = RS.QUANTIFIED_PRECONDITION.strip()
EQUALITY = RS.EQUALITY.strip()
CONDITIONAL_EFFECTS = RS.CONDITIONAL_EFFECTS.strip()
ADL = RS.ADL.strip()
Expand Down
70 changes: 69 additions & 1 deletion pddl/logic/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@
#

"""Base classes for PDDL logic formulas."""
from typing import Optional, Sequence
import functools
from typing import AbstractSet, Collection, Optional, Sequence

from pddl.helpers.base import ensure_set
from pddl.helpers.cache_hash import cache_hash

from pddl.logic.terms import Variable
from pddl.parser.symbols import Symbols


@cache_hash
class Formula:
Expand Down Expand Up @@ -209,6 +214,69 @@ class Not(UnaryOp):

SYMBOL = "not"

@cache_hash
@functools.total_ordering
class QuantifiedCondition(Formula):
"""Superclass for quantified conditions."""

SYMBOL: str

def __init__(
self, cond: "Formula", variables: Optional[Collection[Variable]] = None
) -> None:
"""Initialize the quantified condition."""
self._cond = cond
self._variables = ensure_set(variables)

@property
def condition(self) -> "Formula":
"""Get the condition."""
return self._cond

@property
def variables(self) -> AbstractSet[Variable]:
"""Get the variables."""
return self._variables

def __str__(self) -> str:
"""Get the string representation."""
var_block = ' '.join([f'{v} - {" ".join(v.type_tags)}' for v in self.variables])
haz marked this conversation as resolved.
Show resolved Hide resolved
return f"({self.SYMBOL} ({var_block}) {self.condition})"

def __repr__(self) -> str:
"""Get an unambiguous string representation."""
return f"{type(self).__name__}({self.variables}, {self.condition})"

def __eq__(self, other) -> bool:
"""Compare with another object."""
return (
isinstance(other, type(self))
and self.variables == other.variables
and self.condition == other.condition
)

def __hash__(self) -> int:
"""Compute the hash of the object."""
return hash((type(self), self.variables, self.condition))

def __lt__(self, other):
"""Compare with another object."""
if isinstance(other, QuantifiedCondition):
return (self.variables, self.condition) < (other.variables, other.condition)
return super().__lt__(other)


class ForallCondition(QuantifiedCondition):
"""Forall Condition."""

SYMBOL = Symbols.FORALL.value


class ExistsCondition(QuantifiedCondition):
"""Exists Condition."""

SYMBOL = Symbols.EXISTS.value


def ensure_formula(f: Optional[Formula], is_none_true: bool) -> Formula:
"""
Expand Down
7 changes: 7 additions & 0 deletions pddl/parser/common.lark
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ NAME: /[a-zA-Z][a-zA-Z0-9-_]*/
| NON_DETERMINISTIC
| NEG_PRECONDITION
| DIS_PRECONDITION
| EXISTENTIAL_PRECONDITIONS
| UNIVERSAL_PRECONDITIONS
| QUANTIFIED_PRECONDITIONS
| ADL
| DERIVED_PREDICATES
| CONDITIONAL_EFFECTS
Expand All @@ -24,6 +27,7 @@ PRECONDITION: ":precondition"
EFFECT: ":effect"
DERIVED: ":derived"
FORALL: "forall"
EXISTS: "exists"
WHEN: "when"
OBJECT: "object"
AND: "and"
Expand All @@ -44,6 +48,9 @@ NEG_PRECONDITION: ":negative-preconditions"
DIS_PRECONDITION: ":disjunctive-preconditions"
DERIVED_PREDICATES: ":derived-predicates"
CONDITIONAL_EFFECTS: ":conditional-effects"
EXISTENTIAL_PRECONDITIONS: ":existential-preconditions"
UNIVERSAL_PRECONDITIONS: ":universal-preconditions"
QUANTIFIED_PRECONDITIONS: ":quantified-preconditions"

// others
LPAR : "("
Expand Down
3 changes: 3 additions & 0 deletions pddl/parser/domain.lark
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ gd: atomic_formula_term
| LPAR NOT gd RPAR
| LPAR AND gd* RPAR
| LPAR IMPLY gd gd RPAR
| LPAR EXISTS LPAR typed_list_variable RPAR gd RPAR
| LPAR FORALL LPAR typed_list_variable RPAR gd RPAR

// effects
emptyor_effect: LPAR RPAR
Expand Down Expand Up @@ -76,6 +78,7 @@ type_def: LPAR EITHER primitive_type+ RPAR
%import .common.EFFECT -> EFFECT
%import .common.DERIVED -> DERIVED
%import .common.FORALL -> FORALL
%import .common.EXISTS -> EXISTS
%import .common.WHEN -> WHEN
%import .common.OBJECT -> OBJECT
%import .common.AND -> AND
Expand Down
25 changes: 23 additions & 2 deletions pddl/parser/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from pddl.core import Action, Domain, Requirements
from pddl.exceptions import PDDLMissingRequirementError
from pddl.helpers.base import assert_, safe_get, safe_index
from pddl.logic.base import And, FalseFormula, Imply, Not, OneOf, Or
from pddl.logic.base import And, FalseFormula, Imply, Not, OneOf, Or, ForallCondition, ExistsCondition
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 @@ -157,6 +157,24 @@ def gd(self, args):
):
raise PDDLMissingRequirementError(Requirements.DIS_PRECONDITION)
return Imply(args[2], args[3])
elif args[1] == Symbols.FORALL.value:
if not bool(
{Requirements.UNIVERSAL_PRECONDITION, Requirements.QUANTIFIED_PRECONDITION, Requirements.ADL}
& self._extended_requirements
):
raise PDDLMissingRequirementError(Requirements.UNIVERSAL_PRECONDITION)
variables = [Variable(name, tags) for name, tags in args[3].items()]
condition = args[5]
haz marked this conversation as resolved.
Show resolved Hide resolved
return ForallCondition(cond=condition, variables=variables)
elif args[1] == Symbols.EXISTS.value:
if not bool(
{Requirements.EXISTENTIAL_PRECONDITION, Requirements.QUANTIFIED_PRECONDITION, Requirements.ADL}
& self._extended_requirements
):
raise PDDLMissingRequirementError(Requirements.EXISTENTIAL_PRECONDITION)
variables = [Variable(name, tags) for name, tags in args[3].items()]
condition = args[5]
return ExistsCondition(cond=condition, variables=variables)

def emptyor_effect(self, args):
"""Process the 'emptyor_effect' rule."""
Expand All @@ -178,7 +196,7 @@ def c_effect(self, args):
if len(args) == 1:
return args[0]
if args[1] == Symbols.FORALL.value:
return Forall(effects=args[-2], variables=args[3])
return Forall(effect=args[-2], variables=args[3])
if args[1] == Symbols.WHEN.value:
return When(args[2], args[3])
if args[1] == Symbols.ONEOF.value:
Expand Down Expand Up @@ -206,6 +224,9 @@ def atomic_formula_term(self, args):
"""Process the 'atomic_formula_term' rule."""

def constant_or_variable(t):
# Case where the term is a free variable (bug) or comes from a parent quantifier
if not isinstance(t, Constant) and t not in self._current_parameters_by_name:
return Variable(str(t), {})
return t if isinstance(t, Constant) else self._current_parameters_by_name[t]

if args[1] == Symbols.EQUAL.value:
Expand Down
3 changes: 3 additions & 0 deletions pddl/parser/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class RequirementSymbols(Enum):
TYPING = ":typing"
NEG_PRECONDITION = ":negative-preconditions"
DIS_PRECONDITION = ":disjunctive-preconditions"
UNIVERSAL_PRECONDITION = ":universal-preconditions"
EXISTENTIAL_PRECONDITION = ":existential-preconditions"
QUANTIFIED_PRECONDITION = ":quantified-preconditions"
EQUALITY = ":equality"
CONDITIONAL_EFFECTS = ":conditional-effects"
ADL = ":adl"
Expand Down