def replace(condition): if isinstance(condition, pddl.FunctionComparison): non_negated = condition if condition.negated: non_negated = condition.negate() # remove possible duplicates fluent_str = 'num_condition_satisfied{0}'.format(task.comparator_count) new_predicate_args = dict() functions = condition.get_functions() for func in functions: arg_types = extract_arg_types(func) for (key, value) in zip(func.args, arg_types): new_predicate_args[key] = pddl.TypedObject(key, value) args = [] for key in sorted(new_predicate_args.keys()): args.append(new_predicate_args[key]) predicate = pddl.Predicate(fluent_str, args) task.predicates.append(predicate) if condition.negated: new_atom = pddl.NegatedNumericWrapper(predicate.name, [x.name for x in args], non_negated) else: new_atom = pddl.NumericWrapper(predicate.name, [x.name for x in args], non_negated) task.comparator_count += 1 return new_atom if condition.has_numeric_precondition(): new_condition = condition.__class__([]) new_condition.parts = [replace(x) for x in condition.parts] return new_condition return condition
def add_stream_actions(domain, stream_results, **kwargs): import pddl stream_actions, stream_result_from_name = get_stream_actions( stream_results, **kwargs) output_objects = [] for stream_result in stream_result_from_name.values(): if isinstance(stream_result, StreamResult): output_objects.extend( map(pddl_from_object, stream_result.output_objects)) new_constants = list( {pddl.TypedObject(obj, OBJECT) for obj in output_objects} | set(domain.constants)) # to_untyped_strips # free_variables new_domain = Domain(domain.name, domain.requirements, domain.types, domain.type_dict, new_constants, domain.predicates, domain.predicate_dict, domain.functions, domain.actions[:] + stream_actions, domain.axioms) """ optimizer_results = list(filter(is_optimizer_result, stream_results)) optimizer_facts = {substitute_expression(result.external.stream_fact, result.get_mapping()) for result in optimizer_results} optimizers = {result.external.optimizer for result in optimizer_results} print(optimizers) for optimizer in optimizers: for stream in optimizer.streams: print(stream.instance.get_constraints()) print(stream.instance) #print(optimizer_results) #print(optimizer_facts) """ return new_domain, stream_result_from_name
def compile_to_exogenous_axioms(evaluations, domain, streams): # TODO: no attribute certified import pddl fluent_predicates = get_fluents(domain) certified_predicates = { get_prefix(a) for s in streams for a in s.certified } future_map = {p: 'f-{}'.format(p) for p in certified_predicates} augment_evaluations(evaluations, future_map) rename_future = lambda a: rename_atom(a, future_map) derived_map = {p: 'd-{}'.format(p) for p in certified_predicates} rename_derived = lambda a: rename_atom(a, derived_map) for action in domain.actions: action.precondition = replace_predicates(derived_map, action.precondition) for effect in action.effects: assert (isinstance(effect, pddl.Effect)) effect.condition = replace_predicates(derived_map, effect.condition) for axiom in domain.axioms: axiom.condition = replace_predicates(derived_map, axiom.condition) #fluent_predicates.update(certified_predicates) for stream in list(streams): if not isinstance(stream, Stream): raise NotImplementedError(stream) streams.append( create_static_stream(stream, evaluations, fluent_predicates, rename_future)) stream_atom = streams[-1].certified[0] domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate( get_prefix(stream_atom), get_args(stream_atom)) preconditions = [stream_atom] + list(map(rename_derived, stream.domain)) for fact in stream.certified: derived_fact = fd_from_fact(rename_derived(fact)) external_params = derived_fact.args internal_params = tuple(p for p in (stream.inputs + stream.outputs) if p not in derived_fact.args) parameters = tuple( pddl.TypedObject(p, OBJECT) for p in (external_params + internal_params)) #precondition = pddl.Conjunction(tuple(map(fd_from_fact, [stream_atom] + # list(map(rename_derived, stream.domain))))) #precondition = pddl.Disjunction([fd_from_fact(fact), precondition]) # TODO: quantifier domain.axioms.extend([ pddl.Axiom(name=derived_fact.predicate, parameters=parameters, num_external_parameters=len(external_params), condition=make_preconditions(preconditions)), pddl.Axiom(name=derived_fact.predicate, parameters=parameters[:len(external_params)], num_external_parameters=len(external_params), condition=fd_from_fact(fact)), ]) stream.certified = tuple( set(stream.certified) | set(map(rename_future, stream.certified)))
def get_problem(init_evaluations, goal_expression, domain, unit_costs=False): objects = objects_from_evaluations(init_evaluations) typed_objects = list({pddl.TypedObject(pddl_from_object(obj), OBJECT) for obj in objects} - set(domain.constants)) # TODO: this doesn't include = init = [fd_from_evaluation(e) for e in init_evaluations if not is_negated_atom(e)] goal = parse_goal(goal_expression, domain) return Problem(task_name=domain.name, task_domain_name=domain.name, objects=sorted(typed_objects, key=lambda o: o.name), task_requirements=pddl.tasks.Requirements([]), init=init, goal=goal, use_metric=not unit_costs)
def parse_domain_custom(checker): # parse domain file checker.parse_code(checker.files['domain'], checker.parse_token_domain) yield checker.names['domain'] if checker.requirements: yield pddl.Requirements(checker.requirements) else: yield pddl.Requirements([":strips"]) types = [pddl.Type("object")] set_supertypes(types) type_dict = dict((type_.name, type_) for type_ in types) yield types yield type_dict yield [] predicates = [[pred] + checker.predicates[pred]['params'] for pred in checker.predicates] predicates = [parse_predicate(entry) for entry in predicates] predicates += [ pddl.Predicate("=", [ pddl.TypedObject("?x", "object"), pddl.TypedObject("?y", "object") ]) ] predicate_dict = dict((pred.name, pred) for pred in predicates) yield predicates yield predicate_dict yield [] actions = [] entries = [[ ':action', action, ':parameters', checker.actions[action]['params'], ':precondition', checker.actions[action]['logic_precs'], ':effect', checker.actions[action]['logic_effs'] ] for action in checker.actions] for entry in entries: action = parse_action(entry, type_dict, predicate_dict) if action is not None: actions.append(action) yield actions yield []
def get_problem(evaluations, goal_exp, domain, unit_costs=False): objects = objects_from_evaluations(evaluations) typed_objects = list({pddl.TypedObject(pddl_from_object(obj), OBJECT) for obj in objects} - set(domain.constants)) # TODO: this doesn't include = init = [fd_from_evaluation(e) for e in evaluations if not is_negated_atom(e)] goal = pddl.Truth() if goal_exp is None else parse_goal(goal_exp, domain) problem_pddl = None if USE_FORBID: problem_pddl = get_problem_pddl(evaluations, goal_exp, domain.pddl, temporal=False) write_pddl(domain.pddl, problem_pddl) return Problem(task_name=domain.name, task_domain_name=domain.name, objects=sorted(typed_objects, key=lambda o: o.name), task_requirements=pddl.tasks.Requirements([]), init=init, goal=goal, use_metric=not unit_costs, pddl=problem_pddl)
def get_problem(init_evaluations, goal_expression, domain, unit_costs): objects = map(pddl_from_object, objects_from_evaluations(init_evaluations)) typed_objects = list({pddl.TypedObject(obj, OBJECT) for obj in objects} - set(domain.constants)) init = get_init(init_evaluations) goal = parse_condition(pddl_list_from_expression(goal_expression), domain.type_dict, domain.predicate_dict) return Problem(task_name=domain.name, task_domain_name=domain.name, objects=typed_objects, task_requirements=pddl.tasks.Requirements([]), init=init, goal=goal, use_metric=not unit_costs)
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 add_stream_actions(domain, stream_results): import pddl stream_actions, stream_result_from_name = get_stream_actions(stream_results) output_objects = [] for stream_result in stream_result_from_name.values(): if isinstance(stream_result, StreamResult): output_objects += list(map(pddl_from_object, stream_result.output_objects)) new_constants = list({pddl.TypedObject(obj, OBJECT) for obj in output_objects} | set(domain.constants)) # to_untyped_strips # free_variables new_domain = Domain(domain.name, domain.requirements, domain.types, domain.type_dict, new_constants, domain.predicates, domain.predicate_dict, domain.functions, domain.actions[:] + stream_actions, domain.axioms) return new_domain, stream_result_from_name
def get_atom_parameter(self, alist, predicate_dict, parameters_dict, parent): """ Initiate Atoms of a cost-term """ par = None pre_arg = 0 args = [] alist_save = list(alist) try: pre = predicate_dict[alist[0]] except: if (alist[0] not in parent.unbound_check): raise ValueError(alist[0], " is not a predicate or parameter") alist = alist[1:] for index in range(0, len(alist)): par = parameters_dict.get(alist[index]) for un_par in parent.unbound_check: parl = un_par.split(" - ") assert (len(parl) <= 2) par_str1 = parl[0] par_str2 = "object" if len(parl) > 1: par_str2 = parl[1] if alist[index] == par_str1: par = pddl.TypedObject(par_str1, par_str2) break if not par: par = alist[index] if not isinstance( par, str) and par.type_name != pre.arguments[index].type_name: raise ValueError("Predicate", pre.name, "must have argument of type", pre.arguments[index].type_name, "at index", index, ". Got", par.type_name) pre_arg += 1 if isinstance(par, str): args.append(par) else: args.append(par.name) if pre_arg != pre.get_arity(): raise ValueError( "Number of arguments of predicate", pre.name, "does not match the number of arguments in costfunction") return pddl.Atom(pre.name, args)
def compile_to_exogenous_actions(evaluations, domain, streams): import pddl # TODO: automatically derive fluents # TODO: version of this that operates on fluents of length one? # TODO: better instantiation when have full parameters # TODO: conversion from stream cost to real cost units? # TODO: any predicates derived would need to be replaced as well fluent_predicates = get_fluents(domain) certified_predicates = { get_prefix(a) for s in streams for a in s.certified } future_map = {p: 'f-{}'.format(p) for p in certified_predicates} augment_evaluations(evaluations, future_map) rename_future = lambda a: rename_atom(a, future_map) for stream in list(streams): if not isinstance(stream, Stream): raise NotImplementedError(stream) # TODO: could also just have conditions asserting that one of the fluent conditions fails streams.append( create_static_stream(stream, evaluations, fluent_predicates, rename_future)) stream_atom = streams[-1].certified[0] parameters = [ pddl.TypedObject(p, OBJECT) for p in get_args(stream_atom) ] # TODO: add to predicates as well? domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate( get_prefix(stream_atom), parameters) preconditions = [stream_atom] + list(stream.domain) effort = 1 # TODO: use stream info #effort = 1 if unit_cost else result.instance.get_effort() #if effort == INF: # continue domain.actions.append( pddl.Action(name='call-{}'.format(stream.name), parameters=parameters, num_external_parameters=len(parameters), precondition=make_preconditions(preconditions), effects=make_effects(stream.certified), cost=make_cost(effort))) stream.certified = tuple( set(stream.certified) | set(map(rename_future, stream.certified)))
def compile_to_exogenous_actions(evaluations, domain, streams): import pddl # TODO: automatically derive fluents # TODO: version of this that operates on fluents of length one? # TODO: better instantiation when have full parameters # TODO: conversion from stream cost to real cost units? # TODO: any predicates derived would need to be replaced as well fluent_predicates = get_fluents(domain) domain_predicates = {get_prefix(a) for s in streams for a in s.domain} if not (domain_predicates & fluent_predicates): return certified_predicates = {get_prefix(a) for s in streams for a in s.certified} future_map = {p: 'f-{}'.format(p) for p in certified_predicates} augment_evaluations(evaluations, future_map) rename_future = lambda a: rename_atom(a, future_map) for stream in list(streams): if not isinstance(stream, Stream): raise NotImplementedError(stream) # TODO: could also just have conditions asserting that one of the fluent conditions fails streams.append(create_static_stream(stream, evaluations, fluent_predicates, rename_future)) stream_atom = streams[-1].certified[0] parameters = [pddl.TypedObject(p, 'object') for p in get_args(stream_atom)] # TODO: add to predicates as well? domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate(get_prefix(stream_atom), parameters) precondition = pddl.Conjunction(tuple(map(fd_from_fact, (stream_atom,) + tuple(stream.domain)))) effects = [pddl.Effect(parameters=[], condition=pddl.Truth(), literal=fd_from_fact(fact)) for fact in stream.certified] effort = 1 # TODO: use stream info #effort = 1 if unit_cost else result.instance.get_effort() #if effort == INF: # continue fluent = pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]) expression = pddl.NumericConstant(int_ceil(effort)) # Integer cost = pddl.Increase(fluent=fluent, expression=expression) # Can also be None domain.actions.append(pddl.Action(name='call-{}'.format(stream.name), parameters=parameters, num_external_parameters=len(parameters), precondition=precondition, effects=effects, cost=cost)) stream.certified = tuple(set(stream.certified) | set(map(rename_future, stream.certified)))
def parse_domain_pddl(domain_pddl): iterator = iter(domain_pddl) define_tag = next(iterator) assert define_tag == "define" domain_line = next(iterator) assert domain_line[0] == "domain" and len(domain_line) == 2 yield domain_line[1] ## We allow an arbitrary order of the requirement, types, constants, ## predicates and functions specification. The PDDL BNF is more strict on ## this, so we print a warning if it is violated. requirements = pddl.Requirements([":strips"]) the_types = [pddl.Type("object")] constants, the_predicates, the_functions = [], [], [] correct_order = [ ":requirements", ":types", ":constants", ":predicates", ":functions" ] seen_fields = [] for opt in iterator: field = opt[0] if field not in correct_order: first_action = opt break if field in seen_fields: raise SystemExit("Error in domain specification\n" + "Reason: two '%s' specifications." % field) if (seen_fields and correct_order.index(seen_fields[-1]) > correct_order.index(field)): msg = "\nWarning: %s specification not allowed here (cf. PDDL BNF)" % field print(msg, file=sys.stderr) seen_fields.append(field) if field == ":requirements": requirements = pddl.Requirements(opt[1:]) elif field == ":types": the_types.extend(parse_typed_list(opt[1:], constructor=pddl.Type)) elif field == ":constants": constants = parse_typed_list(opt[1:]) elif field == ":predicates": the_predicates = [parse_predicate(entry) for entry in opt[1:]] the_predicates += [ pddl.Predicate("=", [ pddl.TypedObject("?x", "object"), pddl.TypedObject("?y", "object") ]) ] elif field == ":functions": the_functions = parse_typed_list(opt[1:], constructor=parse_function, default_type="number") set_supertypes(the_types) yield requirements yield the_types type_dict = dict((type.name, type) for type in the_types) yield type_dict yield constants yield the_predicates predicate_dict = dict((pred.name, pred) for pred in the_predicates) yield predicate_dict yield the_functions entries = [first_action] + [entry for entry in iterator] the_axioms = [] the_actions = [] for entry in entries: if entry[0] == ":derived": axiom = parse_axiom(entry, type_dict, predicate_dict) the_axioms.append(axiom) else: action = parse_action(entry, type_dict, predicate_dict) if action is not None: the_actions.append(action) yield the_actions yield the_axioms
def translate_typed_object(prog, obj, type_dict): supertypes = type_dict[obj.type_name].supertype_names for type_name in [obj.type_name] + supertypes: prog.add_fact(pddl.TypedObject(obj.name, type_name).get_atom())
def make_object(obj, type=OBJECT): return pddl.TypedObject(obj, type)
def convert_parameters(parameters): import pddl return [pddl.TypedObject(param.name, param.type) for param in parameters]
def make_parameters(parameters): return tuple(pddl.TypedObject(p, OBJECT) for p in parameters)
def parse_domain_pddl(domain_pddl): def typesplit( alist): # recurse nested lists and replace "-type" by "-", "type" # an error which occurs in some sloppyly modeled domains ix = 0 while ix < len(alist): el = alist[ix] # print("checking element %s"%el) if isinstance(el, list): typesplit(alist[ix]) elif len(el) > 1 and el[0] == "-": msg = ( "\nWARNING: %s seems to be a 'type' definition missing a space.\n" "Splitting Element into '-' and '%s'") % (el, el[1:]) print(msg, file=sys.stderr) alist[ix:ix + 1] = el[0], el[1:] ix += 1 iterator = iter(domain_pddl) define_tag = next(iterator) assert define_tag == "define" domain_line = next(iterator) assert domain_line[0] == "domain" and len(domain_line) == 2 yield domain_line[1] ## We allow an arbitrary order of the requirement, types, constants, ## predicates and functions specification. The PDDL BNF is more strict on ## this, so we print a warning if it is violated. requirements = pddl.Requirements([":strips"]) the_types = [pddl.Type("object")] constants, the_functions = [], [] the_predicates = [ pddl.Predicate("=", [ pddl.TypedObject("?x", "object"), pddl.TypedObject("?y", "object") ]) ] # the_free_functions = [] ## support for global constraints with free functions is not implemented yet correct_order = [ ":requirements", ":types", ":constants", ":predicates", ":functions" ] #, ":free_functions"] seen_fields = [] first_action = None for opt in iterator: # print("Options before: ",opt) typesplit( opt) # fix for missing space between dash '-' and type identifier # print("Options after: ",opt) field = opt[0] if field not in correct_order: first_action = opt break if field in seen_fields: raise SystemExit("Error in domain specification\n" + "Reason: two '%s' specifications." % field) if (seen_fields and correct_order.index(seen_fields[-1]) > correct_order.index(field)): msg = "\nWARNING: %s specification not allowed here (cf. PDDL BNF)" % field print(msg, file=sys.stderr) seen_fields.append(field) if field == ":requirements": requirements = pddl.Requirements(opt[1:]) elif field == ":types": the_types.extend(parse_typed_list(opt[1:], constructor=pddl.Type)) elif field == ":constants": constants = parse_typed_list(opt[1:]) elif field == ":predicates": the_predicates += [parse_predicate(entry) for entry in opt[1:]] elif field == ":functions": the_functions = parse_typed_list(opt[1:], constructor=parse_function, default_type="number") # elif field == ":free_functions": # the_free_functions = parse_typed_list( # opt[1:], # constructor=parse_function, # default_type="number") set_supertypes(the_types) yield requirements yield the_types type_dict = dict((pddltype.name, pddltype) for pddltype in the_types) yield type_dict yield constants yield the_predicates predicate_dict = dict((pred.name, pred) for pred in the_predicates) yield predicate_dict total_cost_fluent = pddl.Function("total-cost", [], "number") the_functions.append(total_cost_fluent) # the_functions.append(the_free_functions) yield the_functions entries = [] if first_action is not None: entries.append(first_action) entries.extend(iterator) the_axioms = [] the_actions = [] for entry in entries: # if DEBUG: print("Entries before: ",entry) typesplit( entry ) # fix for missing space between dash '-' and type identifier # if DEBUG: print("Entries after: ",entry) if entry[0] == ":derived": axiom = parse_axiom(entry, type_dict, predicate_dict) the_axioms.append(axiom) elif entry[0] == ":action": action = parse_action(entry, type_dict, predicate_dict) if action is not None: the_actions.append(action) elif entry[ 0] == ":constraint": ## support for global constraints is new in NFD global_constraint = parse_global_constraint( entry, type_dict, predicate_dict) the_axioms.append(global_constraint) else: print("%s could not be parsed" % entry[0]) if entry[0] != ":free_functions": assert False yield the_actions yield the_axioms