Skip to content

Commit

Permalink
Towards PDDL+ parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Enrico Scala authored and Enrico Scala committed Sep 17, 2024
1 parent 0519adb commit c16b2c4
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 8 deletions.
124 changes: 121 additions & 3 deletions unified_planning/io/pddl_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,30 @@ def __init__(self):
+ Optional(":observe" - set_results_name(nested_expr(), "obs"))
+ Suppress(")")
)
process_def = Group(
Suppress("(")
+ ":process"
- set_results_name(name, "name")
+ ":parameters"
- Suppress("(")
+ parameters
+ Suppress(")")
+ Optional(":precondition" - set_results_name(nested_expr(), "pre"))
+ Optional(":effect" - set_results_name(nested_expr(), "eff"))
+ Suppress(")")
)
event_def = Group(
Suppress("(")
+ ":event"
- set_results_name(name, "name")
+ ":parameters"
- Suppress("(")
+ parameters
+ Suppress(")")
+ Optional(":precondition" - set_results_name(nested_expr(), "pre"))
+ Optional(":effect" - set_results_name(nested_expr(), "eff"))
+ Suppress(")")
)

dur_action_def = Group(
Suppress("(")
Expand Down Expand Up @@ -260,6 +284,8 @@ def __init__(self):
+ set_results_name(
Group(ZeroOrMore(action_def | dur_action_def)), "actions"
)
+ set_results_name(Group(ZeroOrMore(process_def)), "processes")
+ set_results_name(Group(ZeroOrMore(event_def)), "events")
+ Suppress(")")
)

Expand Down Expand Up @@ -526,6 +552,8 @@ def _parse_exp(
solved.append(self._em.FluentExp(problem.fluent(exp.value)))
elif problem.has_object(exp.value): # object
solved.append(self._em.ObjectExp(problem.object(exp.value)))
elif exp.value == "#t":
solved.append(self._em.Int(1))
else: # number
try:
n = Fraction(exp.value)
Expand Down Expand Up @@ -559,7 +587,12 @@ def _parse_exp(
def _add_effect(
self,
problem: up.model.Problem,
act: Union[up.model.InstantaneousAction, up.model.DurativeAction],
act: Union[
up.model.InstantaneousAction,
up.model.DurativeAction,
up.model.Process,
up.model.Event,
],
types_map: TypesMap,
exp: CustomParseResults,
complete_str: str,
Expand Down Expand Up @@ -619,7 +652,12 @@ def _add_effect(
),
cond,
)
act.add_increase_effect(*eff if timing is None else (timing, *eff)) # type: ignore

if isinstance(act, up.model.Process):
eff1 = (eff[0], eff[1].simplify())
act.add_derivative(*eff1)
else:
act.add_increase_effect(*eff if timing is None else (timing, *eff)) # type: ignore
elif op == "decrease":
eff = (
self._parse_exp(
Expand Down Expand Up @@ -1207,6 +1245,87 @@ def declare_type(
task_params[p] = t
task = htn.Task(name, task_params)
problem.add_task(task)
for a in domain_res.get("processes", []):
n = a["name"]
a_params = OrderedDict()
for g in a.get("params", []):
try:
t = types_map[g.value[1] if len(g.value) > 1 else Object]
except KeyError:
g_start_line, g_start_col = lineno(g.locn_start, domain_str), col(
g.locn_start, domain_str
)
g_end_line, g_end_col = lineno(g.locn_end, domain_str), col(
g.locn_end, domain_str
)
raise SyntaxError(
f"Undefined parameter's type: {g.value[1]}."
+ f"\nError from line: {g_start_line}, col: {g_start_col} to line: {g_end_line}, col: {g_end_col}."
)
for p in g.value[0]:
a_params[p] = t
act = up.model.Process(n, a_params, self._env)
if "pre" in a:
act.add_precondition(
self._parse_exp(
problem,
act,
types_map,
{},
CustomParseResults(a["pre"][0]),
domain_str,
)
)
if "eff" in a:
self._add_effect(
problem,
act,
types_map,
CustomParseResults(a["eff"][0]),
domain_str,
)
problem.add_action(act)

for a in domain_res.get("events", []):
n = a["name"]
a_params = OrderedDict()
for g in a.get("params", []):
try:
t = types_map[g.value[1] if len(g.value) > 1 else Object]
except KeyError:
g_start_line, g_start_col = lineno(g.locn_start, domain_str), col(
g.locn_start, domain_str
)
g_end_line, g_end_col = lineno(g.locn_end, domain_str), col(
g.locn_end, domain_str
)
raise SyntaxError(
f"Undefined parameter's type: {g.value[1]}."
+ f"\nError from line: {g_start_line}, col: {g_start_col} to line: {g_end_line}, col: {g_end_col}."
)
for p in g.value[0]:
a_params[p] = t
act = up.model.Event(n, a_params, self._env)
if "pre" in a:
act.add_precondition(
self._parse_exp(
problem,
act,
types_map,
{},
CustomParseResults(a["pre"][0]),
domain_str,
)
)
if "eff" in a:
self._add_effect(
problem,
act,
types_map,
CustomParseResults(a["eff"][0]),
domain_str,
)
problem.add_action(act)

for a in domain_res.get("actions", []):
n = a["name"]
Expand Down Expand Up @@ -1323,7 +1442,6 @@ def declare_type(
has_actions_cost = (
has_actions_cost and self._instantaneous_action_has_cost(act)
)

for m in domain_res.get("methods", []):
assert isinstance(problem, htn.HierarchicalProblem)
name = m["name"]
Expand Down
4 changes: 0 additions & 4 deletions unified_planning/model/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,10 +879,6 @@ def clear_effects(self):
self._fluents_assigned = {}
self._fluents_inc_dec = set()

def __str__(self) -> str:
"""Return a string representation of the `Process`."""
return f"Process(name={self._name}, parameters={self._parameters})"

def _add_effect_instance(self, effect: "up.model.effect.Effect"):
assert (
effect.environment == self._environment
Expand Down
4 changes: 3 additions & 1 deletion unified_planning/model/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ def __repr__(self) -> str:
s.append("actions = [\n")
s.extend(map(custom_str, self.actions))
s.append("processes = [\n")
s.extend(map(custom_str, self.actions))
s.extend(map(custom_str, self.processes))
s.append("events = [\n")
s.extend(map(custom_str, self.events))
s.append("]\n\n")
if len(self.user_types) > 0:
s.append("objects = [\n")
Expand Down

0 comments on commit c16b2c4

Please sign in to comment.