Skip to content

Commit

Permalink
fix(interpreted functions): fix for booleans use iff instead of equals
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Gobbi committed Oct 14, 2024
1 parent 7046cdf commit f506207
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 41 deletions.
24 changes: 12 additions & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,18 +302,18 @@ jobs:
cd ENHSP-Public; git checkout enhsp20-0.14.0; bash ./compile; cd ..
bash -c "mkdir .planners; mv ENHSP-Public/enhsp-dist .planners/enhsp-20; rm -rf ENHSP-Public"
#- name: Checkout up-enhsp
# uses: actions/checkout@v2
# with:
# repository: aiplan4eu/up-enhsp
# path: up-enhsp
# ref: ${{env.up_enhsp_commit}}
#
#- name: Install up-enhsp
# run: python3 -m pip install up-enhsp/
#
#- name: Run tests
# run: bash run_tests.sh
- name: Checkout up-enhsp
uses: actions/checkout@v2
with:
repository: aiplan4eu/up-enhsp
path: up-enhsp
ref: ${{env.up_enhsp_commit}}

- name: Install up-enhsp
run: python3 -m pip install up-enhsp/

- name: Run tests
run: bash run_tests.sh

run-tests-macos:
runs-on: macos-13
Expand Down
99 changes: 88 additions & 11 deletions unified_planning/engines/compilers/interpreted_functions_remover.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import unified_planning as up
import unified_planning.engines as engines
from unified_planning.model.interpreted_function import InterpretedFunction
from unified_planning.model.timing import StartTiming
from unified_planning.model.walkers.substituter import Substituter
from unified_planning.model.walkers.operators_extractor import OperatorsExtractor
from unified_planning.model.operators import OperatorKind
Expand Down Expand Up @@ -293,19 +294,48 @@ def _compile(
]
)
if new_condition is None:
new_condition = new_action.environment.expression_manager.Equals(
aif._content.args[argumentcounter],
kf._content.args[argumentcounter],
)

else:
new_condition = new_action.environment.expression_manager.And(
new_condition,
new_action.environment.expression_manager.Equals(
if aif._content.args[
argumentcounter
].type.is_bool_type():
# is this ok?
new_condition = new_action.environment.expression_manager.Iff(
aif._content.args[argumentcounter],
kf._content.args[argumentcounter],
)
else:
new_condition = new_action.environment.expression_manager.Equals(
aif._content.args[argumentcounter],
kf._content.args[argumentcounter],
),
)
)

else:
if aif._content.args[
argumentcounter
].type.is_bool_type():
# is this ok?
new_condition = new_action.environment.expression_manager.And(
new_condition,
new_action.environment.expression_manager.Iff(
aif._content.args[
argumentcounter
],
kf._content.args[
argumentcounter
],
),
)
else:
new_condition = new_action.environment.expression_manager.And(
new_condition,
new_action.environment.expression_manager.Equals(
aif._content.args[
argumentcounter
],
kf._content.args[
argumentcounter
],
),
)

