From 917a6c41e7de89d51ffe770dc62be47af9988a81 Mon Sep 17 00:00:00 2001 From: Gabriele Roeger Date: Wed, 31 Jan 2024 12:52:37 +0100 Subject: [PATCH] [issue913] fix instantiation bug with uninitialized numeric expressions --- src/translate/normalize.py | 24 ++++++++++++++++++++++-- src/translate/pddl_to_prolog.py | 7 +++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/translate/normalize.py b/src/translate/normalize.py index 375dc67e9c..e0c061956d 100755 --- a/src/translate/normalize.py +++ b/src/translate/normalize.py @@ -3,6 +3,7 @@ import copy import pddl +import pddl_to_prolog class ConditionProxy: def clone_owner(self): @@ -23,7 +24,19 @@ def delete_owner(self, task): def build_rules(self, rules): action = self.owner rule_head = get_action_predicate(action) - rule_body = condition_to_rule_body(action.parameters, self.condition) + + # if the action cost is based on a primitive numeric expression, + # we need to require that it has a value defined in the initial state. + # We hand it over to condition_to_rule_body to include this in the rule + # body. + pne = None + if (isinstance(action.cost, pddl.Increase) and + isinstance(action.cost.expression, + pddl.PrimitiveNumericExpression)): + pne = action.cost.expression + + rule_body = condition_to_rule_body(action.parameters, self.condition, + pne) rules.append((rule_body, rule_head)) def get_type_map(self): return self.owner.type_map @@ -366,10 +379,13 @@ def build_exploration_rules(task): proxy.build_rules(result) return result -def condition_to_rule_body(parameters, condition): +def condition_to_rule_body(parameters, condition, numeric_expression=None): result = [] + # require parameters to be of the right type for par in parameters: result.append(par.get_atom()) + + # require the given condition if not isinstance(condition, pddl.Truth): if isinstance(condition, pddl.ExistentialCondition): for par in condition.parameters: @@ -388,6 +404,10 @@ def condition_to_rule_body(parameters, condition): assert isinstance(part, pddl.Literal), "Condition not normalized: %r" % part if not part.negated: result.append(part) + + # require the numeric expression (from the action cost) to be defined. + if numeric_expression is not None: + result.append(pddl_to_prolog.get_definition_fluent(numeric_expression)) return result if __name__ == "__main__": diff --git a/src/translate/pddl_to_prolog.py b/src/translate/pddl_to_prolog.py index fee70f7c3b..8bbb9d57e7 100755 --- a/src/translate/pddl_to_prolog.py +++ b/src/translate/pddl_to_prolog.py @@ -142,6 +142,9 @@ def __str__(self): cond_str = ", ".join(map(str, self.conditions)) return "%s :- %s." % (self.effect, cond_str) +def get_definition_fluent(pne: pddl.PrimitiveNumericExpression): + return pddl.Atom(f"@def-{pne.symbol}", pne.args) + def translate_typed_object(prog, obj, type_dict): supertypes = type_dict[obj.type_name].supertype_names for type_name in [obj.type_name] + supertypes: @@ -155,6 +158,10 @@ def translate_facts(prog, task): assert isinstance(fact, pddl.Atom) or isinstance(fact, pddl.Assign) if isinstance(fact, pddl.Atom): prog.add_fact(fact) + else: + # Add a fact to indicate that the primitive numeric expression in + # fact.fluent has been defined. + prog.add_fact(get_definition_fluent(fact.fluent)) def translate(task): # Note: The function requires that the task has been normalized.