conditions.py
Go to the documentation of this file.
00001 import itertools
00002 
00003 import pddl_types
00004 import f_expression
00005 import tasks
00006 
00007 def parse_condition(alist):
00008     condition = parse_condition_aux(alist, False)
00009     return condition
00010 
00011 def parse_condition_aux(alist, negated):
00012     """Parse a PDDL condition. The condition is translated into NNF on the fly."""
00013     tag = alist[0]
00014 
00015     if is_function_comparison(alist):
00016         args = [f_expression.parse_expression(arg) for arg in alist[1:]]
00017         assert len(args) == 2, args
00018         if negated:
00019             return NegatedFunctionComparison(tag, args, True)
00020         else:
00021             return FunctionComparison(tag, args, True)
00022     elif tag in ("and", "or", "not", "imply"):
00023         args = alist[1:]
00024         if tag == "imply":
00025             assert len(args) == 2
00026         if tag == "not":
00027             assert len(args) == 1
00028             return parse_condition_aux(args[0], not negated)
00029     elif tag in ("forall", "exists"):
00030         parameters = pddl_types.parse_typed_list(alist[1])
00031         args = alist[2:]
00032         assert len(args) == 1
00033     elif tag == "[":
00034         assert not negated
00035         assert alist[-1] == "]"
00036         alist = alist[1:-1] # strip [ and ]
00037         # where go the type checks here? parameter should match the module...
00038         # somewhere check the "nestedness" as we want them at the top only?
00039         # Perhaps later in translate meckern
00040         return ModuleCall(alist[0], [parse_term(term) for term in alist[1:]])
00041     elif negated:
00042         return NegatedAtom(alist[0], [parse_term(term) for term in alist[1:]])
00043     else:
00044         return Atom(alist[0],[parse_term(term) for term in alist[1:]])
00045 
00046 
00047     if tag == "imply":
00048         parts = [parse_condition_aux(args[0], not negated),
00049                  parse_condition_aux(args[1], negated)]
00050         tag = "or"
00051     else:
00052         parts = [parse_condition_aux(part, negated) for part in args]
00053     if tag == "and" and not negated or tag == "or" and negated:
00054         return Conjunction(parts)
00055     elif tag == "or" and not negated or tag == "and" and negated:
00056         return Disjunction(parts)
00057     elif tag == "forall" and not negated or tag == "exists" and negated:
00058         return UniversalCondition(parameters, parts)
00059     elif tag == "exists" and not negated or tag == "forall" and negated:
00060         return ExistentialCondition(parameters, parts)
00061 
00062 def parse_durative_condition(alist):
00063     """Parse a durative PDDL condition. i
00064        The condition is translated into NNF on the fly.
00065        Returns triple [start condition, over all condition, end condition]"""
00066     if len(alist)==0:
00067         return [Truth(), Truth(),Truth()]
00068     tag = alist[0]
00069     if tag == "and":
00070         args = alist[1:]
00071         parts = [parse_durative_condition(part) for part in args]
00072         parts_begin = [part[0] for part in parts]
00073         parts_end = [part[1] for part in parts]
00074         parts_all = [part[2] for part in parts]
00075         return [Conjunction(parts_begin),Conjunction(parts_end),Conjunction(parts_all)]
00076     elif tag == "forall":
00077         parameters = pddl_types.parse_typed_list(alist[1])
00078         args = alist[2:]
00079         assert len(args) == 1
00080         parts = [parse_durative_condition(part) for part in args]
00081         parts_begin = [part[0] for part in parts]
00082         parts_end = [part[1] for part in parts]
00083         parts_all = [part[2] for part in parts]
00084         return [UniversalCondition(parameters, parts_begin),
00085             UniversalCondition(parameters, parts_end),
00086             UniversalCondition(parameters, parts_all)]
00087     elif tag == "at":
00088         assert len(alist) == 3
00089         assert alist[1] in ("start", "end")
00090         condition = parse_condition_aux(alist[2], False)
00091         if alist[1] == "start":
00092             return [condition, Truth(), Truth()]
00093         else:
00094             return [Truth(), Truth(), condition]
00095     elif tag == "over":
00096         assert alist[1] == "all"
00097         assert len(alist) == 3
00098         condition = parse_condition_aux(alist[2], False)
00099         return [Truth(), condition, Truth()]
00100 
00101 def is_function_comparison(alist):
00102     tag = alist[0]
00103     if tag in (">","<",">=","<="):
00104         return True
00105     if not tag == "=":
00106         return False
00107 
00108     # tag is '='
00109     symbol = alist[1]
00110     if isinstance(symbol,list):
00111         if symbol[0] in ("+","/","*","-"):
00112             return True
00113         symbol = symbol[0]
00114     if (tasks.Task.FUNCTION_SYMBOLS.get(symbol,"object")=="number" or 
00115         symbol.replace(".","").isdigit()):
00116         return True
00117     return False
00118 
00119 def parse_literal(alist):
00120     if alist[0] == "not":
00121         assert len(alist) == 2
00122         alist = alist[1]
00123         return NegatedAtom(alist[0], [parse_term(term) for term in alist[1:]])
00124     else:
00125         return Atom(alist[0], [parse_term(term) for term in alist[1:]])
00126 
00127 def parse_term(term):
00128     if isinstance(term, list):
00129         return FunctionTerm(term[0],[parse_term(t) for t in term[1:]])
00130     elif term.startswith("?"):
00131         return Variable(term)
00132     elif term in tasks.Task.FUNCTION_SYMBOLS:
00133         return FunctionTerm(term,[])
00134     else:
00135         return ObjectTerm(term)
00136         
00137 def dump_temporal_condition(condition,indent="  "):
00138     assert len(condition)==3
00139     if not isinstance(condition[0],Truth):
00140         print "%sat start:" % indent
00141         condition[0].dump(indent+"  ")
00142     if not isinstance(condition[1],Truth):
00143         print "%sover all:" % indent
00144         condition[1].dump(indent+"  ")
00145     if not isinstance(condition[2],Truth):
00146         print "%sat end:" % indent
00147         condition[2].dump(indent+"  ")
00148 
00149 
00150 # Conditions (of any type) are immutable, because they need to
00151 # be hashed occasionally. Immutability also allows more efficient comparison
00152 # based on a precomputed hash value.
00153 #
00154 # Careful: Most other classes (e.g. Effects, Axioms, Actions) are not!
00155 
00156 class Condition(object):
00157     def __init__(self, parts):
00158         self.parts = tuple(parts)
00159         self.hash = hash((self.__class__, self.parts))
00160     def __hash__(self):
00161         return self.hash
00162     def __ne__(self, other):
00163         return not self == other
00164     def dump(self, indent="  "):
00165         print "%s%s" % (indent, self._dump())
00166         for part in self.parts:
00167             part.dump(indent + "  ")
00168     def _dump(self):
00169         return self.__class__.__name__
00170     def _postorder_visit(self, method_name, *args):
00171         part_results = [part._postorder_visit(method_name, *args)
00172                         for part in self.parts] 
00173         method = getattr(self, method_name, self._propagate)
00174         return method(part_results, *args)
00175     def _propagate(self, parts, *args):
00176         return self.change_parts(parts)
00177     def simplified(self):
00178         return self._postorder_visit("_simplified")
00179     def relaxed(self):
00180         return self._postorder_visit("_relaxed")
00181     def untyped(self):
00182         return self._postorder_visit("_untyped")
00183 
00184     def uniquify_variables(self, type_map, renamings={}):
00185         # Cannot used _postorder_visit because this requires preorder
00186         # for quantified effects.
00187         if not self.parts:
00188             return self
00189         else:
00190             return self.__class__([part.uniquify_variables(type_map, renamings)
00191                                    for part in self.parts])
00192     def to_untyped_strips(self):
00193         raise ValueError("Not a STRIPS condition: %s" % self.__class__.__name__)
00194     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00195                     fluent_functions, task, new_axiom, new_modules, result):
00196         raise ValueError("Cannot instantiate condition: not normalized")
00197     def free_variables(self):
00198         result = set()
00199         for part in self.parts:
00200             result |= part.free_variables()
00201         return result
00202     def has_disjunction(self):
00203         for part in self.parts:
00204             if part.has_disjunction():
00205                 return True
00206         return False
00207     def has_existential_part(self):
00208         for part in self.parts:
00209             if part.has_existential_part():
00210                 return True
00211         return False
00212     def has_universal_part(self):
00213         for part in self.parts:
00214             if part.has_universal_part():
00215                 return True
00216         return False
00217 
00218 class ConstantCondition(Condition):
00219     parts = ()
00220     def __init__(self):
00221         self.hash = hash(self.__class__)
00222     def change_parts(self, parts):
00223         return self
00224     def __eq__(self, other):
00225         return self.__class__ is other.__class__
00226 
00227 class Impossible(Exception):
00228     pass
00229 
00230 class Falsity(ConstantCondition):
00231     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00232                     fluent_functions, task, new_axiom, new_modules, result):
00233         raise Impossible()
00234     def negate(self):
00235         return Truth()
00236 
00237 class Truth(ConstantCondition):
00238     def to_untyped_strips(self):
00239         return []
00240     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00241                     fluent_functions, task, new_axiom, new_modules, result):
00242         pass
00243     def negate(self):
00244         return Falsity()
00245 
00246 class JunctorCondition(Condition):
00247     def __eq__(self, other):
00248         # Compare hash first for speed reasons.
00249         return (self.hash == other.hash and
00250                 self.__class__ is other.__class__ and
00251                 self.parts == other.parts)
00252     def change_parts(self, parts):
00253         return self.__class__(parts)
00254 
00255 class Conjunction(JunctorCondition):
00256     def _simplified(self, parts):
00257         result_parts = []
00258         for part in parts:
00259             if isinstance(part, Conjunction):
00260                 result_parts += part.parts
00261             elif isinstance(part, Falsity):
00262                 return Falsity()
00263             elif not isinstance(part, Truth):
00264                 result_parts.append(part)
00265         if not result_parts:
00266             return Truth()
00267         if len(result_parts) == 1:
00268             return result_parts[0]
00269         return Conjunction(result_parts)
00270     def to_untyped_strips(self):
00271         result = []
00272         for part in self.parts:
00273             result += part.to_untyped_strips()
00274         return result
00275     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00276                     fluent_functions, task, new_axiom, new_modules, result):
00277         assert not result, "Condition not simplified"
00278         for part in self.parts:
00279             part.instantiate(var_mapping, init_facts, fluent_facts, init_function_vals,
00280                              fluent_functions, task, new_axiom, new_modules, result)
00281     def negate(self):
00282         return Disjunction([p.negate() for p in self.parts])
00283 
00284 class Disjunction(JunctorCondition):
00285     def _simplified(self, parts):
00286         result_parts = []
00287         for part in parts:
00288             if isinstance(part, Disjunction):
00289                 result_parts += part.parts
00290             elif isinstance(part, Truth):
00291                 return Truth()
00292             elif not isinstance(part, Falsity):
00293                 result_parts.append(part)
00294         if not result_parts:
00295             return Falsity()
00296         if len(result_parts) == 1:
00297             return result_parts[0]
00298         return Disjunction(result_parts)
00299     def negate(self):
00300         return Conjunction([p.negate() for p in self.parts])
00301     def has_disjunction(self):
00302         return True
00303 
00304 class QuantifiedCondition(Condition):
00305     def __init__(self, parameters, parts):
00306         self.parameters = tuple(parameters)
00307         self.parts = tuple(parts)
00308         self.hash = hash((self.__class__, self.parameters, self.parts))
00309     def __eq__(self, other):
00310         # Compare hash first for speed reasons.
00311         return (self.hash == other.hash and
00312                 self.__class__ is other.__class__ and
00313                 self.parameters == other.parameters and
00314                 self.parts == other.parts)
00315     def _dump(self, indent="  "):
00316         arglist = ", ".join(map(str, self.parameters))
00317         return "%s %s" % (self.__class__.__name__, arglist)
00318     def _simplified(self, parts):
00319         if isinstance(parts[0], ConstantCondition):
00320             return parts[0]
00321         else:
00322             return self._propagate(parts)
00323     def uniquify_variables(self, type_map, renamings={}):
00324         renamings = dict(renamings) # Create a copy.
00325         new_parameters = [par.uniquify_name(type_map, renamings)
00326                           for par in self.parameters]
00327         new_parts = (self.parts[0].uniquify_variables(type_map, renamings),)
00328         return self.__class__(new_parameters, new_parts)
00329 
00330     def free_variables(self):
00331         result = Condition.free_variables(self)
00332         for par in self.parameters:
00333             result.discard(par.name)
00334         return result
00335     def change_parts(self, parts):
00336         return self.__class__(self.parameters, parts)
00337 
00338 class UniversalCondition(QuantifiedCondition):
00339 #    def _untyped(self, parts):
00340 #        type_literals = [NegatedAtom(par.type, [par.name]) for par in self.parameters]
00341 #        return UniversalCondition(self.parameters,
00342 #                                  [Disjunction(type_literals + parts)])
00343     def negate(self):
00344         return ExistentialCondition(self.parameters, [p.negate() for p in self.parts])
00345     def has_universal_part(self):
00346         return True
00347 
00348 class ExistentialCondition(QuantifiedCondition):
00349 #    def _untyped(self, parts):
00350 #        type_literals = [Atom(par.type, [par.name]) for par in self.parameters]
00351 #        return ExistentialCondition(self.parameters,
00352 #                                    [Conjunction(type_literals + parts)])
00353     def negate(self):
00354         return UniversalCondition(self.parameters, [p.negate() for p in self.parts])
00355     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00356                     fluent_functions, task, new_axiom, new_modules, result):
00357         assert not result, "Condition not simplified"
00358         self.parts[0].instantiate(var_mapping, init_facts, fluent_facts, init_function_vals,
00359                                   fluent_functions, task, new_axiom, new_modules, result)
00360     def has_existential_part(self):
00361         return True
00362 
00363 class Literal(Condition):
00364     parts = []
00365     def __eq__(self, other):
00366         # Compare hash first for speed reasons.
00367         return (self.hash == other.hash and
00368                 self.__class__ is other.__class__ and
00369                 self.predicate == other.predicate and
00370                 self.args == other.args)
00371     def __init__(self, predicate, args):
00372         self.predicate = predicate
00373         self.args = tuple(args)
00374         self.hash = hash((self.__class__, self.predicate, self.args))
00375     def __str__(self):
00376         return "%s %s(%s)" % (self.__class__.__name__, self.predicate,
00377                               ", ".join(map(str, self.args)))
00378     def dump(self, indent="  "):
00379         print "%s%s %s" % (indent, self._dump(), self.predicate)
00380         for arg in self.args:
00381             arg.dump(indent + "  ")
00382     def change_parts(self, parts):
00383         return self
00384     def uniquify_variables(self, type_map, renamings={}):
00385         if not self.args:
00386             return self
00387         else:
00388             return self.__class__(self.predicate,[arg.uniquify_variables(type_map, renamings)
00389                                                   for arg in self.args])
00390     def rename_variables(self, renamings):
00391         new_args = [arg.rename_variables(renamings) for arg in self.args]
00392         return self.__class__(self.predicate, new_args)
00393     def free_variables(self):
00394         result = set()
00395         for arg in self.args:
00396             result |= arg.free_variables()
00397         return result
00398 
00399 class Atom(Literal):
00400     negated = False
00401     def to_untyped_strips(self):
00402         return [self]
00403     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00404                     fluent_functions, task, new_axiom, new_modules, result):
00405         args = [var_mapping.get(arg, arg) for arg in self.args]
00406         atom = Atom(self.predicate, args)
00407         if atom in fluent_facts:
00408             result.append(atom)
00409         elif atom not in init_facts:
00410             raise Impossible()
00411     def negate(self):
00412         return NegatedAtom(self.predicate, self.args)
00413     def positive(self):
00414         return self
00415 
00416 class NegatedAtom(Literal):
00417     negated = True
00418     def _relaxed(self, parts):
00419         return Truth()
00420     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00421                     fluent_functions, task, new_axiom, new_modules, result):
00422         args = [var_mapping.get(arg, arg) for arg in self.args]
00423         atom = Atom(self.predicate, args)
00424         if atom in fluent_facts:
00425             result.append(NegatedAtom(self.predicate, args))
00426         elif atom in init_facts:
00427             raise Impossible()
00428     def negate(self):
00429         return Atom(self.predicate, self.args)
00430     positive = negate
00431 
00432 class ModuleCall(Condition):
00433     # Can we use _relaxed() = Truth() wenn noetig
00434     negated = False
00435     parts = []
00436     def __eq__(self, other):
00437       # Compare hash first for speed reasons.
00438       return (self.hash == other.hash and
00439               self.__class__ is other.__class__ and
00440               self.name == other.name and
00441               self.args == other.args)
00442     def __init__(self, name, args):
00443         self.name = name
00444         self.args = tuple(args)
00445         self.hash = hash((self.__class__, self.name, self.args))
00446     def change_parts(self, parts):
00447         return self
00448     def rename_variables(self, renamings):
00449         new_args = [arg.rename_variables(renamings) for arg in self.args]
00450         return self.__class__(self.name, new_args)
00451     def free_variables(self):
00452         result = set()
00453         for arg in self.args:
00454             result |= arg.free_variables()
00455         return result
00456     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00457                     fluent_functions, task, new_axiom, new_modules, result):
00458         args = [var_mapping.get(arg, arg) for arg in self.args]
00459         mc = ModuleCall(self.name, args)
00460         result.append(mc)
00461         # we also instantiate the modules here
00462         my_module = None
00463         for module in task.modules:
00464           if module.name == self.name:
00465             my_module = module
00466             break
00467         assert my_module, "No matching module for call found"
00468         
00469         if my_module:
00470           # we need to rename all args, s.th. the module's
00471           # fluents args are the same as in the modulecall.
00472           # [count ?to] and 
00473           # (count ?target - location (stepped-on ?target) effect cout@libBla.so)
00474           # -> (count ?to - location (stepped-on ?to) effect cout@libBla.so)
00475           assert len(my_module.parameters) == len(self.args)
00476           renamings = {}
00477           for param, arg in zip(my_module.parameters, self.args):
00478             pVar = Variable(param.name)
00479             renamings[pVar] = arg
00480           new_module = my_module.rename_variables(renamings)
00481           new_module.instantiate(var_mapping, new_modules)
00482     def __str__(self):
00483         return "%s %s(%s)" % (self.__class__.__name__, self.name,
00484                               ", ".join(map(str, self.args)))
00485     def __repr__(self):
00486       return self.__str__()
00487     def dump(self, indent="  "):
00488         print "%s%s %s" % (indent, self._dump(), self.name)
00489         for arg in self.args:
00490             arg.dump(indent + "  ")
00491 
00492 class FunctionComparison(Condition): # comparing numerical functions
00493     negated = False
00494     def _relaxed(self, parts):
00495         return Truth()
00496     def __init__(self, comparator, parts, compare_to_zero = False):
00497         self.comparator = comparator
00498         assert len(parts) == 2
00499         if compare_to_zero:
00500             self.parts = (f_expression.Difference(parts), f_expression.NumericConstant(0))
00501         else:
00502             self.parts = tuple(parts)
00503         self.hash = hash((self.__class__, self.comparator, self.parts))
00504     def _dump(self, indent="  "):
00505         return "%s %s" % (self.__class__.__name__, self.comparator)
00506     def __eq__(self, other):
00507         # Compare hash first for speed reasons.
00508         return (self.hash == other.hash and
00509                 self.__class__ is other.__class__ and
00510                 self.comparator == other.comparator and
00511                 self.parts == other.parts)
00512     def __str__(self):
00513         return "%s (%s %s)" % (self.__class__.__name__, self.comparator,
00514                               ", ".join(map(str, self.parts)))
00515     def uniquify_variables(self, type_map, renamings={}):
00516         return self.__class__(self.comparator,[part.rename_variables(renamings)
00517                                    for part in self.parts])
00518     def has_disjunction(self):
00519         return False
00520     def has_universal_part(self):
00521         return False
00522     def has_existential_part(self):
00523         return False
00524     def negate(self):
00525         return NegatedFunctionComparison(self.comparator, self.parts)
00526     def change_parts(self, parts):
00527         return self.__class__(self.comparator,parts)
00528     def primitive_numeric_expressions(self):
00529         result = set()
00530         for part in self.parts:
00531             result |= part.primitive_numeric_expressions()
00532         return result
00533     def instantiate(self, var_mapping, init_facts, fluent_facts, init_function_vals,
00534                     fluent_functions, task, new_axiom, new_modules, result):
00535         instantiated_parts = [part.instantiate(var_mapping, fluent_functions, 
00536                                                init_function_vals, task, new_axiom) 
00537                                                for part in self.parts]
00538         # future work: eliminate non-fluent functions
00539         result.append(self.__class__(self.comparator,instantiated_parts))
00540     def positive(self):
00541         return self
00542         
00543     
00544 class NegatedFunctionComparison(FunctionComparison):
00545     negated = True
00546     def negate(self):
00547         return FunctionComparison(self.comparator, self.parts)
00548     positive = negate
00549 
00550 class Term(object):
00551     def dump(self, indent="  "):
00552         print "%s%s %s" % (indent, self._dump(), self.name)
00553         for arg in self.args:
00554             arg.dump(indent + "  ")
00555     def _dump(self):
00556         return self.__class__.__name__
00557     def __eq__(self, other):
00558         return (self.__class__ is other.__class__ and
00559                 self.args == other.args)
00560     def uniquify_variables(self, type_map, renamings={}):
00561         if not self.args:
00562             return self
00563         else:
00564             return self.__class__(self.name,[arg.uniquify_variables(type_map, renamings)
00565                                              for arg in self.args])
00566     def compile_objectfunctions_aux(self, used_variables, recurse_object_terms=True):
00567         return ([],[],self)
00568     def rename_variables(self, renamings):
00569         new_args = [renamings.get(arg, arg) for arg in self.args]
00570         return self.__class__(self.name, new_args)
00571     def free_variables(self):
00572         result = set()
00573         for arg in self.args:
00574             result |= arg.free_variables()
00575         return result
00576 
00577 class FunctionTerm(Term):
00578     def __init__(self, name, args=[]):
00579         self.name = name
00580         self.args = args
00581     def __str__(self):
00582         return "%s(%s)" % (self.name, ", ".join(map(str, self.args)))
00583     def compile_objectfunctions_aux(self, used_variables, recurse_object_terms=True):
00584     # could be done by postorder visit
00585         typed_vars = []
00586         conjunction_parts = []
00587         new_args = []
00588         for arg in self.args:
00589             if recurse_object_terms:
00590                 typed,parts,new_term = arg.compile_objectfunctions_aux(used_variables)
00591                 typed_vars += typed
00592                 conjunction_parts += parts
00593                 new_args.append(new_term)
00594     
00595         for counter in itertools.count(1):
00596             new_var_name = "?v" + str(counter)
00597             if new_var_name not in used_variables:
00598                 used_variables.append(new_var_name)
00599                 typed_vars.append(pddl_types.TypedObject(new_var_name, tasks.Task.FUNCTION_SYMBOLS[self.name]))
00600                 new_var = Variable(new_var_name)
00601                 break
00602 
00603         if recurse_object_terms:
00604             pred_name = function_predicate_name(self.name)
00605             new_args.append(new_var)
00606             atom = Atom(pred_name,new_args)
00607             conjunction_parts = [atom] + conjunction_parts
00608         else:
00609             conjunction_parts = [self] 
00610         return (typed_vars, conjunction_parts, new_var)
00611     
00612 class Variable(Term):
00613     args = []
00614     def __init__(self, name):
00615         self.name = name
00616         self.hash = hash((self.__class__,self.name))
00617     def __eq__(self, other):
00618         return (self.__class__ is other.__class__ and
00619                 self.name == other.name)
00620     def __cmp__(self,other):
00621         return cmp(self.name,other.name)
00622     def __hash__(self):
00623         return self.hash
00624     def __str__(self):
00625         return "<%s>" % self.name
00626     def uniquify_variables(self, type_map, renamings={}):
00627         return self.rename_variables(renamings)
00628     def rename_variables(self, renamings):
00629         return self.__class__(renamings.get(self.name,self.name))
00630     def free_variables(self):
00631         return set((self.name,))
00632 
00633 class ObjectTerm(Term):
00634     args = []
00635     def __init__(self, name):
00636         self.name = name
00637         self.hash = hash((self.__class__,self.name))
00638     def __eq__(self, other):
00639         return (self.__class__ is other.__class__ and
00640                 self.name == other.name)
00641     def __cmp__(self,other):
00642         return cmp(self.name,other.name)
00643     def __str__(self):
00644         return "<%s>" % self.name
00645     def __hash__(self):
00646         return self.hash
00647     def free_variables(self):
00648         return set()
00649     def rename_variables(self, renamings):
00650         return self
00651 
00652 def function_predicate_name(functionname):
00653     return "%s!val" % functionname
00654 


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