def check_unify(self, atom_string1, atom_string2, msg, change_num, unifier1=None, unifier2=None, recursive_str=False): self.open(msg) (p1, unifier1, p2, unifier2, changes) = self.create_unify( atom_string1, atom_string2, msg, change_num, unifier1=unifier1, unifier2=unifier2, recursive_str=recursive_str) unify.undo_all(changes) self.assertTrue(p1.plug(unifier1) == p1) self.assertTrue(p2.plug(unifier2) == p2) self.close(msg)
def top_down_th(self, context, caller): """Top-down evaluation for the rules in self.rules.""" # LOG.debug("%s.top_down_th(%s)", self.name, context) lit = context.literals[context.literal_index] self.print_call(lit, context.binding, context.depth) for rule in self.head_index(lit.table, lit.plug(context.binding)): unifier = self.new_bi_unifier() # Prefer to bind vars in rule head undo = self.bi_unify(self.head(rule), unifier, lit, context.binding) if undo is None: # no unifier continue if len(self.body(rule)) == 0: if self.top_down_finish(context, caller): unify.undo_all(undo) if not caller.find_all: return True else: unify.undo_all(undo) else: new_context = self.TopDownContext(rule.body, 0, unifier, context, self, context.depth + 1) if self.top_down_eval(new_context, caller): unify.undo_all(undo) if not caller.find_all: return True else: unify.undo_all(undo) self.print_fail(lit, context.binding, context.depth) return False
def match(self, atom, unifier): # LOG.debug("DBTuple matching %s against atom %s in %s", # self, iterstr(atom.arguments), unifier) if len(self.tuple) != len(atom.arguments): return None changes = [] for i in xrange(0, len(atom.arguments)): val, binding = unifier.apply_full(atom.arguments[i]) # LOG.debug("val(%s)=%s at %s; comparing to object %s", # atom.arguments[i], val, binding, self.tuple[i]) if val.is_variable(): changes.append(binding.add( val, compile.Term.create_from_python(self.tuple[i]), None)) else: if val.name != self.tuple[i]: unify.undo_all(changes) return None return changes
def check_unify(self, atom_string1, atom_string2, msg, change_num, unifier1=None, unifier2=None, recursive_str=False): self.open(msg) (p1, unifier1, p2, unifier2, changes) = self.create_unify(atom_string1, atom_string2, msg, change_num, unifier1=unifier1, unifier2=unifier2, recursive_str=recursive_str) unify.undo_all(changes) self.assertTrue(p1.plug(unifier1) == p1) self.assertTrue(p2.plug(unifier2) == p2) self.close(msg)
def top_down_eval(self, context, caller): """Compute instances. Compute all instances of LITERALS (from LITERAL_INDEX and above) that are true according to the theory (after applying the unifier BINDING to LITERALS). Returns False or an answer. """ # no recursive rules, ever; this style of algorithm will not terminate lit = context.literals[context.literal_index] # LOG.debug("CALL: %s.top_down_eval(%s, %s)", # self.name, context, caller) # abduction if caller.save is not None and caller.save(lit, context.binding): self.print_call(lit, context.binding, context.depth) # save lit and binding--binding may not be fully flushed out # when we save (or ever for that matter) caller.support.append((lit, context.binding)) self.print_save(lit, context.binding, context.depth) success = self.top_down_finish(context, caller) caller.support.pop() # pop in either case if success: return True else: self.print_fail(lit, context.binding, context.depth) return False # regular processing if lit.is_negated(): # LOG.debug("%s is negated", lit) # recurse on the negation of the literal plugged = lit.plug(context.binding) assert plugged.is_ground(), ( "Negated literal not ground when evaluated: " + str(plugged)) self.print_call(lit, context.binding, context.depth) new_context = self.TopDownContext([lit.complement()], 0, context.binding, None, self, context.depth + 1) new_caller = self.TopDownCaller(caller.variables, caller.binding, caller.theory, find_all=False, save=None) # Make sure new_caller has find_all=False, so we stop as soon # as we can. # Ensure save=None so that abduction does not save anything. # Saving while performing NAF makes no sense. if self.top_down_includes(new_context, new_caller): self.print_fail(lit, context.binding, context.depth) return False else: # don't need bindings b/c LIT must be ground return self.top_down_finish(context, caller, redo=False) elif lit.tablename() == 'true': self.print_call(lit, context.binding, context.depth) return self.top_down_finish(context, caller, redo=False) elif lit.tablename() == 'false': self.print_fail(lit, context.binding, context.depth) return False elif builtin_registry.is_builtin(lit.table, len(lit.arguments)): self.print_call(lit, context.binding, context.depth) builtin = builtin_registry.builtin(lit.table) # copy arguments into variables # PLUGGED is an instance of compile.Literal plugged = lit.plug(context.binding) # print "plugged: " + str(plugged) # PLUGGED.arguments is a list of compile.Term # create args for function args = [] for i in xrange(0, builtin.num_inputs): assert plugged.arguments[i].is_object(), (( "Builtins must be evaluated only after their " "inputs are ground: {} with num-inputs {}".format( str(plugged), builtin.num_inputs))) args.append(plugged.arguments[i].name) # evaluate builtin: must return number, string, or iterable # of numbers/strings try: result = builtin.code(*args) except Exception as e: errmsg = "Error in builtin: " + str(e) self.print_note(lit, context.binding, context.depth, errmsg) self.print_fail(lit, context.binding, context.depth) return False # self.print_note(lit, context.binding, context.depth, # "Result: " + str(result)) success = None undo = [] if builtin.num_outputs > 0: # with return values, local success means we can bind # the results to the return value arguments if isinstance(result, (int, long, float, basestring)): result = [result] # Turn result into normal objects result = [compile.Term.create_from_python(x) for x in result] # adjust binding list unifier = self.new_bi_unifier() undo = unify.bi_unify_lists(result, unifier, lit.arguments[builtin.num_inputs:], context.binding) # print "unifier: " + str(undo) success = undo is not None else: # without return values, local success means # result was True according to Python success = bool(result) # print "success: " + str(success) if not success: self.print_fail(lit, context.binding, context.depth) unify.undo_all(undo) return False # otherwise, try to finish proof. If success, return True if self.top_down_finish(context, caller, redo=False): unify.undo_all(undo) return True # if fail, return False. else: unify.undo_all(undo) self.print_fail(lit, context.binding, context.depth) return False elif lit.theory is not None and lit.theory != self.name: return self.top_down_module(context, caller) else: return self.top_down_truth(context, caller)