Skip to content

Commit

Permalink
Merge pull request #598 from aiplan4eu/durative-action-costs-pddl-par…
Browse files Browse the repository at this point in the history
…sing

PDDL Parsing durative actions costs
  • Loading branch information
alvalentini committed May 6, 2024
2 parents 1bea679 + c0fb5f6 commit ee56971
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 21 deletions.
61 changes: 44 additions & 17 deletions unified_planning/io/pddl_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,13 +974,16 @@ def _durative_action_has_cost(self, dur_act: up.model.DurativeAction):
for c in cl:
if self._totalcost in self._fve.get(c):
return False
cost_found = False
for _, el in dur_act.effects.items():
for e in el:
if (
self._totalcost in self._fve.get(e.fluent)
or self._totalcost in self._fve.get(e.value)
or self._totalcost in self._fve.get(e.condition)
):
if self._totalcost in self._fve.get(e.fluent):
if cost_found:
return False
cost_found = True
if self._totalcost in self._fve.get(
e.value
) or self._totalcost in self._fve.get(e.condition):
return False
return True

Expand Down Expand Up @@ -1640,24 +1643,48 @@ def declare_type(
and optimization == "minimize"
and metric_exp == self._totalcost
):
costs = {}
costs: Dict[up.model.Action, up.model.Expression] = {}
problem._fluents.remove(self._totalcost.fluent())
if self._totalcost in problem._initial_value:
problem._initial_value.pop(self._totalcost)
use_plan_length = all(False for _ in problem.durative_actions)
for a in problem.instantaneous_actions:
cost = None
for e in a.effects:
if e.fluent == self._totalcost:
cost = e
break
if cost is not None:
costs[a] = cost.value
a._effects.remove(cost)
if cost.value != 1:
start_timing, end_timing = (
up.model.StartTiming(),
up.model.EndTiming(),
)
for a in problem.actions:
if isinstance(a, up.model.InstantaneousAction):
cost = None
for e in a.effects:
if e.fluent == self._totalcost:
cost = e
break
if cost is not None:
costs[a] = cost.value
a._effects.remove(cost)
if cost.value != 1:
use_plan_length = False
else:
use_plan_length = False
else:
assert isinstance(a, up.model.DurativeAction)
use_plan_length = False
cost, effects_list = None, None
for timing, el in a.effects.items():
if timing in (start_timing, end_timing):
for e in el:
if e.fluent == self._totalcost:
if cost is not None:
raise UPUnsupportedProblemTypeError(
f"Action {a.name} has more than one effect modifying it's cost"
)
cost, effects_list = e, el
break
if cost is not None:
assert effects_list is not None
costs[a] = cost.value
effects_list.remove(cost)
else:
use_plan_length = False
if use_plan_length:
problem.add_quality_metric(
up.model.metrics.MinimizeSequentialPlanLength()
Expand Down
8 changes: 4 additions & 4 deletions unified_planning/test/examples/minimals.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ def get_example_problems():
problem.add_fluent(y)
problem.add_action(da)
problem.set_initial_value(x, False)
problem.add_timed_effect(StartTiming(5), x, False)
problem.add_timed_effect(GlobalStartTiming(5), x, False)
problem.set_initial_value(y, False)
problem.add_timed_effect(StartTiming(2), y, True)
problem.add_timed_effect(StartTiming(8), y, False)
problem.add_timed_effect(GlobalStartTiming(2), y, True)
problem.add_timed_effect(GlobalStartTiming(8), y, False)
problem.add_goal(x)
t_plan = up.plans.TimeTriggeredPlan([(Fraction(6), da(), Fraction(1))])
invalid_t_plans: List[up.plans.Plan] = [
Expand Down Expand Up @@ -486,7 +486,7 @@ def get_example_problems():
problem.add_action(task)
problem.set_initial_value(value, 1)
problem.add_goal(Equals(value, 2))
problem.add_timed_effect(StartTiming(1), value, 1)
problem.add_timed_effect(GlobalStartTiming(1), value, 1)
t_plan = up.plans.TimeTriggeredPlan(
[(Fraction(2), up.plans.ActionInstance(task), None)]
)
Expand Down
85 changes: 85 additions & 0 deletions unified_planning/test/pddl/parking_action_cost/domain.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
(define (domain parking)
(:requirements :strips :typing :durative-actions)
(:types car curb)
(:predicates
(at-curb ?car - car)
(at-curb-num ?car - car ?curb - curb)
(behind-car ?car ?front-car - car)
(car-clear ?car - car)
(curb-clear ?curb - curb)
)

(:functions (total-cost))
(:durative-action move-curb-to-curb
:parameters (?car - car ?curbsrc ?curbdest - curb)
:duration (= ?duration 1)
:condition (and
(at start (car-clear ?car))
(at start (curb-clear ?curbdest))
(at start (at-curb-num ?car ?curbsrc))
)
:effect (and
(at start (not (curb-clear ?curbdest)))
(at end (curb-clear ?curbsrc))
(at end (at-curb-num ?car ?curbdest))
(at start (not (at-curb-num ?car ?curbsrc)))
(at end (increase (total-cost) 1))
)
)

(:durative-action move-curb-to-car
:parameters (?car - car ?curbsrc - curb ?cardest - car)
:duration (= ?duration 2)
:condition (and
(at start (car-clear ?car))
(at start (car-clear ?cardest))
(at start (at-curb-num ?car ?curbsrc))
(at start (at-curb ?cardest))
)
:effect (and
(at start (not (car-clear ?cardest)))
(at end (curb-clear ?curbsrc))
(at end (behind-car ?car ?cardest))
(at start (not (at-curb-num ?car ?curbsrc)))
(at start (not (at-curb ?car)))
(at end (increase (total-cost) 2))
)
)

(:durative-action move-car-to-curb
:parameters (?car - car ?carsrc - car ?curbdest - curb)
:duration (= ?duration 2)
:condition (and
(at start (car-clear ?car))
(at start (curb-clear ?curbdest))
(at start (behind-car ?car ?carsrc))
)
:effect (and
(at start (not (curb-clear ?curbdest)))
(at end (car-clear ?carsrc))
(at end (at-curb-num ?car ?curbdest))
(at start (not (behind-car ?car ?carsrc)))
(at end (at-curb ?car))
(at end (increase (total-cost) 2))
)
)

(:durative-action move-car-to-car
:parameters (?car - car ?carsrc - car ?cardest - car)
:duration (= ?duration 3)
:condition (and
(at start (car-clear ?car))
(at start (car-clear ?cardest))
(at start (behind-car ?car ?carsrc))
(at start (at-curb ?cardest))
)
:effect (and
(at start (not (car-clear ?cardest)))
(at end (car-clear ?carsrc))
(at end (behind-car ?car ?cardest))
(at start (not (behind-car ?car ?carsrc)))
(at end (increase (total-cost) 3))
)
)
)

23 changes: 23 additions & 0 deletions unified_planning/test/pddl/parking_action_cost/problem.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
(define (problem parking)
(:domain parking)
(:objects
car_00 car_01 - car
curb_00 curb_01 curb_02 curb_03 - curb
)
(:init
(at-curb-num car_00 curb_00)
(at-curb-num car_01 curb_01)
(curb-clear curb_02)
(curb-clear curb_03)
(car-clear car_00)
(car-clear car_01)
(= (total-cost) 0)
)
(:goal
(and
(at-curb-num car_00 curb_02)
(at-curb-num car_01 curb_03)
)
)
(:metric minimize (total-cost))
)
27 changes: 27 additions & 0 deletions unified_planning/test/test_pddl_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,33 @@ def test_matchcellar_reader(self):
problem_2 = reader.parse_problem_string(domain_str, problem_str)
self.assertEqual(problem, problem_2)

def test_parking_reader(self):
reader = PDDLReader()

domain_filename = os.path.join(
PDDL_DOMAINS_PATH, "parking_action_cost", "domain.pddl"
)
problem_filename = os.path.join(
PDDL_DOMAINS_PATH, "parking_action_cost", "problem.pddl"
)
problem = reader.parse_problem(domain_filename, problem_filename)

self.assertIsNotNone(problem)
self.assertEqual(len(problem.fluents), 5)
self.assertEqual(len(problem.actions), 4)
self.assertEqual(len(list(problem.objects(problem.user_type("car")))), 2)
self.assertEqual(len(list(problem.objects(problem.user_type("curb")))), 4)
self.assertEqual(len(problem.quality_metrics), 1)
self.assertTrue(problem.quality_metrics[0].is_minimize_action_costs())

with open(domain_filename, "r", encoding="utf-8") as file:
domain_str = file.read()
with open(problem_filename, "r", encoding="utf-8") as file:
problem_str = file.read()

problem_2 = reader.parse_problem_string(domain_str, problem_str)
self.assertEqual(problem, problem_2)

def _test_htn_transport_reader(self, problem):
assert isinstance(problem, up.model.htn.HierarchicalProblem)
self.assertEqual(5, len(problem.fluents))
Expand Down

0 comments on commit ee56971

Please sign in to comment.