Пример #1
0
    def _top_down_eval(
        self,
        context,  # type: topdown.TopDownTheory.TopDownContext
        caller  # type: topdown.TopDownTheory.TopDownCaller
    ):
        # type: (...) -> bool
        """Evaluation entry point for the non recursive engine

        We must compute unifiers and clear off as soon as we can
        giving back control to the theory context.
        Returns true if we only need one binding and it has been found,
        false otherwise.
        """
        raw_lit = context.literals[context.literal_index]
        query_lit = raw_lit.plug(context.binding)
        answers, bvars, translators = self.z3context.eval(self, query_lit)
        if isinstance(answers, bool):
            if answers:
                return (context.theory._top_down_finish(context, caller)
                        and not caller.find_all)
            return False
        for answer in answers:
            changes = []
            for (val, var, trans) in six.moves.zip(answer, bvars, translators):
                chg = context.binding.add(var, trans.to_os(val), None)
                changes.append(chg)
            context.theory._top_down_finish(context, caller)
            unify.undo_all(changes)
            if not caller.find_all:
                return True
        return False
Пример #2
0
    def _instances(self, rule, index, binding, results, possibilities):
        """Return all instances of the given RULE without evaluating builtins.

        Assumes self.head_index returns rules with empty bodies.
        """
        if index >= len(rule.body):
            results.add(rule.plug(binding))
            return
        lit = rule.body[index]
        self._print_call(lit, binding, 0)
        # if already ground or a builtin, go to the next literal
        if (lit.is_ground() or lit.is_builtin()):
            self._instances(rule, index + 1, binding, results, possibilities)
            return
        # Otherwise, find instances in this theory
        if lit.tablename() in possibilities:
            options = possibilities[lit.tablename()]
        else:
            options = self.head_index(lit.tablename(), lit.plug(binding))
        for data in options:
            self._print_note(lit, binding, 0, "Trying: %s" % repr(data))
            undo = unify.match_atoms(lit, binding, self.head(data))
            if undo is None:  # no unifier
                continue
            self._print_exit(lit, binding, 0)
            # recurse on the rest of the literals in the rule
            self._instances(rule, index + 1, binding, results, possibilities)
            if undo is not None:
                unify.undo_all(undo)
            self._print_redo(lit, binding, 0)
        self._print_fail(lit, binding, 0)
Пример #3
0
    def _instances(self, rule, index, binding, results, possibilities):
        """Return all instances of the given RULE without evaluating builtins.

        Assumes self.head_index returns rules with empty bodies.
        """
        if index >= len(rule.body):
            results.add(rule.plug(binding))
            return
        lit = rule.body[index]
        self._print_call(lit, binding, 0)
        # if already ground or a builtin, go to the next literal
        if (lit.is_ground() or lit.is_builtin()):
            self._instances(rule, index + 1, binding, results, possibilities)
            return
        # Otherwise, find instances in this theory
        if lit.tablename() in possibilities:
            options = possibilities[lit.tablename()]
        else:
            options = self.head_index(lit.tablename(), lit.plug(binding))
        for data in options:
            self._print_note(lit, binding, 0, "Trying: %s" % repr(data))
            undo = unify.match_atoms(lit, binding, self.head(data))
            if undo is None:  # no unifier
                continue
            self._print_exit(lit, binding, 0)
            # recurse on the rest of the literals in the rule
            self._instances(rule, index + 1, binding, results, possibilities)
            if undo is not None:
                unify.undo_all(undo)
            self._print_redo(lit, binding, 0)
        self._print_fail(lit, binding, 0)
Пример #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)
Пример #5
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.assertEqual(p1, p1.plug(unifier1))
     self.assertEqual(p2, p2.plug(unifier2))
     self.close(msg)
Пример #6
0
 def _top_down_th(self, context, caller):
     """Top-down evaluation for the rules in self."""
     # 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.table,
                                 lit.plug(context.binding)):
         unifier = self.new_bi_unifier()
         self._print_note(lit, context.binding, context.depth,
                          "Trying %s" % rule)
         # Prefer to bind vars in rule head
         undo = self.bi_unify(self.head(rule), unifier, lit,
                              context.binding, self.name)
         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
Пример #7
0
    def _top_down_th(self, context, caller):
        """Top-down evaluation for the rules in self."""
        # 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)):
            # LOG.debug("%s._top_down_th rule: %s", self.name, rule)
            unifier = self.new_bi_unifier()
            self._print_note(lit, context.binding, context.depth,
                             "Trying %s" % rule)
            # Prefer to bind vars in rule head
            undo = self.bi_unify(self.head(rule), unifier, lit,
                                 context.binding, self.name)
            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
Пример #8
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 range(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
Пример #9
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 range(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
Пример #10
0
    def _top_down_builtin(self, context, caller):
        """Evaluate a table with a builtin semantics.

        Returns True if done searching and False otherwise.
        """
        lit = context.literals[context.literal_index]
        self._print_call(lit, context.binding, context.depth)
        builtin = congressbuiltin.builtin_registry.builtin(lit.table)
        # copy arguments into variables
        # PLUGGED is an instance of compile.Literal
        plugged = lit.plug(context.binding)
        # PLUGGED.arguments is a list of compile.Term
        # create args for function
        args = []
        for i in range(0, builtin.num_inputs):
            # save builtins with unbound vars during evaluation
            if not plugged.arguments[i].is_object() and caller.save:
                # 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
            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,
                           (six.integer_types, float, six.string_types))):
                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)
            success = undo is not None
        else:
            # without return values, local success means
            #   result was True according to Python
            success = bool(result)

        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
Пример #11
0
    def _top_down_builtin(self, context, caller):
        """Evaluate a table with a builtin semantics.

        Returns True if done searching and False otherwise.
        """
        lit = context.literals[context.literal_index]
        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