Skip to content

Commit

Permalink
fix(interpreted functions): refactoring code
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Gobbi committed Nov 18, 2024
1 parent 0ee0782 commit 7cfd221
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ def _compile(

has_changed_fluents: Dict = {}
for a in problem.actions:
# these fluents are created and added to the problem at the start
# as might need some of them before we encounter them during the compilation
found_effects = self._get_effects(a)
for time, ef in found_effects:
f = ef.fluent.fluent()
Expand All @@ -262,6 +264,8 @@ def _compile(
old_goals = new_problem.goals
new_problem.clear_goals()
for goal_c in old_goals:
# the goal is modified in order to handle situations where
# the fluents contained in it have changed
g_c = goal_c
all_fluents_fnodes = self.free_vars_extractor.get(goal_c)
all_fluents = []
Expand All @@ -283,6 +287,12 @@ def _expand_action(
conds = []
effs = []
ifs = []
# ifs will contain a tuple with the information needed to remove the interpreted functions
# the time (None if instantaneous)
# the expression that contains some IFs
# the list of IFs contained in the expression
# the ElementKind
# the effect that is being handled (None if we are not on an effect)
for t, exp in self._get_conditions(a):
all_fluent_exps = self.free_vars_extractor.get(exp)
all_f = [f_exp.fluent() for f_exp in all_fluent_exps]
Expand Down Expand Up @@ -487,6 +497,7 @@ def _get_conditions(self, a):


def _split_ands(e):

templist = []
if e.is_and():
for sub in e.args:
Expand All @@ -500,6 +511,7 @@ def custom_replace(
action_instance: ActionInstance,
map: Dict["up.model.Action", Optional["up.model.Action"]],
) -> Optional[ActionInstance]:
# the default replace can't handle a different number of parameters
try:
replaced_action = map[action_instance.action]
except KeyError:
Expand Down Expand Up @@ -528,6 +540,8 @@ def custom_replace(


def knowledge_compatible(ifs, known, key_list):
# returns true if no conflicts are found and we have the necessary knowledge about the IFs in question

retval = True
kifuns = []
ukifuns = []
Expand Down
26 changes: 4 additions & 22 deletions unified_planning/engines/plan_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,6 @@ def _validate(
assert isinstance(plan, SequentialPlan)
assert isinstance(problem, Problem)
metric = None
hasif = False
calculated_interpreted_functions: Dict = {}
if (
problem.kind.has_interpreted_functions_in_conditions()
or problem.kind.has_interpreted_functions_in_numeric_assignments()
or problem.kind.has_interpreted_functions_in_boolean_assignments()
):
hasif = True
if len(problem.quality_metrics) > 0:
if len(problem.quality_metrics) == 1:
metric = problem.quality_metrics[0]
Expand Down Expand Up @@ -159,9 +151,6 @@ def _validate(
if unsat_conds:
assert reason == InapplicabilityReasons.VIOLATES_CONDITIONS
msg = f"Preconditions {unsat_conds} of {str(i)}-th action instance {str(ai)} are not satisfied."

if hasif:
calculated_interpreted_functions = simulator.get_knowledge()
else:
next_state = simulator.apply_unsafe(trace[-1], ai)
except UPUsageError as e:
Expand All @@ -181,7 +170,7 @@ def _validate(
reason=FailedValidationReason.INAPPLICABLE_ACTION,
inapplicable_action=ai,
trace=trace,
calculated_interpreted_functions=calculated_interpreted_functions,
calculated_interpreted_functions=simulator.get_interpreted_functions_values(),
)
assert next_state is not None
if metric is not None:
Expand Down Expand Up @@ -382,8 +371,7 @@ def _states_in_interval(
def _check_condition(
self, state: State, se: StateEvaluator, condition: FNode
) -> bool:
ret_val = se.evaluate(condition, state=state).bool_constant_value()
return ret_val
return se.evaluate(condition, state=state).bool_constant_value()

def _instantiate_timing(
self,
Expand Down Expand Up @@ -435,14 +423,6 @@ def _validate(
em = problem.environment.expression_manager
se = StateEvaluator(problem=problem)

hasif = False
if (
problem.kind.has_interpreted_functions_in_conditions()
or problem.kind.has_interpreted_functions_in_durations()
or problem.kind.has_interpreted_functions_in_numeric_assignments()
or problem.kind.has_interpreted_functions_in_boolean_assignments()
):
hasif = True
start_actions: List[Tuple[Fraction, ActionInstance, Optional[Fraction]]] = list(
plan.timed_actions
)
Expand Down Expand Up @@ -660,6 +640,7 @@ def _validate(
reason=FailedValidationReason.UNSATISFIED_GOALS,
inapplicable_action=None,
trace={k: v for k, v in trace.items() if k <= end},
calculated_interpreted_functions=se.if_values,
)

for g in problem.goals:
Expand All @@ -672,6 +653,7 @@ def _validate(
reason=FailedValidationReason.UNSATISFIED_GOALS,
inapplicable_action=None,
trace=trace,
calculated_interpreted_functions=se.if_values,
)

return ValidationResult(
Expand Down
2 changes: 1 addition & 1 deletion unified_planning/engines/sequential_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ def supported_kind() -> "up.model.ProblemKind":
def supports(problem_kind):
return problem_kind <= UPSequentialSimulator.supported_kind()

def get_knowledge(self):
def get_interpreted_functions_values(self):
return self._se.if_values


Expand Down
3 changes: 1 addition & 2 deletions unified_planning/model/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,14 +767,13 @@ def EqualsOrIff(
``left <-> right``
``left == right``
:param left: The ``left`` member of the ``EqualsOrIff expression``.
:param right: The ``right`` member of the ``EqualsOrIff expression``.
:return: The created ``Equals`` or ``Iff`` expression.
"""

left, right = self.auto_promote(left, right)
if (left.type.is_bool_type()) and (right.type.is_bool_type()):
if left.type.is_bool_type() and right.type.is_bool_type():

return self.create_node(node_type=OperatorKind.IFF, args=(left, right))
else:
Expand Down
14 changes: 0 additions & 14 deletions unified_planning/model/walkers/quantifier_simplifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,6 @@ def _compute_node_result(self, expression: "FNode", **kwargs):
self.memoization[key] = f(expression, args=expression.args, **kwargs)
else:
pass
for key in self.memoization:
if key.is_interpreted_function_exp():
args_values = [
self.memoization[self._get_key(s, **kwargs)]
for s in self._get_children(expression)
]
args_fluents = key.args
compatible_substitution = True
if len(args_fluents) != len(args_values):
compatible_substitution = False
for av, af in zip(args_values, args_fluents):
if not (af.type.is_compatible(av.type)):
compatible_substitution = False
result = self.memoization[key]

def _deep_subs_simplify(
self,
Expand Down
11 changes: 6 additions & 5 deletions unified_planning/model/walkers/simplifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from typing import List, Optional, FrozenSet, Union, cast
import unified_planning as up
import unified_planning.environment
from unified_planning.exceptions import UPUnreachableCodeError
import unified_planning.model.walkers as walkers
from unified_planning.model.fnode import FNode
from unified_planning.model.types import _UserType
Expand Down Expand Up @@ -345,15 +346,15 @@ def walk_interpreted_function_exp(
newlist.append(v)
constantval = expression.interpreted_function().function(*newlist)
if expression.interpreted_function().return_type.is_bool_type():
constantval = self.manager.Bool((constantval))
constantval = self.manager.Bool(constantval)
elif expression.interpreted_function().return_type.is_int_type():
constantval = self.manager.Int((constantval))
constantval = self.manager.Int(constantval)
elif expression.interpreted_function().return_type.is_real_type():
constantval = self.manager.Real((Fraction(constantval)))
constantval = self.manager.Real(Fraction(constantval))
elif expression.interpreted_function().return_type.is_user_type():
constantval = self.manager.ObjectExp((constantval))
constantval = self.manager.ObjectExp(constantval)

Check warning on line 355 in unified_planning/model/walkers/simplifier.py

View check run for this annotation

Codecov / codecov/patch

unified_planning/model/walkers/simplifier.py#L354-L355

Added lines #L354 - L355 were not covered by tests
else:
return new_exp
raise UPUnreachableCodeError

Check warning on line 357 in unified_planning/model/walkers/simplifier.py

View check run for this annotation

Codecov / codecov/patch

unified_planning/model/walkers/simplifier.py#L357

Added line #L357 was not covered by tests
return constantval

def walk_dot(self, expression: FNode, args: List[FNode]) -> FNode:
Expand Down
1 change: 0 additions & 1 deletion unified_planning/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,6 @@ def EqualsOrIff(left: Expression, right: Expression) -> FNode:
``left <-> right``
``left == right``
:param left: The ``left`` member of the ``EqualsOrIff expression``.
:param right: The ``right`` member of the ``EqualsOrIff expression``.
:return: The created ``Equals`` or ``Iff`` expression.
Expand Down

0 comments on commit 7cfd221

Please sign in to comment.