def reinstantiate_axiom(old_instance, init_facts=set(), fluent_facts=MockSet()): axiom = old_instance.axiom var_mapping = old_instance.var_mapping new_instance = axiom.instantiate(var_mapping, init_facts, fluent_facts) assert (new_instance is not None) return new_instance
def reinstantiate_action_instances(task, old_instances): import pddl import instantiate # Recomputes the instances with without any pruned preconditions fluents = get_fluents(task) function_assignments = { fact.fluent: fact.expression for fact in task.init if isinstance(fact, pddl.f_expression.FunctionAssignment) } type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) init_facts = set() fluent_facts = MockSet() new_instances = [] state = set(task.init) for old_instance in old_instances: # TODO: better way of instantiating conditional effects (when not fluent) #new_instance = reinstantiate_action(old_instance) predicate_to_atoms = instantiate.get_atoms_by_predicate({ a for a in state if isinstance(a, pddl.Atom) and (a.predicate in fluents) }) action = old_instance.action var_mapping = old_instance.var_mapping new_instance = action.instantiate(var_mapping, init_facts, fluent_facts, type_to_objects, task.use_min_cost_metric, function_assignments, predicate_to_atoms) assert (new_instance is not None) new_instances.append(new_instance) apply_action(state, new_instance) new_instances.append(get_goal_instance(task.goal)) # TODO: move this? return new_instances
def replace_derived(task, negative_init, action_instances): import pddl_to_prolog import build_model import axiom_rules import pddl original_actions = task.actions original_init = task.init task.actions = [] function_assignments = {f.fluent: f.expression for f in task.init if isinstance(f, pddl.f_expression.FunctionAssignment)} task.init = (set(task.init) | {a.negate() for a in negative_init}) - set(function_assignments) for instance in action_instances: #axiom_plan = extract_axiom_plan(task, instance, negative_from_name={}) # TODO: refactor this # TODO: just instantiate task? with Verbose(False): model = build_model.compute_model(pddl_to_prolog.translate(task)) # Changes based on init # fluent_facts = instantiate.get_fluent_facts(task, model) fluent_facts = MockSet() instantiated_axioms = instantiate_axioms(model, task.init, fluent_facts) goal_list = [] # TODO: include the goal? with Verbose(False): # TODO: helpful_axioms prunes axioms that are already true (e.g. not Unsafe) helpful_axioms, axiom_init, _ = axiom_rules.handle_axioms([instance], instantiated_axioms, goal_list) axiom_from_atom = get_achieving_axioms(task.init | negative_init | set(axiom_init), helpful_axioms) # negated_from_name=negated_from_name) axiom_plan = [] extract_axioms(axiom_from_atom, instance.precondition, axiom_plan) substitute_derived(axiom_plan, instance) assert(is_applicable(task.init, instance)) apply_action(task.init, instance) task.actions = original_actions task.init = original_init
def extract_axiom_plan(task, goals, negative_from_name, static_state=set()): import pddl_to_prolog import build_model import instantiate # TODO: only reinstantiate the negative axioms axioms_from_name = get_derived_predicates(task.axioms) derived_goals = {l for l in goals if l.predicate in axioms_from_name} axiom_from_action = get_necessary_axioms(derived_goals, task.axioms, negative_from_name) if not axiom_from_action: return [] conditions_from_predicate = defaultdict(set) for axiom, mapping in axiom_from_action.values(): for literal in get_literals(axiom.condition): conditions_from_predicate[literal.predicate].add(literal.rename_variables(mapping)) original_init = task.init original_actions = task.actions original_axioms = task.axioms # TODO: retrieve initial state based on if helpful task.init = {atom for atom in task.init if is_useful_atom(atom, conditions_from_predicate)} # TODO: store map from predicate to atom task.actions = axiom_from_action.keys() task.axioms = [] # TODO: maybe it would just be better to drop the negative throughout this process until this end with Verbose(False): model = build_model.compute_model(pddl_to_prolog.translate(task)) # Changes based on init task.actions = original_actions task.axioms = original_axioms opt_facts = instantiate.get_fluent_facts(task, model) | (task.init - static_state) mock_fluent = MockSet(lambda item: (item.predicate in negative_from_name) or (item in opt_facts)) instantiated_axioms = instantiate_necessary_axioms(model, static_state, mock_fluent, axiom_from_action) axiom_plan = extraction_helper(task.init, instantiated_axioms, derived_goals, negative_from_name) task.init = original_init return axiom_plan
def get_action_instances(task, action_plan): import pddl import instantiate type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) function_assignments = { f.fluent: f.expression for f in task.init if isinstance(f, pddl.f_expression.FunctionAssignment) } fluent_facts = MockSet() init_facts = set() action_instances = [] for name, objects in action_plan: # TODO: what if more than one action of the same name due to normalization? # Normalized actions have same effects, so I just have to pick one action = find_unique(lambda a: a.name == name, task.actions) args = map(pddl_from_object, objects) assert (len(action.parameters) == len(args)) variable_mapping = {p.name: a for p, a in zip(action.parameters, args)} instance = action.instantiate(variable_mapping, init_facts, fluent_facts, type_to_objects, task.use_min_cost_metric, function_assignments) assert (instance is not None) action_instances.append(instance) return action_instances
def reinstantiate_action_instances(task, old_instances): import pddl import instantiate # Recomputes the instances with without any pruned preconditions function_assignments = { fact.fluent: fact.expression for fact in task.init if isinstance(fact, pddl.f_expression.FunctionAssignment) } type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) init_facts = set() fluent_facts = MockSet() new_instances = [] for old_instance in old_instances: action = old_instance.action #if action is None: # new_instances.append(old_instance) # goal_instance var_mapping = old_instance.var_mapping new_instance = action.instantiate(var_mapping, init_facts, fluent_facts, type_to_objects, task.use_min_cost_metric, function_assignments) assert (new_instance is not None) new_instances.append(new_instance) new_instances.append(get_goal_instance(task.goal)) # TODO: move this? return new_instances
def reinstantiate_axiom_instances(old_instances): init_facts = set() fluent_facts = MockSet() new_instances = [] for old_instance in old_instances: axiom = old_instance.axiom var_mapping = old_instance.var_mapping new_instance = axiom.instantiate(var_mapping, init_facts, fluent_facts) assert (new_instance is not None) new_instances.append(new_instance) return new_instances
def extract_axiom_plan(task, action_instance, negative_from_name, static_state=set()): import pddl_to_prolog import build_model import axiom_rules import instantiate axioms_from_name = get_derived_predicates(task.axioms) derived_preconditions = {l for l in action_instance.precondition if l.predicate in axioms_from_name} nonderived_preconditions = {l for l in action_instance.precondition if l not in derived_preconditions} if not conditions_hold(task.init, nonderived_preconditions): return None axiom_from_action = get_necessary_axioms(action_instance, task.axioms, negative_from_name) if not axiom_from_action: return [] conditions_from_predicate = defaultdict(set) for axiom, mapping in axiom_from_action.values(): for literal in get_literals(axiom.condition): conditions_from_predicate[literal.predicate].add(literal.rename_variables(mapping)) original_init = task.init original_actions = task.actions original_axioms = task.axioms task.init = {atom for atom in task.init if is_useful_atom(atom, conditions_from_predicate)} # TODO: store map from predicate to atom task.actions = axiom_from_action.keys() task.axioms = [] # TODO: maybe it would just be better to drop the negative throughout this process until this end with Verbose(False): model = build_model.compute_model(pddl_to_prolog.translate(task)) # Changes based on init task.actions = original_actions task.axioms = original_axioms opt_facts = instantiate.get_fluent_facts(task, model) | (task.init - static_state) mock_fluent = MockSet(lambda item: (item.predicate in negative_from_name) or (item in opt_facts)) instantiated_axioms = instantiate_necessary_axioms(model, static_state, mock_fluent, axiom_from_action) goal_list = [] with Verbose(False): helpful_axioms, axiom_init, _ = axiom_rules.handle_axioms( [action_instance], instantiated_axioms, goal_list) axiom_init = set(axiom_init) axiom_effects = {axiom.effect for axiom in helpful_axioms} #assert len(axiom_effects) == len(axiom_init) for pre in list(derived_preconditions) + list(axiom_effects): if (pre not in axiom_init) and (pre.negate() not in axiom_init): axiom_init.add(pre.positive().negate()) axiom_from_atom = get_achieving_axioms(task.init | axiom_init, helpful_axioms, negative_from_name) axiom_plan = [] # Could always add all conditions success = extract_axioms(axiom_from_atom, derived_preconditions, axiom_plan, negative_from_name) task.init = original_init #if not success: # return None return axiom_plan
def instantiate_domain(task, prune_static=True): fluent_predicates = get_fluents(task) is_static = lambda a: isinstance(a, pddl.Atom) and (a.predicate not in fluent_predicates) fluent_facts = MockSet(lambda a: not prune_static or not is_static(a)) init_facts = set(task.init) function_assignments = get_function_assignments(task) type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) constants_from_predicate = defaultdict(set) for action in task.actions + task.axioms: for atom in filter(is_static, get_literals(get_precondition(action))): constants = tuple((i, a) for i, a in enumerate(atom.args) if not is_parameter(a)) constants_from_predicate[atom.predicate].add(constants) predicate_to_atoms = defaultdict(set) args_from_predicate = defaultdict(set) for atom in filter(is_static, task.init): # TODO: compute which predicates might involve constants predicate_to_atoms[atom.predicate].add(atom) args_from_predicate[atom.predicate].add(atom.args) for constants in constants_from_predicate[atom.predicate]: if all(atom.args[i] == o for i, o in constants): args_from_predicate[atom.predicate, constants].add(atom.args) instantiated_actions = [] for action in task.actions: for variable_mapping in instantiate_condition(action, is_static, args_from_predicate): inst_action = action.instantiate(variable_mapping, init_facts, fluent_facts, type_to_objects, task.use_min_cost_metric, function_assignments, predicate_to_atoms) if inst_action: instantiated_actions.append(inst_action) instantiated_axioms = [] for axiom in task.axioms: for variable_mapping in instantiate_condition(axiom, is_static, args_from_predicate): inst_axiom = axiom.instantiate(variable_mapping, init_facts, fluent_facts) if inst_axiom: instantiated_axioms.append(inst_axiom) reachable_facts, reachable_operators = get_achieving_axioms(init_facts, instantiated_actions + instantiated_axioms) atoms = {atom for atom in (init_facts | set(reachable_facts)) if isinstance(atom, pddl.Atom)} relaxed_reachable = all(literal_holds(init_facts, goal) or goal in reachable_facts for goal in instantiate_goal(task.goal)) reachable_actions = [action for action in reachable_operators if isinstance(action, pddl.PropositionalAction)] reachable_axioms = [axiom for axiom in reachable_operators if isinstance(axiom, pddl.PropositionalAxiom)] return relaxed_reachable, atoms, reachable_actions, reachable_axioms
def get_action_instances(task, action_plan): type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) function_assignments = get_function_assignments(task) predicate_to_atoms = instantiate.get_atoms_by_predicate(task.init) fluent_facts = MockSet() init_facts = set() action_instances = [] for name, objects in action_plan: # TODO: what if more than one action of the same name due to normalization? # Normalized actions have same effects, so I just have to pick one # TODO: conditional effects and internal parameters action = find_unique(lambda a: a.name == name, task.actions) args = list(map(pddl_from_object, objects)) variable_mapping = {p.name: a for p, a in safe_zip(action.parameters, args)} instance = action.instantiate(variable_mapping, init_facts, fluent_facts, type_to_objects, task.use_min_cost_metric, function_assignments, predicate_to_atoms) assert (instance is not None) action_instances.append(instance) return action_instances
def instantiate_actions(opt_task, type_to_objects, function_assignments, action_plan): action_instances = [] for name, args in action_plan: # TODO: negative atoms in actions candidates = [] for action in opt_task.actions: if action.name != name: continue if len(action.parameters) != len(args): raise NotImplementedError('Existential quantifiers are not currently ' 'supported in preconditions: {}'.format(name)) variable_mapping = {p.name: a for p, a in zip(action.parameters, args)} action_instance = action.instantiate(variable_mapping, set(), MockSet(), type_to_objects, opt_task.use_min_cost_metric, function_assignments) assert (action_instance is not None) candidates.append(((action, args), action_instance)) if not candidates: raise RuntimeError('Could not find an applicable action {}'.format(name)) action_instances.append(candidates) action_instances.append([(None, get_goal_instance(opt_task.goal))]) return action_instances
def simplify_actions(opt_evaluations, action_plan, task, actions, unit_costs): # TODO: add ordering constraints to simplify the optimization import pddl import instantiate fluent_facts = MockSet() init_facts = set() type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) results_from_head = get_results_from_head(opt_evaluations) action_from_name = {} function_plan = set() for i, (name, args) in enumerate(action_plan): action = find_unique(lambda a: a.name == name, actions) assert (len(action.parameters) == len(args)) # parameters = action.parameters[:action.num_external_parameters] var_mapping = {p.name: a for p, a in zip(action.parameters, args)} new_name = '{}-{}'.format(name, i) new_parameters = action.parameters[len(args):] new_preconditions = [] action.precondition.instantiate(var_mapping, init_facts, fluent_facts, new_preconditions) new_effects = [] for eff in action.effects: eff.instantiate(var_mapping, init_facts, fluent_facts, type_to_objects, new_effects) new_effects = [pddl.Effect([], pddl.Conjunction(conditions), effect) for conditions, effect in new_effects] cost = pddl.Increase(fluent=pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]), expression=pddl.NumericConstant(1)) # cost = None task.actions.append(pddl.Action(new_name, new_parameters, len(new_parameters), pddl.Conjunction(new_preconditions), new_effects, cost)) action_from_name[new_name] = (name, map(obj_from_pddl, args)) if not unit_costs: function_result = extract_function_results(results_from_head, action, args) if function_result is not None: function_plan.add(function_result) return action_from_name, list(function_plan)
def reinstantiate_action(state, instance, negative_from_name={}): # Recomputes the instances with without any pruned preconditions # TODO: making the assumption that no negative derived predicates action = instance.action var_mapping = instance.var_mapping init_facts = set() fluent_facts = MockSet() precondition = [] try: action.precondition.instantiate(var_mapping, init_facts, fluent_facts, precondition) except pddl.conditions.Impossible: return None precondition = list(set(precondition)) + instantiate_unsatisfiable( state, action, var_mapping, negative_from_name) effects = [] effect_from_literal = { literal: (cond, effect, effect_mapping) for cond, literal, effect, effect_mapping in instance.effect_mappings } for literal in instance.applied_effects: cond, effect, effect_mapping = effect_from_literal[literal] if effect is None: # Stream effect #effects.append((cond, literal, cond, effect)) continue else: effect._instantiate(effect_mapping, init_facts, fluent_facts, effects) new_effects = [] for cond, effect, e, m in effects: precondition.extend(cond) new_effects.append(([], effect, e, m)) return pddl.PropositionalAction(instance.name, precondition, new_effects, instance.cost, action, var_mapping)
def recover_stream_plan(evaluations, goal_expression, domain, stream_results, action_plan, negative, unit_costs, optimize=True): import pddl_to_prolog import build_model import pddl import axiom_rules import instantiate # Universally quantified conditions are converted into negative axioms # Existentially quantified conditions are made additional preconditions # Universally quantified effects are instantiated by doing the cartesian produce of types (slow) # Added effects cancel out removed effects opt_evaluations = evaluations_from_stream_plan(evaluations, stream_results) opt_task = task_from_domain_problem( domain, get_problem(opt_evaluations, goal_expression, domain, unit_costs)) real_task = task_from_domain_problem( domain, get_problem(evaluations, goal_expression, domain, unit_costs)) function_assignments = { fact.fluent: fact.expression for fact in opt_task.init # init_facts if isinstance(fact, pddl.f_expression.FunctionAssignment) } type_to_objects = instantiate.get_objects_by_type(opt_task.objects, opt_task.types) results_from_head = get_results_from_head(opt_evaluations) action_instances = [] for name, args in action_plan: # TODO: negative atoms in actions candidates = [] for action in opt_task.actions: if action.name != name: continue if len(action.parameters) != len(args): raise NotImplementedError( 'Existential quantifiers are not currently ' 'supported in preconditions: {}'.format(name)) variable_mapping = { p.name: a for p, a in zip(action.parameters, args) } instance = action.instantiate(variable_mapping, set(), MockSet(), type_to_objects, opt_task.use_min_cost_metric, function_assignments) assert (instance is not None) candidates.append(((action, args), instance)) if not candidates: raise RuntimeError( 'Could not find an applicable action {}'.format(name)) action_instances.append(candidates) action_instances.append([(None, get_goal_instance(opt_task.goal))]) axioms_from_name = get_derived_predicates(opt_task.axioms) negative_from_name = {n.name: n for n in negative} opt_task.actions = [] opt_state = set(opt_task.init) real_state = set(real_task.init) preimage_plan = [] function_plan = set() for layer in action_instances: for pair, instance in layer: nonderived_preconditions = [ l for l in instance.precondition if l.predicate not in axioms_from_name ] #nonderived_preconditions = instance.precondition if not conditions_hold(opt_state, nonderived_preconditions): continue opt_task.init = opt_state original_axioms = opt_task.axioms axiom_from_action = get_necessary_axioms(instance, original_axioms, negative_from_name) opt_task.axioms = [] opt_task.actions = axiom_from_action.keys() # TODO: maybe it would just be better to drop the negative throughout this process until this end with Verbose(False): model = build_model.compute_model( pddl_to_prolog.translate( opt_task)) # Changes based on init opt_task.axioms = original_axioms opt_facts = instantiate.get_fluent_facts( opt_task, model) | (opt_state - real_state) mock_fluent = MockSet(lambda item: ( item.predicate in negative_from_name) or (item in opt_facts)) instantiated_axioms = instantiate_necessary_axioms( model, real_state, mock_fluent, axiom_from_action) with Verbose(False): helpful_axioms, axiom_init, _ = axiom_rules.handle_axioms( [instance], instantiated_axioms, []) axiom_from_atom = get_achieving_axioms(opt_state, helpful_axioms, axiom_init, negative_from_name) axiom_plan = [] # Could always add all conditions extract_axioms(axiom_from_atom, instance.precondition, axiom_plan) # TODO: test if no derived solution # TODO: compute required stream facts in a forward way and allow opt facts that are already known required for effects in [instance.add_effects, instance.del_effects]: for i, (conditions, effect) in enumerate(effects[::-1]): if any(c.predicate in axioms_from_name for c in conditions): raise NotImplementedError( 'Conditional effects cannot currently involve derived predicates' ) if conditions_hold(real_state, conditions): # Holds in real state effects[i] = ([], effect) elif not conditions_hold(opt_state, conditions): # Does not hold in optimistic state effects.pop(i) else: # TODO: handle more general case where can choose to achieve particular conditional effects raise NotImplementedError( 'Conditional effects cannot currently involve certified predicates' ) #if any(conditions for conditions, _ in instance.add_effects + instance.del_effects): # raise NotImplementedError('Conditional effects are not currently supported: {}'.format(instance.name)) # TODO: add axiom init to reset state? apply_action(opt_state, instance) apply_action(real_state, instance) preimage_plan.extend(axiom_plan + [instance]) if not unit_costs and (pair is not None): function_plan.update( extract_function_results(results_from_head, *pair)) break else: raise RuntimeError('No action instances are applicable') preimage = plan_preimage(preimage_plan, set()) preimage -= set(real_task.init) negative_preimage = set( filter(lambda a: a.predicate in negative_from_name, preimage)) preimage -= negative_preimage # visualize_constraints(map(fact_from_fd, preimage)) # TODO: prune with rules # TODO: linearization that takes into account satisfied goals at each level # TODO: can optimize for all streams & axioms all at once for literal in negative_preimage: negative = negative_from_name[literal.predicate] instance = negative.get_instance(map(obj_from_pddl, literal.args)) value = not literal.negated if instance.enumerated: assert (instance.value == value) else: function_plan.add( PredicateResult(instance, value, opt_index=instance.opt_index)) node_from_atom = get_achieving_streams(evaluations, stream_results) preimage_facts = list( map(fact_from_fd, filter(lambda l: not l.negated, preimage))) stream_plan = [] extract_stream_plan(node_from_atom, preimage_facts, stream_plan) if not optimize: # TODO: detect this based on unique or not return stream_plan + list(function_plan) # TODO: search in space of partially ordered plans # TODO: local optimization - remove one and see if feasible reschedule_problem = get_problem(evaluations, And(*preimage_facts), domain, unit_costs=True) reschedule_task = task_from_domain_problem(domain, reschedule_problem) reschedule_task.actions, stream_result_from_name = get_stream_actions( stream_results) new_plan, _ = solve_from_task(reschedule_task, planner='max-astar', debug=False) # TODO: investigate admissible heuristics if new_plan is None: return stream_plan + list(function_plan) new_stream_plan = [stream_result_from_name[name] for name, _ in new_plan] return new_stream_plan + list(function_plan)
def sequential_stream_plan(evaluations, goal_expression, domain, stream_results, negated, unit_costs=True, **kwargs): if negated: raise NotImplementedError() # TODO: compute preimage and make that the goal instead opt_evaluations = evaluations_from_stream_plan(evaluations, stream_results) opt_task = task_from_domain_problem(domain, get_problem(opt_evaluations, goal_expression, domain, unit_costs)) action_plan, action_cost = solve_from_task(opt_task, **kwargs) if action_plan is None: return None, action_cost import instantiate fluent_facts = MockSet() init_facts = set() task = task_from_domain_problem(domain, get_problem(evaluations, goal_expression, domain, unit_costs)) type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) task.actions, stream_result_from_name = get_stream_actions(stream_results) results_from_head = get_results_from_head(opt_evaluations) # TODO: add ordering constraints to simplify the optimization import pddl action_from_name = {} function_plan = set() for i, (name, args) in enumerate(action_plan): action = find_unique(lambda a: a.name == name, domain.actions) assert(len(action.parameters) == len(args)) #parameters = action.parameters[:action.num_external_parameters] var_mapping = {p.name: a for p, a in zip(action.parameters, args)} new_name = '{}-{}'.format(name, i) new_parameters = action.parameters[len(args):] new_preconditions = [] action.precondition.instantiate(var_mapping, init_facts, fluent_facts, new_preconditions) new_effects = [] for eff in action.effects: eff.instantiate(var_mapping, init_facts, fluent_facts, type_to_objects, new_effects) new_effects = [pddl.Effect([], pddl.Conjunction(conditions), effect) for conditions, effect in new_effects] cost = pddl.Increase(fluent=pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]), expression=pddl.NumericConstant(1)) #cost = None task.actions.append(pddl.Action(new_name, new_parameters, 0, pddl.Conjunction(new_preconditions), new_effects, cost)) action_from_name[new_name] = (name, map(obj_from_pddl, args)) if not unit_costs: function_plan.update(extract_function_results(results_from_head, action, args)) planner = kwargs.get('planner', 'ff-astar') combined_plan, _ = solve_from_task(task, planner=planner, **kwargs) if combined_plan is None: return None, obj_from_pddl_plan(action_plan), INF stream_plan = [] action_plan = [] for name, args in combined_plan: if name in stream_result_from_name: stream_plan.append(stream_result_from_name[name]) else: action_plan.append(action_from_name[name]) stream_plan += list(function_plan) combined_plan = stream_plan + action_plan return combined_plan, action_cost
def reinstantiate_action(state, instance, negative_from_name={}): # Recomputes the instances with without any pruned preconditions # TODO: making the assumption that no negative derived predicates action = instance.action var_mapping = instance.var_mapping init_facts = set() fluent_facts = MockSet() precondition = [] try: action.precondition.instantiate(var_mapping, init_facts, fluent_facts, precondition) except pddl.conditions.Impossible: return None effects = [] effect_from_literal = { literal: (cond, effect, effect_mapping) for cond, literal, effect, effect_mapping in instance.effect_mappings } for effect in action.effects: if effect.literal.predicate == UNSATISFIABLE: # Condition must be false for plan to succeed conditions = set(get_conjunctive_parts(effect.condition)) negative = { literal for literal in conditions if literal.predicate in negative_from_name } if not negative: continue assert len(negative) == 1 # TODO: handle the case where negative is not used (not (CFree ..)) normal_conjunction = pddl.Conjunction(conditions - negative) # TODO: assumes that can instantiate with just predicate_to_atoms normal_effect = pddl.Effect(effect.parameters, normal_conjunction, effect.literal) # TODO: avoid recomputing these objects_by_type = instantiate.get_objects_by_type([], []) predicate_to_atoms = instantiate.get_atoms_by_predicate(state) result = [] normal_effect.instantiate(var_mapping, state, {effect.literal}, objects_by_type, predicate_to_atoms, result) for _, _, _, mapping in result: for literal in negative: new_literal = literal.rename_variables(mapping).negate() assert (not new_literal.free_variables()) precondition.append(new_literal) for literal in instance.applied_effects: cond, effect, effect_mapping = effect_from_literal[literal] if effect is None: # Stream effect #effects.append((cond, literal, cond, effect)) continue else: effect._instantiate(effect_mapping, init_facts, fluent_facts, effects) new_effects = [] for cond, effect, e, m in effects: precondition.extend(cond) new_effects.append(([], effect, e, m)) return pddl.PropositionalAction(instance.name, precondition, new_effects, instance.cost, action, var_mapping)