Exemplo n.º 1
0
 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)
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
 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
Exemplo n.º 4
0
 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)
Exemplo n.º 5
0
    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)