Skip to content

Commit

Permalink
Fix(FreeVarsExtractor & Oracle): Made FreeVarsExtractor and FreeVarsO…
Browse files Browse the repository at this point in the history
…racle to return a FrozenSet so it can't be modified from outside
  • Loading branch information
Framba-Luca committed Apr 11, 2024
1 parent f85d022 commit b3dac95
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 28 deletions.
8 changes: 5 additions & 3 deletions unified_planning/model/effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(
forall: Iterable["up.model.variable.Variable"] = tuple(),
):
fve = fluent.environment.free_vars_extractor
fluents_in_fluent = fve.get(fluent)
fluents_in_fluent = set(fve.get(fluent))
fluents_in_fluent.remove(fluent)
if fluents_in_fluent:
raise UPProblemDefinitionError(
Expand All @@ -72,15 +72,17 @@ def __init__(
self._condition = condition
self._kind = kind
fvo = fluent.environment.free_vars_oracle
free_vars: Set["up.model.variable.Variable"] = fvo.get_free_variables(fluent)
free_vars: Set["up.model.variable.Variable"] = set(
fvo.get_free_variables(fluent)
)
free_vars.update(fvo.get_free_variables(value))
free_vars.update(fvo.get_free_variables(condition))

def free_vars_without_duplicates() -> Iterator["up.model.variable.Variable"]:
# store seen variables to avoid duplicates
seen: Set["up.model.variable.Variable"] = set()
for v in forall:
if v in free_vars and not v in seen:
if v in free_vars and v not in seen:
seen.add(v)
assert isinstance(
v, up.model.variable.Variable
Expand Down
28 changes: 14 additions & 14 deletions unified_planning/model/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"""


from typing import List, Optional, Set
from typing import List, Optional, FrozenSet
from unified_planning.environment import Environment, get_environment
from unified_planning.model.fnode import FNode
from unified_planning.model.operators import OperatorKind
Expand Down Expand Up @@ -179,36 +179,36 @@ class FreeVarsOracle(walkers.DagWalker):
# - Other operators need to return the union of all their sons
# - Constants have no impact

def get_free_variables(self, expression: FNode) -> Set[Variable]:
"""Returns the set of Symbols appearing free in the expression."""
def get_free_variables(self, expression: FNode) -> FrozenSet[Variable]:
"""Returns the FrozenSet of Symbols appearing free in the expression."""
return self.walk(expression)

@walkers.handles(OperatorKind.VARIABLE_EXP)
def walk_variable_exp(
self, expression: FNode, args: List[Set[Variable]], **kwargs
) -> Set[Variable]:
self, expression: FNode, args: List[FrozenSet[Variable]], **kwargs
) -> FrozenSet[Variable]:
# pylint: disable=unused-argument
return {expression.variable()}
return frozenset((expression.variable(),))

@walkers.handles(OperatorKind.EXISTS, OperatorKind.FORALL)
def walk_quantifier(
self, expression: FNode, args: List[Set[Variable]], **kwargs
) -> Set[Variable]:
self, expression: FNode, args: List[FrozenSet[Variable]], **kwargs
) -> FrozenSet[Variable]:
# pylint: disable=unused-argument
return args[0].difference(expression.variables())

@walkers.handles(op.CONSTANTS)
def walk_constant(
self, expression: FNode, args: List[Set[Variable]], **kwargs
) -> Set[Variable]:
self, expression: FNode, args: List[FrozenSet[Variable]], **kwargs
) -> FrozenSet[Variable]:
# pylint: disable=unused-argument
return set()
return frozenset()

@walkers.handles(
set(OperatorKind)
- {OperatorKind.VARIABLE_EXP, OperatorKind.EXISTS, OperatorKind.FORALL}
)
def walk_all(
self, expression: FNode, args: List[Set[Variable]], **kwargs
) -> Set[Variable]:
return {v for s in args for v in s}
self, expression: FNode, args: List[FrozenSet[Variable]], **kwargs
) -> FrozenSet[Variable]:
return frozenset(v for s in args for v in s)
22 changes: 11 additions & 11 deletions unified_planning/model/walkers/free_vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
# limitations under the License.
#

from itertools import chain
import unified_planning.model.walkers as walkers
from unified_planning.model.fnode import FNode
from unified_planning.model.operators import OperatorKind
from typing import List, Set
from typing import List, FrozenSet


class FreeVarsExtractor(walkers.dag.DagWalker):
Expand All @@ -25,21 +26,20 @@ class FreeVarsExtractor(walkers.dag.DagWalker):
def __init__(self):
walkers.dag.DagWalker.__init__(self)

def get(self, expression: FNode) -> Set[FNode]:
def get(self, expression: FNode) -> FrozenSet[FNode]:
"""
Returns all the `fluent expressions` in the given expression.
:param expression: The expression containing the `fluent expressions` to be returned.
:return: The set of `fluent expressions` appearing in the given expression.
:return: The FrozenSet of `fluent expressions` appearing in the given expression.
"""
ret = self.walk(expression)
return (
ret.copy()
) # return a copy, otherwise modifications of the returned set will invalidate memoization
return self.walk(expression)

@walkers.handles(OperatorKind)
def walk_all_types(self, expression: FNode, args: List[Set[FNode]]) -> Set[FNode]:
res = set(x for y in args for x in y)
def walk_all_types(
self, expression: FNode, args: List[FrozenSet[FNode]]
) -> FrozenSet[FNode]:
res_generator = (x for y in args for x in y)
if expression.is_fluent_exp():
res |= {expression}
return res
res_generator = chain(res_generator, (expression,))
return frozenset(res_generator)

0 comments on commit b3dac95

Please sign in to comment.