Source code for up_SMT_engine.helper_functions.PartialOrderPlanFix
import unified_planning as up
import unified_planning.plans as plans
from typing import Callable, Dict, List, Optional
[docs]def custom_replace_action_instances(
plan,
replace_function: Callable[
["plans.plan.ActionInstance"], Optional["plans.plan.ActionInstance"]
],
) -> "plans.plan.Plan":
"""
Custom function for replacing action instances of a partial_order_plan
The original function has two errors. First for plans of length 1 with no successors the plan is discarded.
Second the successors are duplicated.
Returns a new `PartialOrderPlan` where every `ActionInstance` of the current plan is replaced using the given `replace_function`.
:param replace_function: The function that applied to an `ActionInstance A` returns the `ActionInstance B`; `B`
replaces `A` in the resulting `Plan`.
:return: The `PartialOrderPlan` where every `ActionInstance` is replaced using the given `replace_function`.
"""
new_adj_list: Dict[
"plans.plan.ActionInstance", List["plans.plan.ActionInstance"]
] = {}
# The approach used is to generate equivalent keys for all nodes first, then add successors later.
# This is done because successors need to map exactly to the corresponding node object, and so
# the replace_function can only be called once per unique object.
new_key_dict = {}
# First add all replaced nodes as keys, but leave successors for later
for node in plan._graph.nodes:
key = replace_function(node)
if key is not None:
new_key_dict[node] = key
# Populate the new adjacency dictionary with the replaced action instances
# It is easier to match instances using the adjacency dict
for node in plan._graph.nodes:
if node in new_key_dict:
key = new_key_dict[node]
replaced_neighbors = []
for successor in plan._graph.neighbors(node):
if successor in new_key_dict:
replaced_neighbors.append(new_key_dict[successor])
if len(replaced_neighbors) > 0:
new_adj_list[key] = replaced_neighbors
# This is the only functional change to this part of the code. Without this
# else plans of length 1 are lost
else:
new_adj_list[key] = []
new_env = plan._environment
for ai in new_adj_list.keys():
new_env = ai.action.env
break
return up.plans.PartialOrderPlan(new_adj_list, new_env)