def task_from_domain_problem(domain, problem): # TODO: prune evaluation that aren't needed in actions #domain_name, domain_requirements, types, type_dict, constants, \ # predicates, predicate_dict, functions, actions, axioms = domain task_name, task_domain_name, task_requirements, objects, init, goal, use_metric, problem_pddl = problem assert domain.name == task_domain_name requirements = pddl.Requirements( sorted( set(domain.requirements.requirements + task_requirements.requirements))) objects = domain.constants + objects check_for_duplicates( [o.name for o in objects], errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") init.extend(pddl.Atom(EQ, (obj.name, obj.name)) for obj in objects) # TODO: optimistically evaluate (not (= ?o1 ?o2)) for fd_obj in objects: obj = obj_from_pddl(fd_obj.name) if obj.is_unique(): init.append(pddl.Atom(IDENTICAL, (fd_obj.name, fd_obj.name))) else: assert obj.is_shared() task = pddl.Task(domain.name, task_name, requirements, domain.types, objects, domain.predicates, domain.functions, init, goal, domain.actions, domain.axioms, use_metric) normalize.normalize(task) # task.add_axiom return task
def make_domain(constants=[], predicates=[], functions=[], actions=[], axioms=[]): types = [pddl.Type(OBJECT)] pddl_parser.parsing_functions.set_supertypes(types) return Domain(name='', requirements=pddl.Requirements([]), types=types, type_dict={ty.name: ty for ty in types}, constants=constants, predicates=predicates, predicate_dict={p.name: p for p in predicates}, functions=functions, actions=actions, axioms=axioms, pddl=None)
def parse_task(domain_pddl, task_pddl): domain_name, domain_requirements, types, type_dict, constants, predicates, predicate_dict, functions, actions, \ axioms, overalls = parse_domain_pddl(domain_pddl) frees = dict() frees = process_is_free_propositions(overalls, actions, predicates, predicate_dict) #add_overall_to_start_and_end(overalls, actions, predicates, predicate_dict) can_be_compressed = analyze_compressible(actions) actions = merge_actions(actions, can_be_compressed) task_name, task_domain_name, task_requirements, objects, init, goal, use_metric = parse_task_pddl( task_pddl, type_dict, predicate_dict, frees) assert domain_name == task_domain_name requirements = pddl.Requirements( sorted( set(domain_requirements.requirements + task_requirements.requirements))) objects = constants + objects check_for_duplicates( [o.name for o in objects], errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") init += [pddl.Atom("=", (obj.name, obj.name)) for obj in objects] return pddl.Task(domain_name, task_name, requirements, types, objects, predicates, functions, init, goal, actions, axioms, use_metric)
def parse_task(domain_pddl, task_pddl): # if DEBUG: # print("domain_pddl %s" % domain_pddl) # print("task_pddl %s" % task_pddl) domain_name, domain_requirements, types, type_dict, constants, predicates, predicate_dict,\ functions, actions, axioms = parse_domain_pddl(domain_pddl) task_name, task_domain_name, task_requirements, objects, init, num_init, goal, metric \ = parse_task_pddl(task_pddl, type_dict, predicate_dict) # if DEBUG: # print("Init= %s"% init) if not domain_name == task_domain_name: msg = "\nWarning: Domain name in domain file %s differs from domain name in task file %s" % ( domain_name, task_domain_name) print(msg, file=sys.stderr) #assert domain_name == task_domain_name requirements = pddl.Requirements( sorted( set(domain_requirements.requirements + task_requirements.requirements))) objects = constants + objects check_for_duplicates( # This will remove duplicates now instead of outright aborting. objects, errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") init += [pddl.Atom("=", (obj.name, obj.name)) for obj in objects] # print("parsing_funtions parse_task returns num_init", num_init) # for ini in num_init: # ini.dump() # print("parsing_funtions parse_task returns metric", metric) return pddl.Task(domain_name, task_name, requirements, types, objects, predicates, functions, init, num_init, goal, actions, axioms, metric)
def task_from_domain_problem(domain, problem, add_identical=True): # TODO: prune evaluation that aren't needed in actions #domain_name, domain_requirements, types, type_dict, constants, \ # predicates, predicate_dict, functions, actions, axioms = domain task_name, task_domain_name, task_requirements, objects, init, goal, use_metric, problem_pddl = problem assert domain.name == task_domain_name requirements = pddl.Requirements( sorted( set(domain.requirements.requirements + task_requirements.requirements))) objects = domain.constants + objects check_for_duplicates( [o.name for o in objects], errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") init.extend(pddl.Atom(EQ, (obj.name, obj.name)) for obj in objects) if add_identical: init.extend(get_identical_atoms(objects)) #print('{} objects and {} atoms'.format(len(objects), len(init))) task = pddl.Task(domain.name, task_name, requirements, domain.types, objects, domain.predicates, domain.functions, init, goal, domain.actions, domain.axioms, use_metric) normalize.normalize(task) # task.add_axiom return task
def parse_temporal_domain(domain_pddl): translate_path = os.path.join(get_tfd_path(), 'translate/') # tfd & temporal-FD prefixes = ['pddl', 'normalize'] deleted = delete_imports(prefixes) sys.path.insert(0, translate_path) import pddl import normalize temporal_domain = TemporalDomain(*pddl.tasks.parse_domain(pddl.parser.parse_nested_list(domain_pddl.splitlines()))) name, requirements, constants, predicates, types, functions, actions, durative_actions, axioms = temporal_domain fluents = normalize.get_fluent_predicates(temporal_domain) sys.path.remove(translate_path) delete_imports(prefixes) sys.modules.update(deleted) # This is important otherwise classes are messed up import pddl import pddl_parser assert not actions simple_from_durative = simple_from_durative_action(durative_actions, fluents) simple_actions = [action for triplet in simple_from_durative.values() for action in triplet] requirements = pddl.Requirements([]) types = [pddl.Type(ty.name, ty.basetype_name) for ty in types] pddl_parser.parsing_functions.set_supertypes(types) predicates = [pddl.Predicate(p.name, p.arguments) for p in predicates] constants = convert_parameters(constants) axioms = list(map(convert_axiom, axioms)) return SimplifiedDomain(name, requirements, types, {ty.name: ty for ty in types}, constants, predicates, {p.name: p for p in predicates}, functions, simple_actions, axioms, simple_from_durative, domain_pddl)
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 parse_task_custom(checker, type_dict, predicate_dict): # parse problem file checker.parse_code(checker.files['problem'], checker.parse_token_problem) yield checker.names['problem'] yield checker.names['domain'] yield pddl.Requirements([]) yield parse_typed_list(checker.objects) initial = [] initial_true = set() initial_false = set() initial_assignments = dict() for fact in checker.init_: 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 yield parse_condition(checker.goal_logic, type_dict, predicate_dict) yield False
def parse_task(domain_pddl, task_pddl): domain_name, domain_requirements, types, type_dict, constants, predicates, predicate_dict, functions, actions, axioms \ = parse_domain_pddl(domain_pddl) task_name, task_domain_name, task_requirements, objects, init, goal, use_metric = parse_task_pddl(task_pddl, type_dict, predicate_dict) assert domain_name == task_domain_name requirements = pddl.Requirements(sorted(set( domain_requirements.requirements + task_requirements.requirements))) objects = constants + objects check_for_duplicates( [o.name for o in objects], errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") # init += [pddl.Atom("=", (obj.name, obj.name)) for obj in objects] return pddl.Task( domain_name, task_name, requirements, types, objects, predicates, functions, init, goal, actions, axioms, use_metric)
def task_from_domain_problem(domain, problem): # TODO: prune eval domain_name, domain_requirements, types, type_dict, constants, \ predicates, predicate_dict, functions, actions, axioms = domain task_name, task_domain_name, task_requirements, objects, init, goal, use_metric = problem assert domain_name == task_domain_name requirements = pddl.Requirements(sorted(set(domain_requirements.requirements + task_requirements.requirements))) objects = constants + objects check_for_duplicates([o.name for o in objects], errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") init.extend(pddl.Atom(EQ, (obj.name, obj.name)) for obj in objects) task = pddl.Task(domain_name, task_name, requirements, types, objects, predicates, functions, init, goal, actions, axioms, use_metric) normalize.normalize(task) return task
def parse_task(domain_pddl, task_pddl, parser): if not parser: domain_name, domain_requirements, types, type_dict, constants, predicates, predicate_dict, functions, actions, axioms \ = parse_domain_pddl(domain_pddl) task_name, task_domain_name, task_requirements, objects, init, goal, use_metric = parse_task_pddl( task_pddl, type_dict, predicate_dict) else: # set files parser.set_files(domain_pddl, task_pddl) domain_name, domain_requirements, types, type_dict, constants, predicates, predicate_dict, functions, actions, axioms \ = parse_domain_custom(parser) task_name, task_domain_name, task_requirements, objects, init, goal, use_metric = parse_task_custom( parser, type_dict, predicate_dict) # remove actions parser.remove_actions() # update domain parser.update_domain() assert domain_name == task_domain_name requirements = pddl.Requirements( sorted( set(domain_requirements.requirements + task_requirements.requirements))) objects = constants + objects check_for_duplicates( [o.name for o in objects], errmsg="error: duplicate object %r", finalmsg="please check :constants and :objects definitions") init += [pddl.Atom("=", (obj.name, obj.name)) for obj in objects] return pddl.Task(domain_name, task_name, requirements, types, objects, predicates, functions, init, goal, actions, axioms, use_metric)
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
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 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 = [] num_initial = [] initial_true = set() initial_false = set() initial_assignments = dict() for fact in init[1:]: # if DEBUG: print("Analyzing fact %s"%fact) if fact[0] == "=": # if DEBUG: print("Fact is '=' assignment") 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 num_initial.append(assignment) elif fact[0] == "not": # if DEBUG: print("Fact is negation") atom = pddl.Atom(fact[1][0], fact[1][1:]) check_atom_consistency(atom, initial_false, initial_true, False) initial_false.add(atom) else: # if DEBUG: print("Fact is positive atom") atom = pddl.Atom(fact[0], fact[1:]) check_atom_consistency(atom, initial_true, initial_false) initial_true.add(atom) # if DEBUG: print("initial_true is %s"%sorted(initial_true)) initial.extend(initial_true) if DEBUG: initial.sort( key=lambda x: x.__repr__()) # makes the result deterministic # print("initial is s%s"%initial) yield initial # yielding num_initial delayed (metric section may add artificial fluent 'total-cost' # goal goal = next(iterator) assert goal[0] == ":goal" and len(goal) == 2 #metric metric_symbol = '<' # minimize metric_expression = None # unit cost for entry in iterator: if entry[0] == ":metric": if entry[1] == "minimize": metric_symbol = '<' else: assert entry[ 1] == "maximize", "Unknown metric, 'minimize' or 'maximize' expected." metric_symbol = '>' # try: metric_expression = parse_expression(entry[2]) # except: # raise SystemExit("Cannot parse metric expression in %s" % entry[2]) if metric_expression is None: metric_expression = pddl.PrimitiveNumericExpression( 'total-cost', [], 'I') num_initial.append(parse_assignment(['=', 'total-cost', 0])) # print("parsing_functions yields num_initial:", num_initial) yield num_initial yield parse_condition(goal[1], type_dict, predicate_dict) yield (metric_symbol, metric_expression) for entry in iterator: assert False, entry
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