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_assignment(alist): assert len(alist) == 3 op = alist[0] head = parse_expression(alist[1]) exp = parse_expression(alist[2]) if op == "=": return pddl.Assign(head, exp) elif op == "increase": return pddl.Increase(head, exp) else: assert False, "Assignment operator not supported."
def remove_duration_variable(task): def recurse(condition, act, time, duration, pnes): if isinstance(condition, pddl.FunctionComparison): parts = [ exp.remove_duration_variable(act, time, duration, pnes) for exp in condition.parts ] return condition.__class__(condition.comparator, parts) # return pddl.FunctionComparison(condition.comparator,parts) else: new_parts = [ recurse(part, act, time, duration, pnes) for part in condition.parts ] return condition.change_parts(new_parts) for act in task.durative_actions: assert len(act.duration[1]) == 0, "at end durations are not supported" assert len(act.duration[0]) == 1 and act.duration[0][0][0] == "=" duration = act.duration[0][0][1] duration_functions = [] # remove from action conditions condition = [] for time, cond in enumerate(act.condition): condition.append( recurse(cond, act, time, duration, duration_functions)) act.condition = condition for time in range(2): for eff in act.effects[time]: # remove from effect condition condition = [] for eff_time, cond in enumerate(eff.condition): condition.append( recurse(cond, act, eff_time, duration, duration_functions)) eff.condition = condition # remove from effect if isinstance(eff.peffect, pddl.FunctionAssignment): assign = eff.peffect assign.expression = assign.expression.remove_duration_variable( act, time, duration, duration_functions) for pne in duration_functions: assign = pddl.Assign(pne, duration) condition = [pddl.Truth(), pddl.Truth(), pddl.Truth()] effect = pddl.Effect([], condition, assign) act.effects[0].append(effect) task.function_symbols[pne.symbol] = "number"
def parse_assignment(alist): assert len(alist) == 3 op = alist[0] head = parse_expression(alist[1]) exp = parse_expression(alist[2]) if op == "assign" or op == "=": return pddl.Assign(head, exp) elif op == "scale-up": return pddl.ScaleUp(head, exp) elif op == "scale-down": return pddl.ScaleDown(head, exp) elif op == "increase": return pddl.Increase(head, exp) elif op == "decrease": return pddl.Decrease(head, exp) else: assert False, "Assignment operator not supported."
def instantiate(task, model): relaxed_reachable = False fluent_facts = get_fluent_facts(task, model) fluent_functions = get_fluent_functions(model) ## HACK: This is a not very clean way of initializing the previously ## added functions that store the duration of an action to a haphazardly value for atom in model: if isinstance(atom.predicate,str) and atom.predicate.startswith("defined!duration_"): pne = pddl.PrimitiveNumericExpression(atom.predicate.replace("defined!","",1),atom.args) value = pddl.NumericConstant(1.0) init_assign = pddl.Assign(pne, value) task.init.append(init_assign) init_facts = set(task.init) # TODO adapt init_function_vals = init_function_values(init_facts) # print "** fluent functions" # for function in fluent_functions: # function.dump() # print "** fluent facts" # for fact in fluent_facts: # print fact # print "** init facts" # for fact in init_facts: # print fact type_to_objects = get_objects_by_type(task.objects,task.types) instantiated_actions = [] instantiated_durative_actions = [] instantiated_axioms = [] instantiated_numeric_axioms = set() new_constant_numeric_axioms = set() reachable_action_parameters = defaultdict(list) for atom in model: if isinstance(atom.predicate, pddl.Action): action = atom.predicate parameters = action.parameters if isinstance(action.condition, pddl.ExistentialCondition): parameters = list(parameters) parameters += action.condition.parameters variable_mapping = dict([(pddl.Variable(par.name), arg) for par, arg in zip(parameters, atom.args)]) inst_action = action.instantiate(variable_mapping, init_facts, fluent_facts, init_function_vals, fluent_functions, task, new_constant_numeric_axioms, type_to_objects) if inst_action: instantiated_actions.append(inst_action) elif isinstance(atom.predicate, pddl.DurativeAction): action = atom.predicate parameters = action.parameters reachable_action_parameters[action.name].append(parameters) for condition in action.condition: if isinstance(condition,pddl.ExistentialCondition): parameters = list(parameters) parameters += condition.parameters variable_mapping = dict([(pddl.Variable(par.name), arg) for par, arg in zip(parameters, atom.args)]) inst_action = action.instantiate(variable_mapping, init_facts, fluent_facts, init_function_vals, fluent_functions, task, new_constant_numeric_axioms, type_to_objects) if inst_action: instantiated_durative_actions.append(inst_action) elif isinstance(atom.predicate, pddl.Axiom): axiom = atom.predicate parameters = axiom.parameters if isinstance(axiom.condition, pddl.ExistentialCondition): parameters = list(parameters) parameters += axiom.condition.parameters variable_mapping = dict([(pddl.Variable(par.name), arg) for par, arg in zip(parameters, atom.args)]) inst_axiom = axiom.instantiate(variable_mapping, init_facts, fluent_facts, fluent_functions, init_function_vals, task, new_constant_numeric_axioms) if inst_axiom: instantiated_axioms.append(inst_axiom) elif isinstance(atom.predicate, pddl.NumericAxiom): axiom = atom.predicate variable_mapping = dict([(pddl.Variable(par.name), arg) for par, arg in zip(axiom.parameters, atom.args)]) new_constant_numeric_axioms = set() inst_axiom = axiom.instantiate(variable_mapping, fluent_functions, init_function_vals, task, new_constant_numeric_axioms) instantiated_numeric_axioms.add(inst_axiom) elif atom.predicate == "@goal-reachable": relaxed_reachable = True instantiated_numeric_axioms |= new_constant_numeric_axioms return (relaxed_reachable, fluent_facts, fluent_functions, instantiated_actions, instantiated_durative_actions, instantiated_axioms, instantiated_numeric_axioms, reachable_action_parameters)
def instantiate(task, model): relaxed_reachable = False fluent_facts = get_fluent_facts(task, model) fluent_functions = get_fluent_functions(model) ## HACK: This is a not very clean way of initializing the previously ## added functions that store the duration of an action to a haphazardly value for atom in model: if isinstance(atom.predicate, str) and atom.predicate.startswith("defined!duration_"): pne = pddl.PrimitiveNumericExpression( atom.predicate.replace("defined!", "", 1), atom.args) value = pddl.NumericConstant(1.0) init_assign = pddl.Assign(pne, value) task.init.append(init_assign) init_facts = set(task.init) # TODO adapt init_function_vals = init_function_values(init_facts) # Determine initial facts, that are not fluents => constant facts, that a module might need init_constant_fluents = set(init_function_vals) init_constant_fluents.difference_update( fluent_functions ) # all fluents that are in init, but are NOT a fluent -> constant # Now get the assigned values from the init_facts for the constant fluents init_constant_numeric_facts = set( ) # This will hold Assigns that assign the fluents for i in init_constant_fluents: for j in init_facts: if isinstance(j, pddl.Assign): if isinstance(j.fluent, pddl.PrimitiveNumericExpression): if j.fluent is i: # Assign in init_fact assign this (i) fluent init_constant_numeric_facts.add(j) # Now get predicates that are in init, but are not fluent_facts init_constant_predicate_facts = set() for i in init_facts: if isinstance(i, pddl.Atom): # do NOT consider PNEs, etc. if i not in fluent_facts: # only consider non-fluents if i.predicate is not "=": # hack to remove the intermediate '=' fluents init_constant_predicate_facts.add(i) # print "** fluent functions" # for function in fluent_functions: # function.dump() # print "** fluent facts" # for fact in fluent_facts: # print fact # print "** init facts" # for fact in init_facts: # print fact type_to_objects = get_objects_by_type(task.objects, task.types) instantiated_actions = [] instantiated_durative_actions = [] instantiated_axioms = [] instantiated_numeric_axioms = set() new_constant_numeric_axioms = set() reachable_action_parameters = defaultdict(list) instantiated_modules = set() for atom in model: if isinstance(atom.predicate, pddl.Action): action = atom.predicate parameters = action.parameters if isinstance(action.condition, pddl.ExistentialCondition): parameters = list(parameters) parameters += action.condition.parameters variable_mapping = dict([ (pddl.Variable(par.name), arg) for par, arg in zip(parameters, atom.args) ]) inst_action = action.instantiate(variable_mapping, init_facts, fluent_facts, init_function_vals, fluent_functions, task, new_constant_numeric_axioms, instantiated_modules, type_to_objects) if inst_action: instantiated_actions.append(inst_action) elif isinstance(atom.predicate, pddl.DurativeAction): action = atom.predicate parameters = action.parameters reachable_action_parameters[action.name].append(parameters) for condition in action.condition: if isinstance(condition, pddl.ExistentialCondition): parameters = list(parameters) parameters += condition.parameters variable_mapping = dict([ (pddl.Variable(par.name), arg) for par, arg in zip(parameters, atom.args) ]) inst_action = action.instantiate(variable_mapping, init_facts, fluent_facts, init_function_vals, fluent_functions, task, new_constant_numeric_axioms, instantiated_modules, type_to_objects) if inst_action: instantiated_durative_actions.append(inst_action) elif isinstance(atom.predicate, pddl.Axiom): axiom = atom.predicate parameters = axiom.parameters if isinstance(axiom.condition, pddl.ExistentialCondition): parameters = list(parameters) parameters += axiom.condition.parameters variable_mapping = dict([ (pddl.Variable(par.name), arg) for par, arg in zip(parameters, atom.args) ]) inst_axiom = axiom.instantiate(variable_mapping, init_facts, fluent_facts, fluent_functions, init_function_vals, task, new_constant_numeric_axioms, instantiated_modules) if inst_axiom: instantiated_axioms.append(inst_axiom) elif isinstance(atom.predicate, pddl.NumericAxiom): axiom = atom.predicate variable_mapping = dict([ (pddl.Variable(par.name), arg) for par, arg in zip(axiom.parameters, atom.args) ]) new_constant_numeric_axioms = set() inst_axiom = axiom.instantiate(variable_mapping, fluent_functions, init_function_vals, task, new_constant_numeric_axioms) instantiated_numeric_axioms.add(inst_axiom) elif atom.predicate == "@goal-reachable": relaxed_reachable = True instantiated_numeric_axioms |= new_constant_numeric_axioms return (relaxed_reachable, fluent_facts, fluent_functions, instantiated_actions, instantiated_durative_actions, instantiated_axioms, instantiated_numeric_axioms, instantiated_modules, init_constant_predicate_facts, init_constant_numeric_facts, reachable_action_parameters)