def transform_exp_actions(actions, mutex_groups): """ Exponential transformation of actions with sdac into actions with constant action costs. """ mutex_dict = dict() for group in mutex_groups: for elem in group: mutex_dict[elem] = group del_actions = [] new_actions = actions add_actions = [] for action in new_actions: if isinstance(action.cost, pddl_parser.CostNode): del_actions.append(action) if not is_usefull(action): continue at_list = [] consistent_actions = [] used_dict = dict() for atom in action.cost.get_atoms_set(): if atom not in mutex_dict: at_list.append( [atom, pddl.NegatedAtom(atom.predicate, atom.args)]) elif len(mutex_dict[atom]) == 1: at_list.append( [atom, pddl.NegatedAtom(atom.predicate, atom.args)]) elif str(mutex_dict[atom]) not in used_dict: at_list.append(mutex_dict[atom]) used_dict[str(mutex_dict[atom])] = True for combi in itertools.product(*at_list): pre = [] pre.extend(action.precondition) pre.extend(combi) if not is_consistent(combi, action.precondition, mutex_dict): continue if isinstance(action, pddl.Action): action_copy = pddl.Action(action.name, action.parameters, action.num_external_parameters, pre, action.effects, str(action.cost.get_cost(combi))) else: action_copy = pddl.PropositionalAction( action.name, pre, [], str(action.cost.get_cost(combi))) action_copy.add_effects.extend(action.add_effects) action_copy.del_effects.extend(action.del_effects) consistent_actions.append(action_copy) add_actions.extend(consistent_actions) for a in del_actions: new_actions.remove(a) new_actions.extend(add_actions) return new_actions
def add_inequality_preconds(self, action, reachable_action_params): if reachable_action_params is None or len(action.parameters) < 2: return action inequal_params = [] combs = itertools.combinations(range(len(action.parameters)), 2) for pos1, pos2 in combs: inequality = True for params in reachable_action_params[action.name]: if params[pos1] == params[pos2]: inequality = False break if inequality: inequal_params.append((pos1, pos2)) if inequal_params: precond_parts = list(action.precondition.parts) for pos1, pos2 in inequal_params: param1 = action.parameters[pos1].name param2 = action.parameters[pos2].name new_cond = pddl.NegatedAtom("=", (param1, param2)) precond_parts.append(new_cond) precond = action.precondition.change_parts(precond_parts) return pddl.Action(action.name, action.parameters, precond, action.effects, action.cost) else: return action
def add_inequality_preconds(self, action, reachable_action_params): if reachable_action_params is None or len(action.parameters) < 2: return action new_cond_parts = [] combs = itertools.combinations(range(len(action.parameters)), 2) for pos1, pos2 in combs: for params in reachable_action_params[action.name]: if params[pos1] == params[pos2]: break else: param1 = pddl.Variable(action.parameters[pos1].name) param2 = pddl.Variable(action.parameters[pos2].name) new_cond = pddl.NegatedAtom("=", (param1, param2)) new_cond_parts.append(new_cond) if new_cond_parts: new_cond = list(action.condition) for time in (0, 2): # add inequalities to start and end condition cond_parts = list(action.condition[time].parts) if isinstance(action.condition[time], pddl.Literal): cond_parts = [action.condition[time]] cond_parts.extend(new_cond_parts) cond = pddl.Conjunction(cond_parts) new_cond[time] = cond return pddl.DurativeAction(action.name, action.parameters, action.grounding_call, action.duration, new_cond, action.effects) else: return action
def add_inequality_preconds(self, action, reachable_action_params): if reachable_action_params is None or len(action.parameters) < 2: return action inequal_params = [] combs = itertools.combinations(range(len(action.parameters)), 2) for pos1, pos2 in combs: for params in reachable_action_params[action]: if params[pos1] == params[pos2]: break else: inequal_params.append((pos1, pos2)) if inequal_params: precond_parts = [action.precondition] for pos1, pos2 in inequal_params: param1 = action.parameters[pos1].name param2 = action.parameters[pos2].name new_cond = pddl.NegatedAtom("=", (param1, param2)) precond_parts.append(new_cond) precond = pddl.Conjunction(precond_parts).simplified() return pddl.Action( action.name, action.parameters, action.num_external_parameters, precond, action.effects, action.cost) else: return action
def convert_condition(condition): import pddl class_name = condition.__class__.__name__ if class_name in ('Truth', 'FunctionComparison'): # TODO: currently ignoring numeric conditions return pddl.Truth() elif class_name == 'Atom': return pddl.Atom(condition.predicate, convert_args(condition.args)) elif class_name == 'NegatedAtom': return pddl.NegatedAtom(condition.predicate, convert_args(condition.args)) elif class_name == 'Conjunction': return pddl.conditions.Conjunction( list(map(convert_condition, condition.parts))) elif class_name == 'Disjunction': return pddl.Disjunction(list(map(convert_condition, condition.parts))) elif class_name == 'ExistentialCondition': return pddl.ExistentialCondition( convert_parameters(condition.parameters), list(map(convert_condition, condition.parts))) elif class_name == 'UniversalCondition': return pddl.UniversalCondition( convert_parameters(condition.parameters), list(map(convert_condition, condition.parts))) raise NotImplementedError(class_name)
def add_unsatisfiable_to_goal(domain, goal_expression): import pddl from pddlstream.language.optimizer import UNSATISFIABLE add_predicate(domain, make_predicate(UNSATISFIABLE, [])) negated_atom = pddl.NegatedAtom(UNSATISFIABLE, tuple()) for action in domain.actions: if negated_atom not in action.precondition.parts: action.precondition = pddl.Conjunction( [action.precondition, negated_atom]).simplified() return And(goal_expression, Not((UNSATISFIABLE, )))
def fd_from_evaluation(evaluation): name = evaluation.head.function args = tuple(map(pddl_from_object, evaluation.head.args)) if is_atom(evaluation): return pddl.Atom(name, args) elif is_negated_atom(evaluation): return pddl.NegatedAtom(name, args) fluent = pddl.f_expression.PrimitiveNumericExpression(symbol=name, args=args) expression = pddl.f_expression.NumericConstant(evaluation.value) return pddl.f_expression.Assign(fluent, expression)
def add_unsatisfiable_to_goal(domain, goal_expression, negate_actions=False): import pddl add_predicate(domain, make_predicate(UNSATISFIABLE, [])) if negate_actions: negated_atom = pddl.NegatedAtom(UNSATISFIABLE, tuple()) for action in domain.actions: if negated_atom not in action.precondition.parts: action.precondition = pddl.Conjunction( [action.precondition, negated_atom]).simplified() return And(goal_expression, Not((UNSATISFIABLE, )))
def build_evmdd_actions_rek(evm, action_list, action, cost_atoms, aux_dict, mutex_dict, weight, val, first, parent_aux, parent_level, visited): aux_string = "evmdd-aux-" + action.name[1:-1].replace(" ", "-") + "-" is_first = first if str(type(evm)) == "<class 'evmdd.evmdd.Node'>": if evm in visited: return visited[evm] = True for i in range(0, len(evm.children)): build_evmdd_actions_rek(evm.children[i], action_list, action, cost_atoms, aux_dict, mutex_dict, weight, i, is_first, aux_dict[evm], evm.level, visited) elif str(type(evm)) == "<class 'evmdd.evmdd.Edge'>": if is_first: aux_atom = pddl.Atom(aux_string + aux_dict[evm.succ], []) action_copy = pddl.PropositionalAction(action.name[:-1] + "-init-", action.precondition, [], str(evm.weight)) action_copy.add_effects.append(([], aux_atom)) aux_atom_init = pddl.Atom("evmdd-aux-init", []) action_copy.add_effects.append(([], aux_atom_init)) action_copy.precondition.append(aux_atom_init.negate()) is_first = False else: if not evm.succ.is_sink_node(): aux_atom = pddl.Atom(aux_string + aux_dict[evm.succ], []) aux_pre_atom = pddl.Atom(aux_string + parent_aux, []) pre_atom = cost_atoms[parent_level - 1] if val == 0: pre_atom = pddl.NegatedAtom(pre_atom.predicate, pre_atom.args) pre_copy = [] pre_copy.append(aux_pre_atom) pre_copy.append(pre_atom) pre_atom_str = str(pre_atom.predicate) for a in pre_atom.args: pre_atom_str += "-" + str(a) pre_atom_str += "=" + str(val) + "-" action_copy = pddl.PropositionalAction( action.name[:-1] + "-" + pre_atom_str, pre_copy, [], str(evm.weight)) if evm.succ.is_sink_node(): action_copy.add_effects.extend(action.add_effects) action_copy.del_effects.append(([], aux_pre_atom)) action_copy.del_effects.extend(action.del_effects) aux_atom_init = pddl.Atom("evmdd-aux-init", []) action_copy.del_effects.append(([], aux_atom_init)) else: action_copy.add_effects.append(([], aux_atom)) action_copy.del_effects.append(([], aux_pre_atom)) action_list.append(action_copy) build_evmdd_actions_rek(evm.succ, action_list, action, cost_atoms, aux_dict, mutex_dict, evm.weight, -1, is_first, parent_aux, parent_level, visited)
def get_action_str(sas_task, task): out_str = "" if options.evmdd: sas_operator_names = [] else: sas_operator_names = [op.name[1:-1] for op in sas_task.operators] for pddl_op in task.inst_actions: pddl_op_name = pddl_op.name[1:-1] if isinstance(pddl_op.cost, str): if options.evmdd or pddl_op_name in sas_operator_names: out_str += "(:action " + pddl_op_name.replace( " ", "-") + "-" + pddl_op.cost out_str += "\n" + ":parameters ()" precon_str = "\n:precondition (and " eff_list = [] for atom in pddl_op.precondition: if atom.negated: precon_str += "(not (" else: precon_str += "(" precon_str += atom.predicate + " " for arg in atom.args: precon_str += arg + " " if atom.negated: precon_str += "))" else: precon_str += ")" for eff in pddl_op.add_effects: eff_list.append(eff[1]) for eff in pddl_op.del_effects: eff_list.append( pddl.NegatedAtom(eff[1].predicate, eff[1].args)) out_str += precon_str + ")" eff_str = "\n:effect (and " for atom in eff_list: if atom.negated: eff_str += "(not (" else: eff_str += "(" eff_str += atom.predicate + " " for arg in atom.args: eff_str += arg + " " if atom.negated: eff_str += "))" else: eff_str += ")" out_str += eff_str + "(increase (total-cost) " + pddl_op.cost + "))" out_str += ")\n" return out_str
def augment_goal(domain, goal_expression, negate_actions=False): # TODO: only do this if optimizers are present #return goal_expression import pddl predicate = pddl.predicates.Predicate(UNSATISFIABLE, tuple()) if predicate.name not in domain.predicate_dict: domain.predicates.append(predicate) domain.predicate_dict[predicate.name] = predicate if negate_actions: negated_atom = pddl.NegatedAtom(UNSATISFIABLE, tuple()) for action in domain.actions: if negated_atom not in action.precondition.parts: action.precondition = pddl.Conjunction( [action.precondition, negated_atom]).simplified() return And(goal_expression, Not((UNSATISFIABLE, )))
def recurse(condition): # Uses new_axioms_by_condition and type_map from surrounding scope. if isinstance(condition, pddl.UniversalCondition): axiom_condition = condition.negate() parameters = sorted(axiom_condition.free_variables()) typed_parameters = tuple(pddl.TypedObject(v, type_map[v]) for v in parameters) axiom = new_axioms_by_condition.get((axiom_condition, typed_parameters)) if not axiom: condition = recurse(axiom_condition) axiom = task.add_axiom(list(typed_parameters), condition) new_axioms_by_condition[(condition, typed_parameters)] = axiom return pddl.NegatedAtom(axiom.name, parameters) else: new_parts = [recurse(part) for part in condition.parts] return condition.change_parts(new_parts)
def recurse(condition): # Uses new_axioms_by_condition and type_map from surrounding scope. if isinstance(condition, pddl.UniversalCondition): axiom_condition = condition.negate() parameters = axiom_condition.free_variables() axiom = new_axioms_by_condition.get(axiom_condition) if not axiom: typed_parameters = [pddl.TypedObject(v, type_map[v]) for v in parameters] condition = recurse(axiom_condition) axiom = task.add_axiom(typed_parameters, condition) new_axioms_by_condition[condition] = axiom return pddl.NegatedAtom(axiom.name, [pddl.conditions.parse_term(par) for par in parameters]) else: new_parts = [recurse(part) for part in condition.parts] return condition.change_parts(new_parts)
def create_evmdd_action(action): #TODO action parameters? name = action.name[1:-1] eff_list = [] #TODO conditional effects? for eff in action.add_effects: eff_list.append(eff[1]) for eff in action.del_effects: eff_list.append(pddl.NegatedAtom(eff[1].predicate, eff[1].args)) prec_facts = [] eff_facts = [] for prec in action.precondition: prec_facts.append(atom_to_mdd_fact(prec)) for eff in eff_list: eff_facts.append(atom_to_mdd_fact(eff)) return Action(name, prec_facts, eff_facts, get_cost_function(action.cost))
def parse_literal(alist, type_dict, predicate_dict, negated=False): if alist[0] == "not": assert len(alist) == 2 alist = alist[1] negated = not negated pred_id, arity = _get_predicate_id_and_arity(alist[0], type_dict, predicate_dict) if arity != len(alist) - 1: raise SystemExit("predicate used with wrong arity: (%s)" % " ".join(alist)) if negated: return pddl.NegatedAtom(pred_id, alist[1:]) else: return pddl.Atom(pred_id, alist[1:])
def get_init(init_evaluations, negated=False): # TODO: this doesn't include = init = [] for evaluation in init_evaluations: name = evaluation.head.function args = tuple(map(pddl_from_object, evaluation.head.args)) if is_atom(evaluation): init.append(pddl.Atom(name, args)) elif negated and is_negated_atom(evaluation): init.append(pddl.NegatedAtom(name, args)) else: fluent = pddl.f_expression.PrimitiveNumericExpression(symbol=name, args=args) expression = pddl.f_expression.NumericConstant( evaluation.value) # Integer init.append(pddl.f_expression.Assign(fluent, expression)) return init
def lit_replacement(condition, obj_map): if isinstance(condition, pddl.Literal): if isinstance(condition, pddl.Atom): return pddl.Atom( condition.predicate, [obj_map.get(arg, arg) for arg in condition.args]) elif isinstance(condition, pddl.NegatedAtom): return pddl.NegatedAtom( condition.predicate, [obj_map.get(arg, arg) for arg in condition.args]) else: assert False, "What is a Literal but not an atom??" else: new_parts = [ lit_replacement(part, obj_map) for part in condition.parts ] return condition.change_parts(new_parts) return True
def parse_state(new_state, all_literals): state = [] state_true = set() state_false = set() state_assignments = dict() for fact in new_state: if fact[0] == "=": try: assignment = parse_assignment(fact) except ValueError as e: raise SystemExit("Error in initial state specification\n" + "Reason: %s." % e) if not isinstance(assignment.expression, pddl.NumericConstant): raise SystemExit("Illegal assignment in initial state " + "specification:\n%s" % assignment) if assignment.fluent in state_assignments: prev = state_assignments[assignment.fluent] if assignment.expression == prev.expression: print("Warning: %s is specified twice" % assignment, "in initial state specification") else: raise SystemExit("Error in initial state specification\n" + "Reason: conflicting assignment for " + "%s." % assignment.fluent) else: state_assignments[assignment.fluent] = assignment state.append(assignment) elif fact[0] == "not": atom = pddl.Atom(fact[1][0], fact[1][1:]) check_atom_consistency(atom, state_false, state_true, False) state_false.add(atom) else: atom = pddl.Atom(fact[0], fact[1:]) check_atom_consistency(atom, state_true, state_false) state_true.add(atom) state.extend(state_true) for atom in all_literals.difference(state_true): state.append(pddl.NegatedAtom(atom.predicate, atom.args)) return sorted(state)