f_expression.py
Go to the documentation of this file.
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         # TODO check whether this PNE is fluent. Otherwise substitute it by the
00252         # corresponding constant
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 


tfd_modules
Author(s): Maintained by Christian Dornhege (see AUTHORS file).
autogenerated on Mon Oct 6 2014 07:52:06