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 recurse(condition): disjunctive_parts = [] other_parts = [] for part in condition.parts: part = recurse(part) if isinstance(part, pddl.Disjunction): disjunctive_parts.append(part) else: other_parts.append(part) if not disjunctive_parts: return condition # Rule (1): Associativity of disjunction. if isinstance(condition, pddl.Disjunction): result_parts = other_parts for part in disjunctive_parts: result_parts.extend(part.parts) return pddl.Disjunction(result_parts) # Rule (2): Distributivity disjunction/existential quantification. if isinstance(condition, pddl.ExistentialCondition): parameters = condition.parameters result_parts = [ pddl.ExistentialCondition(parameters, (part, )) for part in disjunctive_parts[0].parts ] return pddl.Disjunction(result_parts) # Rule (3): Distributivity disjunction/conjunction. assert isinstance(condition, pddl.Conjunction) result_parts = [pddl.Conjunction(other_parts)] while disjunctive_parts: previous_result_parts = result_parts result_parts = [] parts_to_distribute = disjunctive_parts.pop().parts for part1 in previous_result_parts: for part2 in parts_to_distribute: result_parts.append(pddl.Conjunction((part1, part2))) return pddl.Disjunction(result_parts)
def parse_condition_aux(alist, negated, type_dict, predicate_dict): """Parse a PDDL condition. The condition is translated into NNF on the fly.""" # if DEBUG: print ("parsing condition aux %s" % [alist]) tag = alist[0] if is_function_comparison( alist ): # NFD conditions are always comparisons between 2 numeric expressions args = [parse_expression(arg) for arg in alist[1:]] assert len(args) == 2, args if negated: return pddl.NegatedFunctionComparison(tag, args, True) else: return pddl.FunctionComparison(tag, args, True) elif tag in ("and", "or", "not", "imply"): args = alist[1:] if tag == "imply": assert len(args) == 2 if tag == "not": assert len(args) == 1 return parse_condition_aux(args[0], not negated, type_dict, predicate_dict) elif tag in ("forall", "exists"): parameters = parse_typed_list(alist[1]) args = alist[2:] assert len(args) == 1 else: # if is_object_comparison(alist): # print("DEBUG: Object comparison!") # print(alist) return parse_literal(alist, type_dict, predicate_dict, negated=negated) if tag == "imply": parts = [ parse_condition_aux(args[0], not negated, type_dict, predicate_dict), parse_condition_aux(args[1], negated, type_dict, predicate_dict) ] tag = "or" else: parts = [ parse_condition_aux(part, negated, type_dict, predicate_dict) for part in args ] if tag == "and" and not negated or tag == "or" and negated: return pddl.Conjunction(parts) elif tag == "or" and not negated or tag == "and" and negated: return pddl.Disjunction(parts) elif tag == "forall" and not negated or tag == "exists" and negated: return pddl.UniversalCondition(parameters, parts) elif tag == "exists" and not negated or tag == "forall" and negated: return pddl.ExistentialCondition(parameters, parts)
def parse_condition_aux(alist, negated, type_dict, predicate_dict): """Parse a PDDL condition. The condition is translated into NNF on the fly.""" tag = alist[0] if tag in ("and", "or", "not", "imply"): args = list() for arg in alist[1:]: if arg[0] == "=": continue if arg[0] == "not" and arg[1][0] == "=": continue args.append(arg) if tag == "imply": assert len(args) == 2 if tag == "not": assert len(args) == 1 return parse_condition_aux(args[0], not negated, type_dict, predicate_dict) elif tag in ("forall", "exists"): parameters = parse_typed_list(alist[1]) args = alist[2:] assert len(args) == 1 else: return parse_literal(alist, type_dict, predicate_dict, negated=negated) if tag == "imply": parts = [ parse_condition_aux(args[0], not negated, type_dict, predicate_dict), parse_condition_aux(args[1], negated, type_dict, predicate_dict) ] tag = "or" else: parts = [ parse_condition_aux(part, negated, type_dict, predicate_dict) for part in args ] if tag == "and" and not negated or tag == "or" and negated: return pddl.Conjunction(parts) elif tag == "or" and not negated or tag == "and" and negated: return pddl.Disjunction(parts) elif tag == "forall" and not negated or tag == "exists" and negated: return pddl.UniversalCondition(parameters, parts) elif tag == "exists" and not negated or tag == "forall" and negated: return pddl.ExistentialCondition(parameters, parts)
def add_plan_constraints(constraints, domain, evaluations, goal_exp, internal=False): if (constraints is None) or (constraints.skeletons is None): return goal_exp import pddl # TODO: unify this with the constraint ordering # TODO: can constrain to use a plan prefix prefix = get_internal_prefix(internal) assigned_predicate = ASSIGNED_PREDICATE.format(prefix) bound_predicate = BOUND_PREDICATE.format(prefix) group_predicate = GROUP_PREDICATE.format(prefix) order_predicate = ORDER_PREDICATE.format(prefix) new_facts = [] for group in constraints.groups: for value in constraints.groups[group]: # TODO: could make all constants groups (like an equality group) fact = (group_predicate, to_obj(group), to_obj(value)) new_facts.append(fact) new_actions = [] new_goals = [] for num, skeleton in enumerate(constraints.skeletons): actions, orders = skeleton incoming_orders, _ = neighbors_from_orders(orders) order_facts = [(order_predicate, to_obj('n{}'.format(num)), to_obj('t{}'.format(step))) for step in range(len(actions))] for step, (name, args) in enumerate(actions): # TODO: could also just remove the free parameter from the action new_action = deepcopy( find_unique(lambda a: a.name == name, domain.actions)) local_from_global = { a: p.name for a, p in safe_zip(args, new_action.parameters) if is_parameter(a) } ancestors, descendants = get_ancestors(step, orders), get_descendants( step, orders) parallel = set(range( len(actions))) - ancestors - descendants - {step} parameters = set(filter(is_parameter, args)) ancestor_parameters = parameters & set( filter(is_parameter, (p for idx in ancestors for p in actions[idx][1]))) #descendant_parameters = parameters & set(filter(is_parameter, (p for idx in descendants for p in actions[idx][1]))) parallel_parameters = parameters & set( filter(is_parameter, (p for idx in parallel for p in actions[idx][1]))) #bound_preconditions = [Imply(bound, assigned) for bound, assigned in safe_zip(bound_facts, assigned_facts)] bound_condition = pddl.Conjunction([ pddl.Disjunction( map(fd_from_fact, [ Not((bound_predicate, to_constant(p))), (assigned_predicate, to_constant(p), local_from_global[p]) ])) for p in parallel_parameters ]) existing_preconditions = [(assigned_predicate, to_constant(p), local_from_global[p]) for p in ancestor_parameters] constant_pairs = [(a, p.name) for a, p in safe_zip(args, new_action.parameters) if is_constant(a)] group_preconditions = [ (group_predicate if is_hashable(a) and (a in constraints.groups) else EQ, to_obj(a), p) for a, p in constant_pairs ] order_preconditions = [ order_facts[idx] for idx in incoming_orders[step] ] new_preconditions = existing_preconditions + group_preconditions + order_preconditions + [ Not(order_facts[step]) ] new_action.precondition = pddl.Conjunction([ new_action.precondition, bound_condition, make_preconditions(new_preconditions) ]).simplified() new_parameters = parameters - ancestors bound_facts = [(bound_predicate, to_constant(p)) for p in new_parameters] assigned_facts = [(assigned_predicate, to_constant(p), local_from_global[p]) for p in new_parameters] new_effects = bound_facts + assigned_facts + [order_facts[step]] new_action.effects.extend(make_effects(new_effects)) # TODO: should also negate the effects of all other sequences here new_actions.append(new_action) #new_action.dump() new_goals.append( And(*[order_facts[idx] for idx in incoming_orders[GOAL_INDEX]])) add_predicate(domain, make_predicate(order_predicate, ['?num', '?step'])) if constraints.exact: domain.actions[:] = [] domain.actions.extend(new_actions) new_goal_exp = And(goal_exp, Or(*new_goals)) for fact in new_facts: add_fact(evaluations, fact, result=INTERNAL_EVALUATION) return new_goal_exp