def verify_expression(aexp): # print("Verifying ",str(aexp)) if isinstance(aexp, pddl.PrimitiveNumericExpression): # print("- it is a PNE with fluent",aexp.symbol) if not aexp.symbol in function_names: msg = ( "WARNING: Function symbol '%s' appears in a numeric expression but is not defined in domain file.\n" "Adding new symbol '%s' with arity %d.") % ( aexp.symbol, aexp.symbol, len(aexp.args)) print(msg, file=sys.stderr) if len(aexp.args) == 0: newfunction = pddl.Function(aexp.symbol, [], "number") task.functions.append(newfunction) initassignment = pddl.Assign(aexp, pddl.NumericConstant(0.0)) task.num_init.append(initassignment) else: # if this occurs in an actual domain, maybe we could also determine the type of the parameters of higher-arity functions raise Error( "Don't know the parameters of function %s with arity %d" % (aexp.symbol, len(aexp.args))) assert False # elif isinstance(aexp, pddl.NumericConstant): # print("- it is a constant: ",aexp.value) elif isinstance(aexp, pddl.AdditiveInverse): # print("- it is an additive inverse: ",aexp) assert len(parts) == 1 verify_expression(aexp.parts[0]) elif isinstance(aexp, pddl.ArithmeticExpression): # print("- it is an arithmetic expression: ",aexp) for part in aexp.parts: verify_expression(part)
def parse_function(alist, type_name): name = alist[0] arguments = parse_typed_list(alist[1:]) pddl.Task.FUNCTION_SYMBOLS[name] = type_name # add function name to function symbol dictionary return pddl.Function(name, arguments, type_name)
def parse_function(alist, type_name): name = alist[0] arguments = parse_typed_list(alist[1:]) return pddl.Function(name, arguments, type_name)
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