00001 import itertools
00002
00003 import actions
00004 import axioms
00005 import conditions
00006 import effects
00007 import f_expression
00008 import functions
00009 import modules
00010 import predicates
00011 import pddl_types
00012
00013
00014 class Task(object):
00015 FUNCTION_SYMBOLS = dict()
00016 CONSTANT_MAPPING = dict()
00017
00018 def __init__(self, domain_name, task_name, requirements, oplinit,
00019 types, objects, modules, predicates, init, goal, actions, durative_actions, axioms, function_symbols, subplan_generators, module_inits):
00020 self.domain_name = domain_name
00021 self.task_name = task_name
00022 self.requirements = requirements
00023 self.oplinit = oplinit
00024 self.types = types
00025 self.objects = objects
00026 self.modules = modules
00027 self.predicates = predicates
00028 self.init = init
00029 self.goal = goal
00030 self.actions = actions
00031 self.durative_actions = durative_actions
00032 self.axioms = axioms
00033 self.axiom_counter = 0
00034 self.function_symbols = function_symbols
00035 self.function_administrator = DerivedFunctionAdministrator()
00036 self.subplan_generators = subplan_generators
00037 self.module_inits = module_inits
00038
00039 def add_axiom(self, parameters, condition):
00040 name = "new-axiom@%d" % self.axiom_counter
00041 self.axiom_counter += 1
00042 axiom = axioms.Axiom(name, parameters, condition)
00043 self.predicates.append(predicates.Predicate(name, parameters))
00044 self.axioms.append(axiom)
00045 return axiom
00046
00047 def parse(domain_pddl, task_pddl):
00048 domain_name, requirements, oplinit, constants, predicates, types, functions, actions, durative_actions, axioms, modules, subplan_generators \
00049 = parse_domain(domain_pddl)
00050 task_name, task_domain_name, module_inits, objects, init, goal = parse_task(task_pddl)
00051
00052 assert domain_name == task_domain_name
00053 objects = constants + objects
00054 init += [conditions.Atom("=", (conditions.parse_term(obj.name), conditions.parse_term(obj.name)))
00055 for obj in objects]
00056 return Task(domain_name, task_name, requirements, oplinit, types, objects, modules,
00057 predicates, init, goal, actions, durative_actions, axioms, Task.FUNCTION_SYMBOLS, subplan_generators, module_inits)
00058 parse = staticmethod(parse)
00059
00060 def dump(self):
00061 print "Problem %s: %s [%s]" % (self.domain_name, self.task_name,
00062 self.requirements)
00063 print "OplInit:"
00064 for init in self.oplinit:
00065 init.dump()
00066 print "Types:"
00067 for type in self.types:
00068 print " %s" % type
00069 print "Objects:"
00070 for obj in self.objects:
00071 print " %s" % obj
00072 print "Modules:"
00073 for module in self.modules:
00074 module.dump()
00075 print "Module Inits:"
00076 for mod_init in self.module_inits:
00077 mod_init.dump()
00078 print "Subplan Generators:"
00079 for spg in self.subplan_generators:
00080 spg.dump()
00081 print "Predicates:"
00082 for pred in self.predicates:
00083 print " %s" % pred
00084 print "Functions:"
00085 print " " + str(self.function_symbols)
00086 print "Init:"
00087 for fact in self.init:
00088 fact.dump()
00089 print "Goal:"
00090 self.goal.dump()
00091 print "Derived Functions:"
00092 self.function_administrator.dump()
00093 if self.actions:
00094 print "Actions:"
00095 for action in self.actions:
00096 action.dump()
00097 if self.durative_actions:
00098 print "Durative Actions:"
00099 for action in self.durative_actions:
00100 action.dump()
00101 if self.axioms:
00102 print "Axioms:"
00103 for axiom in self.axioms:
00104 axiom.dump()
00105
00106 class Requirements(object):
00107 def __init__(self, requirements):
00108 self.requirements = requirements
00109 for req in requirements:
00110 assert req in (
00111 ":strips", ":adl", ":typing", ":negation", ":equality",
00112 ":negative-preconditions", ":disjunctive-preconditions",
00113 ":existential-preconditions", ":universal-preconditions",
00114 ":quantified-preconditions", ":conditional-effects",
00115 ":fluents", ":object-fluents", ":numeric-fluents", ":action-costs",
00116 ":durative-actions", ":derived-predicates", ":duration-inequalities", ":modules"), req
00117 def __str__(self):
00118 return ", ".join(self.requirements)
00119
00120 class DerivedFunctionAdministrator(object):
00121
00122 def __init__(self):
00123 self.functions = dict()
00124
00125 def dump(self,indent = " "):
00126 for axiom in self.functions.values():
00127 axiom.dump(indent)
00128 def get_all_axioms(self):
00129 return self.functions.values()
00130 def get_derived_function(self,exp):
00131 def get_default_variables(nr):
00132 return [conditions.Variable("?v%s" % varnr) for varnr in range(nr)]
00133 def get_new_symbol(key):
00134
00135 used_names = [axiom.name for axiom in self.functions.values()]
00136 for counter in itertools.count(1):
00137 new_func_name = "derived!" + str(counter)
00138 if new_func_name not in used_names:
00139 Task.FUNCTION_SYMBOLS[new_func_name]="number"
00140 return new_func_name
00141
00142 assert isinstance(exp,f_expression.FunctionalExpression)
00143 if isinstance(exp,f_expression.PrimitiveNumericExpression):
00144 return exp
00145 elif isinstance(exp,f_expression.NumericConstant):
00146 key = (exp.value,)
00147 if key not in self.functions:
00148 symbol = get_new_symbol(key)
00149 self.functions[key] = axioms.NumericAxiom(symbol,[],None,[exp])
00150 args = ()
00151 elif isinstance(exp,f_expression.AdditiveInverse):
00152 subexp = self.get_derived_function(exp.parts[0])
00153 key = (exp.op, subexp.symbol)
00154 args = subexp.args
00155 if key not in self.functions:
00156 symbol = get_new_symbol(key)
00157 default_args = get_default_variables(len(subexp.args))
00158 subexp = f_expression.PrimitiveNumericExpression(subexp.symbol, default_args)
00159 self.functions[key] = axioms.NumericAxiom(symbol, default_args, exp.op, [subexp])
00160 else:
00161 assert (isinstance(exp,f_expression.ArithmeticExpression) and
00162 len(exp.parts) == 2)
00163 pne1 = self.get_derived_function(exp.parts[0])
00164 pne2 = self.get_derived_function(exp.parts[1])
00165 key = (exp.op, pne1.symbol, pne2.symbol)
00166 args = pne1.args + pne2.args
00167 if key not in self.functions:
00168 if exp.op in ("+","*"):
00169 key = (exp.op, pne2.symbol, pne1.symbol)
00170 pne1,pne2 = pne2,pne1
00171 args = pne1.args + pne2.args
00172 if key not in self.functions:
00173 symbol = get_new_symbol(key)
00174 default_args = get_default_variables(len(args))
00175 pne1 = f_expression.PrimitiveNumericExpression(pne1.symbol,
00176 default_args[:len(pne1.args)])
00177 if pne2.args:
00178 pne2 = f_expression.PrimitiveNumericExpression(pne2.symbol,
00179 default_args[-len(pne2.args):])
00180
00181 self.functions[key] = axioms.NumericAxiom(symbol, tuple(default_args),
00182 exp.op,[pne1,pne2])
00183 pne_symbol = self.functions[key].get_head().symbol
00184 return f_expression.PrimitiveNumericExpression(pne_symbol,args)
00185
00186 def parse_domain_structure(entry,the_functions,the_axioms,the_actions,the_durative_actions,
00187 the_types, the_predicates):
00188 if entry[0] == ":derived":
00189 axiom = axioms.Axiom.parse(entry)
00190 the_axioms.append(axiom)
00191 elif entry[0] == ":durative-action":
00192 action = actions.DurativeAction.parse(entry)
00193 the_durative_actions.append(action)
00194 elif entry[0] == ":functions":
00195 the_functions.extend(pddl_types.parse_typed_list(entry[1:],
00196 constructor=functions.Function.parse_typed, functions=True, types=the_types))
00197 for function in the_functions:
00198 Task.FUNCTION_SYMBOLS[function.name] = function.type
00199 if function.type != "number":
00200 the_predicates.append(
00201 predicates.Predicate(conditions.function_predicate_name(function.name),
00202 function.arguments + [pddl_types.TypedObject("?val", function.type)]))
00203 elif entry[0] == ":action":
00204 action = actions.Action.parse(entry)
00205 the_actions.append(action)
00206 else:
00207 assert False, "unknown entity"
00208
00209 def parse_domain(domain_pddl):
00210 iterator = iter(domain_pddl)
00211
00212 the_functions = []
00213 the_axioms = []
00214 the_actions = []
00215 the_durative_actions = []
00216 the_modules = []
00217 the_subplan_generators = []
00218
00219 assert iterator.next() == "define"
00220 domain_line = iterator.next()
00221 assert domain_line[0] == "domain" and len(domain_line) == 2
00222 yield domain_line[1]
00223
00224 opt_requirements = iterator.next()
00225 if opt_requirements[0] == ":requirements":
00226 yield Requirements(opt_requirements[1:])
00227 oplinit = iterator.next()
00228 else:
00229 yield Requirements([":strips"])
00230 oplinit = opt_requirements
00231
00232 if oplinit[0] == ":oplinit":
00233 yield [modules.OplInit.parse(mi) for mi in oplinit[1:]]
00234 opt_types = iterator.next()
00235 else:
00236 yield []
00237 opt_types = oplinit
00238
00239 the_types = [pddl_types.Type("object")]
00240 if opt_types[0] == ":types":
00241 the_types.extend(pddl_types.parse_typed_list(opt_types[1:],
00242 constructor=pddl_types.Type))
00243 opt_modules = iterator.next()
00244 else:
00245 opt_modules = opt_types
00246
00247 if opt_modules[0] == ":modules":
00248 for mod_entry in opt_modules[1:]:
00249 if mod_entry[0] == "subplan_generator":
00250 the_subplan_generators.append(modules.SubplanGenerator.parse(mod_entry))
00251 else:
00252 the_modules.append(modules.Module.parse(mod_entry))
00253 opt_constants = iterator.next()
00254 else:
00255 opt_constants = opt_modules
00256
00257 if opt_constants[0] == ":constants":
00258 yield pddl_types.parse_typed_list(opt_constants[1:],types=the_types)
00259 pred = iterator.next()
00260 else:
00261 yield []
00262 pred = opt_constants
00263
00264 the_predicates = []
00265 if pred[0] == ":predicates":
00266 the_predicates = ([predicates.Predicate.parse(entry) for entry in pred[1:]] +
00267 [predicates.Predicate("=",
00268 [pddl_types.TypedObject("?x", "object"),
00269 pddl_types.TypedObject("?y", "object")])])
00270 else:
00271 the_predicates = [predicates.Predicate("=",
00272 [pddl_types.TypedObject("?x", "object"),
00273 pddl_types.TypedObject("?y", "object")])]
00274 parse_domain_structure(pred,the_functions,the_axioms,the_actions,the_durative_actions,the_types,the_predicates)
00275
00276 for entry in iterator:
00277 parse_domain_structure(entry,the_functions,the_axioms,the_actions,the_durative_actions,the_types,the_predicates)
00278
00279 pddl_types.set_supertypes(the_types)
00280 the_types = [type for type in the_types if type.supertype_names != [] or type.name == "object"]
00281 yield the_predicates
00282 yield the_types
00283 yield the_functions
00284 yield the_actions
00285 yield the_durative_actions
00286 yield the_axioms
00287 yield the_modules
00288 yield the_subplan_generators
00289
00290 def parse_task(task_pddl):
00291 iterator = iter(task_pddl)
00292
00293 assert iterator.next() == "define"
00294 problem_line = iterator.next()
00295 assert problem_line[0] == "problem" and len(problem_line) == 2
00296 yield problem_line[1]
00297 domain_line = iterator.next()
00298 assert domain_line[0] == ":domain" and len(domain_line) == 2
00299 yield domain_line[1]
00300
00301 module_opt = iterator.next()
00302 if module_opt[0] == ":moduleoptions":
00303 yield [modules.ModuleInit.parse(mi) for mi in module_opt[1:]]
00304 objects_opt = iterator.next()
00305 else:
00306 yield []
00307 objects_opt = module_opt
00308
00309 if objects_opt[0] == ":objects":
00310 yield pddl_types.parse_typed_list(objects_opt[1:])
00311 init = iterator.next()
00312 else:
00313 yield []
00314 init = objects_opt
00315
00316 assert init[0] == ":init"
00317 initial = []
00318 for fact in init[1:]:
00319 if fact[0] == "=":
00320 if conditions.is_function_comparison(fact):
00321 initial.append(f_expression.parse_assignment(fact))
00322 else:
00323 function = conditions.parse_term(fact[1])
00324 terms = function.args
00325 terms.append(conditions.parse_term(fact[2]))
00326 atomname = conditions.function_predicate_name(function.name)
00327 initial.append(conditions.Atom(atomname, terms))
00328 else:
00329 initial.append(conditions.Atom(fact[0], [conditions.parse_term(term) for term in fact[1:]]))
00330 yield initial
00331
00332 goal = iterator.next()
00333 assert goal[0] == ":goal" and len(goal) == 2
00334 yield conditions.parse_condition(goal[1])
00335
00336 for entry in iterator:
00337 if entry[0] == ":metric" and entry[1]=="minimize":
00338 if entry[2][0] in ["total-time", "total-cost"] :
00339 continue
00340 assert False, "Can only minimize total-time or total-cost, got: " + str(entry)