def translate_strips_conditions_aux(conditions, dictionary, ranges, numeric_dictionary, comparison_axioms, mutex_check=False): condition = {} comp_axiom_dict = comparison_axioms[0] sas_comp_axioms = comparison_axioms[1] for fact in conditions: if (isinstance(fact, pddl.FunctionComparison) or isinstance(fact, pddl.NegatedFunctionComparison)): # print("comparison condition in translate strips condition aux:") if fact not in dictionary: # print("Fact is not in dictionary") for part in fact.parts: # TODO: remove this assertion check when not debugging assert part in numeric_dictionary parts = [numeric_dictionary[part] for part in fact.parts] key = (fact.comparator, tuple(parts)) negated = fact.negated if key in comp_axiom_dict: # print("key %s ist im comp_axiom_dict" % [key]) # print(comp_axiom_dict) fact = comp_axiom_dict[key] if negated: # print("(nach dem negieren)") fact = fact.negate() else: axiom = sas_tasks.SASCompareAxiom(fact.comparator, parts, len(ranges)) if negated: negfact = fact posfact = fact.negate() else: posfact = fact negfact = fact.negate() if not mutex_check: # if mutexes are checked the axioms will not be added because the # strips to sas dictionary would not be updated properly otherwise sas_comp_axioms.append(axiom) comp_axiom_dict[key] = posfact dictionary.setdefault(posfact, []).append((len(ranges), 0)) dictionary.setdefault(negfact, []).append((len(ranges), 1)) ranges.append(3) # print (dictionary[fact]) var, val = dictionary[fact][0] if (var in condition and val not in condition[var]): # Conflicting conditions on this variable: Operator invalid. return None condition[var] = set([val]) else: if fact.negated: # we handle negative conditions later, because then we # can recognize when the negative condition is already # ensured by a positive condition continue for var, val in dictionary.get(fact, ()): # The default () here is a bit of a hack. For goals (but # only for goals!), we can get static facts here. They # cannot be statically false (that would have been # detected earlier), and hence they are statically true # and don't need to be translated. # TODO: This would not be necessary if we dealt with goals # in the same way we deal with operator preconditions etc., # where static facts disappear during grounding. So change # this when the goal code is refactored (also below). (**) if (condition.get(var) is not None and val not in condition.get(var)): # Conflicting conditions on this variable: Operator invalid. return None condition[var] = set([val]) def number_of_values(var_vals_pair): var, vals = var_vals_pair return len(vals) for fact in conditions: if (isinstance(fact, pddl.FunctionComparison) or isinstance(fact, pddl.NegatedFunctionComparison)): continue if fact.negated: ## Note Here we use a different solution than in Sec. 10.6.4 ## of the thesis. Compare the last sentences of the third ## paragraph of the section. ## We could do what is written there. As a test case, ## consider Airport ADL tasks with only one airport, where ## (occupied ?x) variables are encoded in a single variable, ## and conditions like (not (occupied ?x)) do occur in ## preconditions. ## However, here we avoid introducing new derived predicates ## by treat the negative precondition as a disjunctive ## precondition and expanding it by "multiplying out" the ## possibilities. This can lead to an exponential blow-up so ## it would be nice to choose the behaviour as an option. done = False new_condition = {} atom = pddl.Atom(fact.predicate, fact.args) # force positive for var, val in dictionary.get(atom, ()): # see comment (**) above poss_vals = set(range(ranges[var])) poss_vals.remove(val) if condition.get(var) is None: assert new_condition.get(var) is None new_condition[var] = poss_vals else: # constrain existing condition on var prev_possible_vals = condition.get(var) done = True prev_possible_vals.intersection_update(poss_vals) if len(prev_possible_vals) == 0: # Conflicting conditions on this variable: # Operator invalid. return None if not done and len(new_condition) != 0: # we did not enforce the negative condition by constraining # an existing condition on one of the variables representing # this atom. So we need to introduce a new condition: # We can select any from new_condition and currently prefer the # smallest one. candidates = sorted(new_condition.items(), key=number_of_values) var, vals = candidates[0] condition[var] = vals def multiply_out(condition): # destroys the input sorted_conds = sorted(condition.items(), key=number_of_values) flat_conds = [{}] for var, vals in sorted_conds: if len(vals) == 1: for cond in flat_conds: cond[var] = vals.pop() # destroys the input here else: new_conds = [] for cond in flat_conds: for val in vals: new_cond = deepcopy(cond) new_cond[var] = val new_conds.append(new_cond) flat_conds = new_conds return flat_conds return multiply_out(condition)
def translate_strips_conditions_aux(conditions, dictionary, ranges): condition = {} for fact in conditions: if fact.negated: # we handle negative conditions later, because then we # can recognize when the negative condition is already # ensured by a positive condition continue for var, val in dictionary.get(fact, ()): # The default () here is a bit of a hack. For goals (but # only for goals!), we can get static facts here. They # cannot be statically false (that would have been # detected earlier), and hence they are statically true # and don't need to be translated. # TODO: This would not be necessary if we dealt with goals # in the same way we deal with operator preconditions etc., # where static facts disappear during grounding. So change # this when the goal code is refactored (also below). (**) if (condition.get(var) is not None and val not in condition.get(var)): # Conflicting conditions on this variable: Operator invalid. return None condition[var] = set([val]) for fact in conditions: if fact.negated: ## Note Here we use a different solution than in Sec. 10.6.4 ## of the thesis. Compare the last sentences of the third ## paragraph of the section. ## We could do what is written there. As a test case, ## consider Airport ADL tasks with only one airport, where ## (occupied ?x) variables are encoded in a single variable, ## and conditions like (not (occupied ?x)) do occur in ## preconditions. ## However, here we avoid introducing new derived predicates ## by treat the negative precondition as a disjunctive precondition ## and expanding it by "multiplying out" the possibilities. ## This can lead to an exponential blow-up so it would be nice ## to choose the behaviour as an option. done = False new_condition = {} atom = pddl.Atom(fact.predicate, fact.args) # force positive for var, val in dictionary.get(atom, ()): # see comment (**) above poss_vals = set(range(ranges[var])) poss_vals.remove(val) if condition.get(var) is None: assert new_condition.get(var) is None new_condition[var] = poss_vals else: # constrain existing condition on var prev_possible_vals = condition.get(var) done = True prev_possible_vals.intersection_update(poss_vals) if len(prev_possible_vals) == 0: # Conflicting conditions on this variable: # Operator invalid. return None if not done and len(new_condition) != 0: # we did not enforce the negative condition by constraining # an existing condition on one of the variables representing # this atom. So we need to introduce a new condition: # We can select any from new_condition and currently prefer the # smalles one. candidates = sorted(new_condition.items(), lambda x,y: cmp(len(x[1]),len(y[1]))) var, vals = candidates[0] condition[var] = vals def multiply_out(condition): # destroys the input sorted_conds = sorted(condition.items(), lambda x,y: cmp(len(x[1]),len(y[1]))) flat_conds = [{}] for var, vals in sorted_conds: if len(vals) == 1: for cond in flat_conds: cond[var] = vals.pop() # destroys the input here else: new_conds = [] for cond in flat_conds: for val in vals: new_cond = deepcopy(cond) new_cond[var] = val new_conds.append(new_cond) flat_conds = new_conds return flat_conds return multiply_out(condition)
def get_axiom_predicate(axiom): name = axiom variables = [par.name for par in axiom.parameters] if isinstance(axiom.condition, pddl.ExistentialCondition): variables += [par.name for par in axiom.condition.parameters] return pddl.Atom(name, variables)
def add_rule(self, type, conditions, effect_vars): effect = pddl.Atom(self.name_generator.next(), effect_vars) rule = pddl_to_prolog.Rule(conditions, effect) rule.type = type self.result.append(rule) return rule.effect
def push(self, predicate, args): self.num_pushes += 1 eff_tuple = (predicate, ) + tuple(args) if eff_tuple not in self.enqueued: self.enqueued.add(eff_tuple) self.queue.append(pddl.Atom(predicate, list(args)))
def build_rules(self, rules): rule_head_name = "@goal-reachable" rule_head = pddl.Atom("@goal-reachable", []) rule_body = list(condition_to_rule_body([], self.condition)) rules.append((rule_body, rule_head))
def project_rule(rule, conditions, name_generator): predicate = next(name_generator) effect_variables = set(rule.effect.args) & get_variables(conditions) effect = pddl.Atom(predicate, sorted(effect_variables)) projected_rule = Rule(conditions, effect) return projected_rule
def instantiate(self, parameters): args = ["?X"] * (len(self.order) + (self.omitted_pos != -1)) for arg, argpos in zip(parameters, self.order): args[argpos] = arg return pddl.Atom(self.predicate, args)
def test_normalization(): prog = PrologProgram() prog.add_fact(pddl.Atom("at", ["foo", "bar"])) prog.add_fact(pddl.Atom("truck", ["bollerwagen"])) prog.add_fact(pddl.Atom("truck", ["segway"])) prog.add_rule( Rule([pddl.Atom("truck", ["?X"])], pddl.Atom("at", ["?X", "?Y"]))) prog.add_rule( Rule([pddl.Atom("truck", ["X"]), pddl.Atom("location", ["?Y"])], pddl.Atom("at", ["?X", "?Y"]))) prog.add_rule( Rule([pddl.Atom("truck", ["?X"]), pddl.Atom("location", ["?Y"])], pddl.Atom("at", ["?X", "?X"]))) prog.add_rule( Rule([pddl.Atom("p", ["?Y", "?Z", "?Y", "?Z"])], pddl.Atom("q", ["?Y", "?Y"]))) prog.add_rule(Rule([], pddl.Atom("foo", []))) prog.add_rule(Rule([], pddl.Atom("bar", ["X"]))) prog.normalize() prog.dump()
def translate_typed_object(prog, obj, type_dict): supertypes = type_dict[obj.type].supertype_names for type_name in [obj.type] + supertypes: prog.add_fact(pddl.Atom(type_name, [obj.name]))
def parse_task_pddl(task_pddl, type_dict, predicate_dict): iterator = iter(task_pddl) define_tag = next(iterator) assert define_tag == "define" problem_line = next(iterator) assert problem_line[0] == "problem" and len(problem_line) == 2 yield problem_line[1] domain_line = next(iterator) assert domain_line[0] == ":domain" and len(domain_line) == 2 yield domain_line[1] requirements_opt = next(iterator) if requirements_opt[0] == ":requirements": requirements = requirements_opt[1:] objects_opt = next(iterator) else: requirements = [] objects_opt = requirements_opt yield pddl.Requirements(requirements) if objects_opt[0] == ":objects": yield parse_typed_list(objects_opt[1:]) init = next(iterator) else: yield [] init = objects_opt assert init[0] == ":init" initial = [] initial_true = set() initial_false = set() initial_assignments = dict() for fact in init[1:]: 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 initial_assignments: prev = initial_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: initial_assignments[assignment.fluent] = assignment initial.append(assignment) elif fact[0] == "not": atom = pddl.Atom(fact[1][0], fact[1][1:]) check_atom_consistency(atom, initial_false, initial_true, False) initial_false.add(atom) else: atom = pddl.Atom(fact[0], fact[1:]) check_atom_consistency(atom, initial_true, initial_false) initial_true.add(atom) initial.extend(initial_true) yield initial goal = next(iterator) assert goal[0] == ":goal" and len(goal) == 2 yield parse_condition(goal[1], type_dict, predicate_dict) use_metric = False for entry in iterator: if entry[0] == ":metric": if entry[1] == "minimize" and entry[2][0] == "total-cost": use_metric = True else: assert False, "Unknown metric." yield use_metric for entry in iterator: assert False, entry