00001 import string
00002 import conditions
00003 import pddl
00004
00005 def isFloat(astring):
00006 try:
00007 float(astring)
00008 except ValueError:
00009 return False
00010 return True
00011
00012 def parse_expression(exp, durative=False):
00013 if isinstance(exp, list):
00014 alist = exp
00015 operator_or_functionsymbol = alist[0]
00016 if operator_or_functionsymbol in ("+","/","*","-"):
00017 args = [parse_expression(arg,durative) for arg in alist[1:]]
00018 operator = operator_or_functionsymbol
00019 elif operator_or_functionsymbol == "?duration":
00020 return DurationVariable()
00021 else:
00022 return PrimitiveNumericExpression(operator_or_functionsymbol,
00023 [conditions.parse_term(arg) for arg in alist[1:]])
00024 if operator == "+":
00025 return Sum(args)
00026 elif operator == "/":
00027 assert len(args) == 2
00028 return Quotient(args)
00029 elif operator == "*":
00030 return Product(args)
00031 else:
00032 if len(args) == 1:
00033 return AdditiveInverse(args)
00034 else:
00035 assert len(args) == 2
00036 return Difference(args)
00037 elif isFloat(exp):
00038 return NumericConstant(string.atof(exp))
00039 elif exp == "?duration":
00040 return DurationVariable()
00041 else:
00042 return PrimitiveNumericExpression(exp,[])
00043
00044 def parse_assignment(alist, durative=False):
00045 assert len(alist) == 3
00046 op = alist[0]
00047 head = parse_expression(alist[1])
00048 exp = parse_expression(alist[2],durative)
00049 if op == "assign" or op == "=":
00050 return Assign(head, exp)
00051 elif op == "scale-up":
00052 return ScaleUp(head, exp)
00053 elif op == "scale-down":
00054 return ScaleDown(head, exp)
00055 elif op == "increase":
00056 return Increase(head, exp)
00057 elif op == "decrease":
00058 return Decrease(head, exp)
00059
00060
00061 class FunctionalExpression(object):
00062 def __init__(self,parts):
00063 self.parts = tuple(parts)
00064 self.hash = hash((self.__class__, self.parts))
00065 def __hash__(self):
00066 return self.hash
00067 def __ne__(self, other):
00068 return not self == other
00069 def free_variables(self):
00070 result = set()
00071 for part in self.parts:
00072 result |= part.free_variables()
00073 return result
00074 def dump(self, indent=" "):
00075 print "%s%s" % (indent, self._dump())
00076 for part in self.parts:
00077 part.dump(indent + " ")
00078 def _dump(self):
00079 return self.__class__.__name__
00080 def _postorder_visit(self, method_name, *args):
00081 part_results = [part._postorder_visit(method_name, *args)
00082 for part in self.parts]
00083 method = getattr(self, method_name, self._propagate)
00084 return method(part_results, *args)
00085 def _propagate(self, parts, *args):
00086 return self.change_parts(parts)
00087 def primitive_numeric_expressions(self):
00088 result = set()
00089 for part in self.parts:
00090 result |= part.primitive_numeric_expressions()
00091 return result
00092 def compile_objectfunctions_aux(self,used_variables, recurse_object_terms=True):
00093 typed_vars = []
00094 conjunction_parts = []
00095 new_parts = []
00096 for part in self.parts:
00097 typed,parts,new_part = part.compile_objectfunctions_aux(used_variables,
00098 recurse_object_terms)
00099 typed_vars += typed
00100 conjunction_parts += parts
00101 new_parts.append(new_part)
00102 return (typed_vars,conjunction_parts,self.__class__(new_parts))
00103 def instantiate(self, var_mapping, fluent_functions,
00104 init_function_vals, task, new_axioms=[]):
00105 print self.__class__.__name__
00106 raise ValueError("Cannot instantiate condition: not normalized")
00107
00108
00109 class ArithmeticExpression(FunctionalExpression):
00110 def __eq__(self,other):
00111 return (self.hash == other.hash and
00112 self.__class__ == other.__class__ and
00113 self.parts == other.parts)
00114 def rename_variables(self, renamings={}):
00115 return self.__class__([part.rename_variables(renamings)
00116 for part in self.parts])
00117 def change_parts(self, parts):
00118 return self.__class__(parts)
00119 def remove_duration_variable(self, action, time, duration, pnes):
00120 return self.__class__([part.remove_duration_variable(action, time, duration, pnes)
00121 for part in self.parts])
00122
00123 class Quotient(ArithmeticExpression):
00124 op = "/"
00125 def __init__(self,parts):
00126 assert len(parts)==2
00127 ArithmeticExpression.__init__(self,parts)
00128 def _simplified(self, parts):
00129 if isinstance(parts[1], NumericConstant) and parts[1].value == 1:
00130 return parts[0]
00131 else:
00132 return self._propagate(parts)
00133
00134 class Difference(ArithmeticExpression):
00135 op = "-"
00136 def __init__(self,parts):
00137 assert len(parts)==2
00138 ArithmeticExpression.__init__(self,parts)
00139 def _simplified(self, parts):
00140 if isinstance(parts[1], NumericConstant) and parts[1].value == 0:
00141 return parts[0]
00142 else:
00143 return self._propagate(parts)
00144
00145 class AdditiveInverse(ArithmeticExpression):
00146 op = "-"
00147 def __init__(self,parts):
00148 assert len(parts)==1
00149 ArithmeticExpression.__init__(self,parts)
00150 def _simplified(self, parts):
00151 return self._propagate(parts)
00152
00153 class Sum(ArithmeticExpression):
00154 op = "+"
00155 def _simplified(self, parts):
00156 result_parts = []
00157 for part in parts:
00158 if isinstance(part, Sum):
00159 result_parts += part.parts
00160 elif not (isinstance(part, NumericConstant) and part.value == 0):
00161 result_parts.append(part)
00162 if not result_parts:
00163 return NumericConstant(0)
00164 if len(result_parts) == 1:
00165 return result_parts[0]
00166 return Sum(result_parts)
00167
00168 class Product(ArithmeticExpression):
00169 op = "*"
00170 def _simplified(self, parts):
00171 result_parts = []
00172 for part in parts:
00173 if isinstance(part, Product):
00174 result_parts += part.parts
00175 elif isinstance(part, NumericConstant) and part.value == 0:
00176 return NumericConstant(0)
00177 elif not (isinstance(part, NumericConstant) and part.value == 1):
00178 result_parts.append(part)
00179 if not result_parts:
00180 return NumericConstant(1)
00181 if len(result_parts) == 1:
00182 return result_parts[0]
00183 return Product(result_parts)
00184
00185 class NumericConstant(FunctionalExpression):
00186 parts = ()
00187 def __init__(self, value):
00188 self.value = value
00189 self.hash = hash((self.__class__, self.value))
00190 def __eq__(self, other):
00191 return (self.__class__ == other.__class__ and self.value == other.value)
00192 def __str__(self):
00193 return str(self.value)
00194 def _dump(self):
00195 return self.value
00196 def rename_variables(self, renamings={}):
00197 return self
00198 def instantiate(self, var_mapping, fluent_functions,
00199 init_function_vals, task, new_axioms=[]):
00200 return self
00201 def change_parts(self, parts):
00202 return self
00203 def compile_objectfunctions_aux(self, used_variables, recurse_object_terms=True):
00204 return ([],[],self)
00205 def remove_duration_variable(self, action, time, duration, pnes):
00206 return self
00207
00208 class PrimitiveNumericExpression(FunctionalExpression):
00209 parts = ()
00210 def __init__(self, symbol, args):
00211 self.symbol = symbol
00212 self.args = tuple(args)
00213 self.hash = hash((self.__class__, self.symbol, self.args))
00214 def __str__(self):
00215 return "PNE %s(%s)" % (self.symbol, ", ".join(map(str, self.args)))
00216 def __eq__(self, other):
00217 return (self.__class__ is other.__class__ and
00218 self.hash == other.hash and
00219 self.symbol == other.symbol and
00220 self.args == other.args)
00221 def dump(self, indent=" "):
00222 print "%s%s" % (indent, self._dump())
00223 for arg in self.args:
00224 arg.dump(indent + " ")
00225 def _dump(self):
00226 return str(self)
00227 def rename_variables(self, renamings):
00228 new_args = [renamings.get(arg, arg) for arg in self.args]
00229 return self.__class__(self.symbol, new_args)
00230 def free_variables(self):
00231 return set(arg.name for arg in self.args if isinstance(arg,conditions.Variable))
00232 def change_parts(self, parts):
00233 return self
00234 def primitive_numeric_expressions(self):
00235 return set([self])
00236 def compile_objectfunctions_aux(self, used_variables, recurse_object_terms=True):
00237 typed_vars = []
00238 conjunction_parts = []
00239 new_args = []
00240 for term in self.args:
00241 typed,parts,new_term = term.compile_objectfunctions_aux(used_variables,
00242 recurse_object_terms)
00243 typed_vars += typed
00244 conjunction_parts += parts
00245 new_args.append(new_term)
00246 return (typed_vars,conjunction_parts,self.__class__(self.symbol,new_args))
00247 def instantiate(self, var_mapping, fluent_functions,
00248 init_function_vals, task, new_axioms=[]):
00249 args = [var_mapping.get(conditions.Variable(arg.name),arg) for arg in self.args]
00250 pne = PrimitiveNumericExpression(self.symbol, args)
00251
00252
00253 if fluent_functions!=None:
00254 if pne not in fluent_functions and not pne.symbol.startswith("derived!"):
00255 if pne not in init_function_vals:
00256 raise ValueError("Cannot instantiate non-fluent PNE: no initial value given %s" % pne)
00257 constant = init_function_vals[pne]
00258 new_axiom_predicate = task.function_administrator.get_derived_function(constant)
00259 new_axiom = task.function_administrator.functions[(constant.value,)]
00260 new_axiom = new_axiom.instantiate(var_mapping, fluent_functions,init_function_vals,
00261 task, new_axioms)
00262 new_axioms.add(new_axiom)
00263 ground_name = pne.symbol + " " + str(len(pne.args)) + " " + " ".join(map(lambda x: x.name, list(pne.args)))
00264 pddl.Task.CONSTANT_MAPPING[ground_name] = new_axiom_predicate
00265 return new_axiom_predicate
00266 return pne
00267 def remove_duration_variable(self, action, time, duration, pnes):
00268 return self
00269
00270 class FunctionAssignment(object):
00271 def __init__(self, fluent, expression):
00272 self.fluent = fluent
00273 self.expression = expression
00274 self.hash = hash((self.__class__.__name__, self.fluent, self.expression))
00275 def __str__(self):
00276 return "%s %s %s" % (self.__class__.__name__, self.fluent, self.expression)
00277 def __eq__(self, other):
00278 return (self.__class__ is other.__class__ and
00279 self.hash == other.hash and
00280 self.fluent == other.fluent and
00281 self.expression == other.expression)
00282 def dump(self, indent=" "):
00283 print "%s%s" % (indent, self._dump())
00284 self.fluent.dump(indent + " ")
00285 self.expression.dump(indent + " ")
00286 def _dump(self):
00287 return self.__class__.__name__
00288 def rename_variables(self, renamings):
00289 return self.__class__(self.fluent.rename_variables(renamings),
00290 self.expression.rename_variables(renamings))
00291 def free_variables(self):
00292 return self.fluent.free_variables() | self.expression.free_variables()
00293 def instantiate(self, var_mapping, init_facts, fluent_facts,
00294 init_function_vals, fluent_functions, task, new_axioms, modules, result):
00295 if not isinstance(self.expression,PrimitiveNumericExpression):
00296 raise ValueError("Cannot instantiate assignment: not normalized")
00297 fluent = self.fluent.instantiate(var_mapping, fluent_functions,
00298 init_function_vals, task, new_axioms)
00299 expression = self.expression.instantiate(var_mapping, fluent_functions,
00300 init_function_vals, task, new_axioms)
00301 result.append(self.__class__(fluent,expression))
00302
00303 class Assign(FunctionAssignment):
00304 symbol = "="
00305 def __str__(self):
00306 return "%s := %s" % (self.fluent, self.expression)
00307
00308 class ScaleUp(FunctionAssignment):
00309 symbol = "*"
00310 pass
00311
00312 class ScaleDown(FunctionAssignment):
00313 symbol = "/"
00314 pass
00315
00316 class Increase(FunctionAssignment):
00317 symbol = "+"
00318 pass
00319
00320 class Decrease(FunctionAssignment):
00321 symbol = "-"
00322 pass
00323
00324 class DurationVariable(FunctionalExpression):
00325 parts = ()
00326 def __init__(self):
00327 self.hash = hash(self.__class__)
00328 def __str__(self):
00329 return "?duration"
00330 def _dump(self):
00331 return str(self)
00332 def rename_variables(self, renamings={}):
00333 return self
00334 def change_parts(self, parts):
00335 return self
00336 def compile_objectfunctions_aux(self, used_variables, recurse_object_terms=True):
00337 return ([],[],self)
00338 def remove_duration_variable(self, action, time, duration, pnes):
00339 if time == 0:
00340 return duration
00341 else:
00342 name = "duration_" + action.name
00343 params = [conditions.Variable(param.name) for param in action.parameters]
00344 duration_function = PrimitiveNumericExpression(name, params)
00345 pnes.append(duration_function)
00346 return duration_function
00347