Skip to content

Commit

Permalink
updated kinds and documentation, separated functions for increase/dec…
Browse files Browse the repository at this point in the history
…rease
  • Loading branch information
Samuel Gobbi committed Jan 10, 2025
1 parent 5ffee71 commit e83b326
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 32 deletions.
15 changes: 15 additions & 0 deletions docs/problem_representation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ Problem Kinds
* -
- SELF_OVERLAPPING
- The temporal planning problem allows actions self overlapping.
* -
- PROCESSES
- The problem contains processes, natural transitions that occur automatically over time as their pre-conditions are met.
* -
- EVENTS
- The problem contains events, natural transitions that occur automatically at a single time point when their pre-conditions are met.
* - EXPRESSION_DURATION
- STATIC_FLUENTS_IN_DURATION
- The duration of at least one action uses static fluents (that may never change).
Expand Down Expand Up @@ -111,6 +117,15 @@ Problem Kinds
* -
- DECREASE_EFFECTS
- At least one effect uses the numeric decrement operator.
* -
- INCREASE_CONTINUOUS_EFFECTS
- At least one effect uses the continuous numeric increment operator.
* -
- DECREASE_CONTINUOUS_EFFECTS
- At least one effect uses the continuous numeric decrement operator.
* -
- NON_LINEAR_CONTINUOUS_EFFECTS
- At least one continuous effect is described by a differential equation that depends on a continuous variable.
* -
- STATIC_FLUENTS_IN_BOOLEAN_ASSIGNMENTS
- At least one effect uses a static fluent in the expression of a boolean assignment.
Expand Down
6 changes: 3 additions & 3 deletions unified_planning/io/pddl_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ def _add_effect(

if isinstance(act, up.model.Process):
eff1 = (eff[0], eff[1].simplify())
act.add_derivative(*eff1)
act.add_continuous_increase(*eff1)
else:
act.add_increase_effect(*eff if timing is None else (timing, *eff)) # type: ignore
elif op == "decrease":
Expand All @@ -669,8 +669,8 @@ def _add_effect(
cond,
)
if isinstance(act, up.model.Process):
eff1 = (eff[0], (eff[1] * (-1)).simplify())
act.add_derivative(*eff1)
eff1 = (eff[0], eff[1].simplify())
act.add_continuous_decrease(*eff1)
else:
act.add_decrease_effect(*eff if timing is None else (timing, *eff)) # type: ignore
elif op == "forall":
Expand Down
2 changes: 1 addition & 1 deletion unified_planning/io/pddl_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,7 @@ def _write_derivative(
out.write(f" (increase {fluent} (* #t {converter.convert(simplified_value)} ))")
elif effect.is_decrease():
out.write(f" (decrease {fluent} (* #t {converter.convert(simplified_value)} ))")
elif effect.is_derivative():
elif effect.is_continuous_increase() or effect.is_continuous_decrease():
out.write(f" (increase {fluent} (* #t {converter.convert(simplified_value)} ))")
else:
raise UPProblemDefinitionError(
Expand Down
20 changes: 13 additions & 7 deletions unified_planning/model/effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ class EffectKind(Enum):
`ASSIGN` => `if C then F <= V`
`INCREASE` => `if C then F <= F + V`
`DECREASE` => `if C then F <= F - V`
`DERIVATIVE` => `dF/dt <= V`
`CONTINUOUS_INCREASE` => `dF/dt <= V`
`CONTINUOUS_DECREASE` => `dF/dt <= -V`
"""

ASSIGN = auto()
INCREASE = auto()
DECREASE = auto()
DERIVATIVE = auto()
CONTINUOUS_INCREASE = auto()
CONTINUOUS_DECREASE = auto()


class Effect:
Expand Down Expand Up @@ -111,15 +113,15 @@ def __repr__(self) -> str:
s.append(f"forall {', '.join(str(v) for v in self._forall)}")
if self.is_conditional():
s.append(f"if {str(self._condition)} then")
if not (self.is_derivative()):
if not (self.is_continuous_increase() or self.is_continuous_decrease()):
s.append(f"{str(self._fluent)}")
if self.is_assignment():
s.append(":=")
elif self.is_increase():
s.append("+=")
elif self.is_decrease():
s.append("-=")
elif self.is_derivative():
elif self.is_continuous_increase() or self.is_continuous_decrease():
s.append(f"d{str(self._fluent)}/dt =")
s.append(f"{str(self._value)}")
return " ".join(s)
Expand Down Expand Up @@ -250,9 +252,13 @@ def is_decrease(self) -> bool:
"""Returns `True` if the :func:`kind <unified_planning.model.Effect.kind>` of this `Effect` is a `decrease`, `False` otherwise."""
return self._kind == EffectKind.DECREASE

def is_derivative(self) -> bool:
"""Returns `True` if the :func:`kind <unified_planning.model.Effect.kind>` of this `Effect` is a `derivative`, `False` otherwise."""
return self._kind == EffectKind.DERIVATIVE
def is_continuous_increase(self) -> bool:
"""Returns `True` if the :func:`kind <unified_planning.model.Effect.kind>` of this `Effect` is a `continuous increase`, `False` otherwise."""
return self._kind == EffectKind.CONTINUOUS_INCREASE

def is_continuous_decrease(self) -> bool:
"""Returns `True` if the :func:`kind <unified_planning.model.Effect.kind>` of this `Effect` is a `continuous decrease`, `False` otherwise."""
return self._kind == EffectKind.CONTINUOUS_DECREASE


class SimulatedEffect:
Expand Down
64 changes: 49 additions & 15 deletions unified_planning/model/natural_transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,12 @@ def _add_effect_instance(self, effect: "up.model.effect.Effect"):

self._effects.append(effect)

def add_derivative(
def _add_continuous_effect(
self,
fluent: Union["up.model.fnode.FNode", "up.model.fluent.Fluent"],
value: "up.model.expression.Expression",
negative: bool,
):
"""
Adds the given `time derivative effect` to the `process's effects`.
:param fluent: The `fluent` is the numeric state variable of which this process expresses its time derivative, which in Newton's notation would be over-dot(fluent).
:param value: This is the actual time derivative function. For instance, `fluent = 4` expresses that the time derivative of `fluent` is 4.
"""
(
fluent_exp,
value_exp,
Expand All @@ -166,15 +161,54 @@ def add_derivative(
)
if not fluent_exp.type.is_int_type() and not fluent_exp.type.is_real_type():
raise UPTypeError("Derivative can be created only on numeric types!")
self._add_effect_instance(
up.model.effect.Effect(
fluent_exp,
value_exp,
condition_exp,
kind=up.model.effect.EffectKind.DERIVATIVE,
forall=tuple(),
if not negative:
self._add_effect_instance(
up.model.effect.Effect(
fluent_exp,
value_exp,
condition_exp,
kind=up.model.effect.EffectKind.CONTINUOUS_INCREASE,
forall=tuple(),
)
)
)
else:
self._add_effect_instance(
up.model.effect.Effect(
fluent_exp,
value_exp,
condition_exp,
kind=up.model.effect.EffectKind.CONTINUOUS_DECREASE,
forall=tuple(),
)
)

def add_continuous_increase(
self,
fluent: Union["up.model.fnode.FNode", "up.model.fluent.Fluent"],
value: "up.model.expression.Expression",
):
"""
Adds the given `continuous increase effect` to the `process's effects`.
NOTE description might be outdated
:param fluent: The `fluent` is the numeric state variable of which this process expresses its continuous increase, which in Newton's notation would be over-dot(fluent).
:param value: This is the actual time derivative function. For instance, `fluent = 4` expresses that the time derivative of `fluent` is 4.
"""
self._add_continuous_effect(fluent, value, False)

def add_continuous_decrease(
self,
fluent: Union["up.model.fnode.FNode", "up.model.fluent.Fluent"],
value: "up.model.expression.Expression",
):
"""
Adds the given `continuous decrease effect` to the `process's effects`.
NOTE description might be outdated
:param fluent: The `fluent` is the numeric state variable of which this process expresses its continuous decrease, which in Newton's notation would be over-dot(fluent).
:param value: This is the actual time derivative function. For instance, `fluent = 4` expresses that the time derivative of `fluent` is 4.
"""
self._add_continuous_effect(fluent, value, True)


class Event(UntimedEffectMixin, NaturalTransition):
Expand Down
20 changes: 20 additions & 0 deletions unified_planning/model/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,8 @@ def _kind_factory(self) -> "_KindFactory":
factory.update_problem_kind_initial_state(self)
if len(list(self.processes)) > 0:
factory.kind.set_time("PROCESSES")
if len(list(self.events)) > 0:
factory.kind.set_time("EVENTS")

return factory

Expand Down Expand Up @@ -884,6 +886,10 @@ def update_problem_kind_effect(
self.kind.set_effects_kind("STATIC_FLUENTS_IN_OBJECT_ASSIGNMENTS")
if any(f not in self.static_fluents for f in fluents_in_value):
self.kind.set_effects_kind("FLUENTS_IN_OBJECT_ASSIGNMENTS")
elif e.is_continuous_increase():
self.kind.unset_problem_type("SIMPLE_NUMERIC_PLANNING")
elif e.is_continuous_decrease():
self.kind.unset_problem_type("SIMPLE_NUMERIC_PLANNING")

def update_problem_kind_expression(
self,
Expand Down Expand Up @@ -1027,6 +1033,20 @@ def update_problem_kind_action(
for t, le in action.effects.items():
for e in le:
self.update_action_timed_effect(t, e)
continuous_fluents = set()
fluents_in_rhs = set()
# TODO
for t, le in action.effects.items():
for e in le:
self.update_action_timed_effect(t, e)
continuous_fluents.add(e.fluent.fluent)
rhs = self.simplifier.simplify(e.value)
for var in self.environment.free_vars_extractor.get(rhs):
if var.is_fluent_exp():
fluents_in_rhs.add(var.fluent)
if any(variable in fluents_in_rhs for variable in continuous_fluents):
self.kind.set_effects_kind("NON_LINEAR_CONTINUOUS_EFFECTS")

if len(action.simulated_effects) > 0:
self.kind.set_simulated_entities("SIMULATED_EFFECTS")
self.kind.set_time("CONTINUOUS_TIME")
Expand Down
4 changes: 4 additions & 0 deletions unified_planning/model/problem_kind.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"DURATION_INEQUALITIES",
"SELF_OVERLAPPING",
"PROCESSES",
"EVENTS",
],
"EXPRESSION_DURATION": [
"STATIC_FLUENTS_IN_DURATIONS",
Expand All @@ -70,6 +71,9 @@
"CONDITIONAL_EFFECTS",
"INCREASE_EFFECTS",
"DECREASE_EFFECTS",
"INCREASE_CONTINUOUS_EFFECTS",
"DECREASE_CONTINUOUS_EFFECTS",
"NON_LINEAR_CONTINUOUS_EFFECTS",
"STATIC_FLUENTS_IN_BOOLEAN_ASSIGNMENTS",
"STATIC_FLUENTS_IN_NUMERIC_ASSIGNMENTS",
"STATIC_FLUENTS_IN_OBJECT_ASSIGNMENTS",
Expand Down
6 changes: 3 additions & 3 deletions unified_planning/test/examples/processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def get_example_problems():

b = Process("moving")
b.add_precondition(on)
b.add_derivative(d, 1)
b.add_continuous_increase(d, 1)

problem = Problem("1d_Movement")
problem.add_fluent(on)
Expand Down Expand Up @@ -54,11 +54,11 @@ def get_example_problems():

water_heating = Process("water_heating")
water_heating.add_precondition(And(boiler_on, LE(temperature, 100)))
water_heating.add_derivative(temperature, 1)
water_heating.add_continuous_increase(temperature, 1)

water_boiling = Process("water_boiling")
water_boiling.add_precondition(And(boiler_on, GE(temperature, 100)))
water_boiling.add_derivative(water_level, -1)
water_boiling.add_continuous_decrease(water_level, 1)

open_chimney_vent_auto = Event("open_chimney_vent_auto")
open_chimney_vent_auto.add_precondition(
Expand Down
7 changes: 5 additions & 2 deletions unified_planning/test/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,12 @@ def test_process(self):
x = Fluent("x", IntType())
move = Process("moving", car=Vehicle)
move.add_precondition(a)
move.add_derivative(x, 1)
move.add_continuous_increase(x, 1)
e = Effect(
FluentExp(x), Int(1), TRUE(), unified_planning.model.EffectKind.DERIVATIVE
FluentExp(x),
Int(1),
TRUE(),
unified_planning.model.EffectKind.CONTINUOUS_INCREASE,
)
self.assertEqual(move.effects[0], e)
self.assertEqual(move.name, "moving")
Expand Down
5 changes: 4 additions & 1 deletion unified_planning/test/test_pddl_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,10 @@ def test_non_linear_car(self):
for ele in problem.processes:
if isinstance(ele, Process):
for e in ele.effects:
self.assertEqual(e.kind, EffectKind.DERIVATIVE)
self.assertTrue(
(e.kind == EffectKind.CONTINUOUS_INCREASE)
or (e.kind == EffectKind.CONTINUOUS_DECREASE)
)
if ele.name == "drag_ahead":
found_drag_ahead = True
self.assertTrue("engine_running" in str(ele))
Expand Down

0 comments on commit e83b326

Please sign in to comment.