def recover_negative_axioms(real_task, opt_task, axiom_plans, action_plan, negative_from_name): action_plan = reinstantiate_action_instances( opt_task, action_plan, negative_from_name=negative_from_name) # https://github.com/caelan/pddlstream/commit/18b303e19bbab9f8e0016fbb2656f461067e1e94#diff-55454a85485551f9139e20a446b56a83L53 #simplify_conditional_effects(opt_task, action_plan, negative_from_name) axiom_plans = list(map(reinstantiate_axiom_instances, axiom_plans)) axioms_from_name = get_derived_predicates(opt_task.axioms) # TODO: could instead just accumulate difference between real and opt opt_task.init = set(opt_task.init) real_states = [set(real_task.init)] preimage_plan = [] for axiom_plan, action_instance in safe_zip(axiom_plans, action_plan): preimage = [ l for l in plan_preimage(axiom_plan + [action_instance]) if (l.predicate in axioms_from_name) ] #assert conditions_hold(opt_task.init, conditions) # TODO: only add derived facts and negative facts to fluent state to make normalizing easier negative_axiom_plan = extract_axiom_plan(opt_task, preimage, negative_from_name, static_state=opt_task.init) #static_state=real_states[-1]) assert negative_axiom_plan is not None preimage_plan.extend(negative_axiom_plan + axiom_plan + [action_instance]) if action_instance.name != GOAL_NAME: apply_action(opt_task.init, action_instance) real_states.append(set(real_states[-1])) apply_action(real_states[-1], action_instance) return real_states, preimage_plan
def __init__(self, instantiated, action_instances=[]): derived_predicates = get_derived_predicates(instantiated.task.axioms) conditions = { literal.positive() for axiom in instantiated.axioms for literal in axiom.condition } state = set(instantiated.task.init) fluents = get_fluents(state, action_instances) & conditions self.fluent_order = list(fluents) applicable_axioms = [] axiom_from_literal = defaultdict(list) # TODO: could also just use get_achieving_axioms self.root = SuccessorNode() for axiom in instantiated.axioms: if all((l.predicate in derived_predicates) or ( l.positive() in fluents) or literal_holds(state, l) for l in axiom.condition): applicable_axioms.append(axiom) for literal in axiom.condition: if literal in fluents: axiom_from_literal[literal].append(axiom) fluent_conds = { l.positive(): not l.negated for l in axiom.condition } node = self.root for atom in self.fluent_order: value = fluent_conds.get(atom, None) node = node.get_child(value) node.instances.append(axiom)
def recover_axioms_plans(instantiated, action_instances): #axioms, axiom_init, _ = axiom_rules.handle_axioms( # instantiated.actions, instantiated.axioms, instantiated.goal_list) new_action_instances = [ copy.deepcopy(instance) for instance in action_instances ] axioms, axiom_init = instantiated.axioms, [ ] # TODO: bug when needing to reachieve negated axioms_from_effect = defaultdict(list) for axiom in axioms: axioms_from_effect[axiom.effect].append(axiom) axioms_from_name = get_derived_predicates(instantiated.task.axioms) state = set(instantiated.task.init) | set(axiom_init) axiom_plans = [] for action in new_action_instances + [ get_goal_instance(instantiated.task.goal) ]: all_conditions = list(get_precondition(action)) + list( flatten(cond for cond, _ in action.add_effects + action.del_effects)) axioms = backtrack_axioms(all_conditions, axioms_from_effect, set()) axiom_from_atom, _ = get_achieving_axioms(state, axioms) action.applied_effects = [] for effects in [action.add_effects, action.del_effects]: negate = (effects is action.del_effects) for i, (conditions, effect) in reversed(list(enumerate(effects))): if all( literal_holds(state, literal) or ( literal in axiom_from_atom) for literal in conditions): action.precondition.extend(conditions) effects[i] = ([], effect) action.applied_effects.append( effect.negate() if negate else effect) else: effects.pop(i) # RuntimeError: Preimage fact ('new-axiom@0',) is not achievable! #precondition = action.precondition # TODO: strange bug if this applies precondition = [ literal for literal in action.precondition if literal.predicate in axioms_from_name ] axiom_plans.append([]) success = extract_axioms(state, axiom_from_atom, precondition, axiom_plans[-1]) if not success: print(all_conditions) print(action) print(axioms) raise RuntimeError('Could not extract axioms') apply_action(state, action) return new_action_instances, axiom_plans
def get_necessary_axioms(conditions, axioms, negative_from_name): if not conditions or not axioms: return {} axioms_from_name = get_derived_predicates(axioms) atom_queue = [] processed_atoms = set() def add_literals(literals): for lit in literals: atom = lit.positive() if atom not in processed_atoms: atom_queue.append( atom) # Previously was lit.positive() for some reason? processed_atoms.add(atom) add_literals(conditions) axiom_from_action = {} partial_instantiations = set() while atom_queue: literal = atom_queue.pop() for axiom in axioms_from_name[literal.predicate]: derived_parameters = axiom.parameters[:axiom. num_external_parameters] var_mapping = { p.name: a for p, a in zip(derived_parameters, literal.args) if not is_parameter(a) } key = (axiom, frozenset(var_mapping.items())) if key in partial_instantiations: continue partial_instantiations.add(key) parts = [ l.rename_variables(var_mapping) for l in get_literals(axiom.condition) if l.predicate not in negative_from_name ] # Assumes a conjunction? # new_condition = axiom.condition.uniquify_variables(None, var_mapping) effect_args = [ var_mapping.get(a.name, a.name) for a in derived_parameters ] effect = pddl.Effect([], pddl.Truth(), pddl.conditions.Atom(axiom.name, effect_args)) free_parameters = [ p for p in axiom.parameters if p.name not in var_mapping ] new_action = pddl.Action(axiom.name, free_parameters, len(free_parameters), pddl.Conjunction(parts), [effect], None) # Creating actions so I can partially instantiate (impossible with axioms) axiom_from_action[new_action] = (axiom, var_mapping) add_literals(parts) return axiom_from_action
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 if not negative_from_name: return [] axioms_from_name = get_derived_predicates(task.axioms) derived_goals = {l for l in goals if l.predicate in axioms_from_name} assert all( literal_holds(task.init, l) # or (l.predicate in negative_from_name) for l in set(goals) - derived_goals) 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(verbose=False): model = build_model.compute_model( pddl_to_prolog.translate(task)) # Changes based on init 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 task.actions = original_actions task.axioms = original_axioms return axiom_plan