argumentcounter = argumentcounter + 1
new_action.add_precondition(new_condition)
Expand Down Expand Up @@ -335,16 +365,37 @@ def _compile(
no_IF_action = a.clone()
minduration: FNode | int = 1
maxduration: FNode | int = 1000000
IF_in_durations = list()

if not (
OperatorKind.INTERPRETED_FUNCTION_EXP
in self.operators_extractor.get(a.duration.lower)
):
minduration = a.duration.lower
else:
IFs = self.interpreted_functions_extractor.get(a.duration.lower)
if len(IFs) != 0: # get all the IFs in the precondition
for f in IFs:
if f not in IF_in_durations:
# and append them in the key list if not already there
IF_in_durations.append(f)

IFs = None
if not (
OperatorKind.INTERPRETED_FUNCTION_EXP
in self.operators_extractor.get(a.duration.upper)
):
maxduration = a.duration.upper
else:
IFs = self.interpreted_functions_extractor.get(a.duration.upper)
if len(IFs) != 0: # get all the IFs in the precondition
for f in IFs:
if f not in IF_in_durations:
# and append them in the key list if not already there
IF_in_durations.append(f)
print("compiler with knowledge:")
# print (IF_in_durations)
# print (self._interpreted_functions_values)

no_IF_action.set_closed_duration_interval(minduration, maxduration)
# print("after duration part of the remover")
Expand All @@ -365,6 +416,32 @@ def _compile(
in precondition_operators
):
no_IF_action.add_condition(ii, fc)
kifid = []
for kif in self._interpreted_functions_values:
for ifid in IF_in_durations:
if kif._content.payload.__eq__(ifid._content.payload):
if kif not in kifid:
kifid.append(ifid)
print("found a match:")
print(kif)
print(ifid)
condition_to_avoid = None
i = 0
while i < len(kif.args):
print(ifid.args[i])
print("should not be")
print(kif.args[i])
# have to do the combination thing
temp_cond = no_IF_action.environment.expression_manager.Not(
no_IF_action.environment.expression_manager.Equals(
ifid.args[i], kif.args[i]
)
)
no_IF_action.add_condition(StartTiming(), temp_cond)

i = i + 1

# no_IF_action.add_condition(StartTiming(), condition_to_avoid)
no_IF_action.name = get_fresh_name(new_problem, a.name)
new_to_old[no_IF_action] = a
new_problem.add_action(no_IF_action)
Expand Down
20 changes: 10 additions & 10 deletions unified_planning/engines/interpreted_functions_planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,16 @@ def _attempt_to_solve(
else:
# temporary skip for ttp

if isinstance(mappedbackplan, TimeTriggeredPlan):
print("temporary skip for ttp")
if self._debug_print_final_problem:
print(new_problem)
return PlanGenerationResult(
validation_result.status,
mappedbackplan,
self.name,
log_messages=res.log_messages,
)
# if isinstance(mappedbackplan, TimeTriggeredPlan):
# print("temporary skip for ttp")
# if self._debug_print_final_problem:
# print(new_problem)
# return PlanGenerationResult(
# validation_result.status,
# mappedbackplan,
# self.name,
# log_messages=res.log_messages,
# )

refined_problem = _refine(self, problem, validation_result)
if refined_problem is None:
Expand Down
41 changes: 39 additions & 2 deletions unified_planning/engines/plan_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from dataclasses import dataclass
from fractions import Fraction
import heapq
from typing import Any, Dict, Generator, List, Optional, Set, Tuple, cast
from typing import Any, Dict, Generator, List, Optional, OrderedDict, Set, Tuple, cast
import warnings
import unified_planning as up
import unified_planning.environment
Expand Down Expand Up @@ -166,6 +166,7 @@ def _validate(
msg = f"{str(i)}-th action instance {str(ai)} creates Conflicting Effects: {str(e)}"
if msg is not None:
logs = [LogMessage(LogLevel.INFO, msg)]
# print (cif)
return ValidationResult(
status=ValidationResultStatus.INVALID,
engine_name=self.name,
Expand Down Expand Up @@ -423,7 +424,10 @@ def _validate(
cif = None

hasif = False
if problem.kind.has_interpreted_functions_in_conditions():
if (
problem.kind.has_interpreted_functions_in_conditions()
or problem.kind.has_interpreted_functions_in_durations()
):
hasif = True
start_actions: List[Tuple[Fraction, ActionInstance, Optional[Fraction]]] = list(
plan.timed_actions
Expand Down Expand Up @@ -628,6 +632,39 @@ def _validate(
print(
"this thing does not have a simulator like the sequential ones ;-;"
)
print(opt_ai.action)
ife: up.model.walkers.InterpretedFunctionsExtractor = (
up.model.walkers.InterpretedFunctionsExtractor()
)
ifl = ife.get(opt_ai.action.duration.lower)
ifu = ife.get(opt_ai.action.duration.upper)
ifc = []
for ii, cl in opt_ai.action.conditions.items():

for c in cl:
ifc.append(ife.get(c))

# print (ifl)
# print (ifu)
# print (ifc)
# print(trace)
cif = OrderedDict()
for lll in ifl:
fp = lll._content.payload
fa = lll._content.args # aka args
fc = lll._content.payload.function
# print (fc)
notOkParams = list()
for fan in fa:
notOkParams.append(state.get_value(fan))

# print (fp)
# print (fa)
print(fp(*notOkParams))
print(fc(*notOkParams))
cif[fp(*notOkParams)] = fc(
*notOkParams
) # does not use memoization
return ValidationResult(
status=ValidationResultStatus.INVALID,
engine_name=self.name,
Expand Down
13 changes: 7 additions & 6 deletions unified_planning/test/examples/complex_interpreted_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def simple_always_false(ind):
return False

s_simple_always_false = OrderedDict()
s_simple_always_false["ind"] = IntType()
s_simple_always_false["ind"] = BoolType()
IF_simple_always_false = InterpretedFunction(
"simple_always_false", BoolType(), s_simple_always_false, simple_always_false
)
Expand All @@ -58,15 +58,16 @@ def simple_always_false(ind):
ione = Fluent("ione", IntType(0, 20))
itwo = Fluent("itwo", IntType(0, 20))
ithree = Fluent("ithree", IntType(0, 20))
ifour = Fluent("ifour", IntType(0, 20))
ifour = Fluent("ifour", BoolType())
a = InstantaneousAction("a")
a.add_precondition(And(IF_integers_to_bool(ione, itwo), LT(ione, 15)))
a.add_precondition(LT(g, 10))
a.add_effect(g, Plus(g, 3))
b = InstantaneousAction("b")
b.add_precondition(
And(
And(IF_integers_to_bool(itwo, itwo), GT(simple_int_to_int(ithree), 5)), True
And(IF_integers_to_bool(itwo, itwo), GT(IF_simple_int_to_int(ithree), 5)),
True,
)
)
b.add_effect(g, Plus(g, 5))
Expand All @@ -75,10 +76,10 @@ def simple_always_false(ind):
d = InstantaneousAction("d")
d.add_effect(ione, Minus(ione, 1))
e = InstantaneousAction("e")
e.add_precondition(simple_always_false(ifour))
e.add_precondition(IF_simple_always_false(ifour))
e.add_effect(g, 5)
f = InstantaneousAction("f")
f.add_precondition(And(GT(ione, simple_int_to_int(ithree))))
f.add_precondition(And(GT(ione, IF_simple_int_to_int(ithree))))
f.add_effect(itwo, 5)
problem = Problem("IF_in_conditions_complex_1")
problem.add_fluent(g)
Expand All @@ -96,7 +97,7 @@ def simple_always_false(ind):
problem.set_initial_value(ione, 11)
problem.set_initial_value(itwo, 1)
problem.set_initial_value(ithree, 15)
problem.set_initial_value(ifour, 15)
problem.set_initial_value(ifour, False)
problem.add_goal(GE(g, 5))

ifproblem = TestCase(
Expand Down

0 comments on commit f506207

Please sign in to comment.