예제 #1
0
    def eliminate_self_joins(cls, formulas):
        """Remove self joins.

        Return new list of formulas that is equivalent to
        the list of formulas FORMULAS except that there
        are no self-joins.
        """
        def new_table_name(name, arity, index):
            return "___{}_{}_{}".format(name, arity, index)

        def n_variables(n):
            vars = []
            for i in xrange(0, n):
                vars.append("x" + str(i))
            return vars

        # dict from (table name, arity) tuple to
        #      max num of occurrences of self-joins in any rule
        global_self_joins = {}
        # remove self-joins from rules
        results = []
        for rule in formulas:
            if rule.is_atom():
                results.append(rule)
                continue
            LOG.debug("eliminating self joins from %s", rule)
            occurrences = {}  # for just this rule
            for atom in rule.body:
                table = atom.tablename()
                arity = len(atom.arguments)
                tablearity = (table, arity)
                if tablearity not in occurrences:
                    occurrences[tablearity] = 1
                else:
                    # change name of atom
                    atom.table = new_table_name(table, arity,
                                                occurrences[tablearity])
                    # update our counters
                    occurrences[tablearity] += 1
                    if tablearity not in global_self_joins:
                        global_self_joins[tablearity] = 1
                    else:
                        global_self_joins[tablearity] = (max(
                            occurrences[tablearity] - 1,
                            global_self_joins[tablearity]))
            results.append(rule)
            LOG.debug("final rule: %s", rule)
        # add definitions for new tables
        for tablearity in global_self_joins:
            table = tablearity[0]
            arity = tablearity[1]
            for i in xrange(1, global_self_joins[tablearity] + 1):
                newtable = new_table_name(table, arity, i)
                args = [compile.Variable(var) for var in n_variables(arity)]
                head = compile.Literal(newtable, args)
                body = [compile.Literal(table, args)]
                results.append(compile.Rule(head, body))
                LOG.debug("Adding rule %s", results[-1])
        return results
예제 #2
0
 def consequences(self, filter=None, table_theories=None):
     """Return all the true instances of any table in this theory."""
     # find all table, theory pairs defined in this theory
     if table_theories is None:
         table_theories = set()
         for key in self.rules.keys():
             table_theories |= set([(rule.head.table.table,
                                     rule.head.table.service)
                                    for rule in self.rules.get_rules(key)])
     results = set()
     # create queries: need table names and arities
     # TODO(thinrichs): arity computation will need to ignore
     #   modals once we start using insert[p(x)] instead of p+(x)
     for (table, theory) in table_theories:
         if filter is None or filter(table):
             tablename = compile.Tablename(table, theory)
             arity = self.arity(tablename)
             vs = []
             for i in range(0, arity):
                 vs.append("x" + str(i))
             vs = [compile.Variable(var) for var in vs]
             tablename = table
             if theory:
                 tablename = theory + ":" + tablename
             query = compile.Literal(tablename, vs)
             results |= set(self.select(query))
     return results
예제 #3
0
def retrieve(theory, tablename):
    # type: (topdown.TopDownTheory, str) -> List[ast.Literal]
    """Retrieves all the values of an external table.

    Performs a select on the theory with a query computed from the schema
    of the table.
    """
    arity = theory.schema.arity(tablename)
    table = ast.Tablename(tablename, theory.name)
    args = [ast.Variable('X' + str(i)) for i in range(arity)]
    query = ast.Literal(table, args)
    return theory.select(query)
예제 #4
0
    def get_rules(self, key, match_literal=None):
        facts = []

        if (match_literal and not match_literal.is_negated()
                and key in self.facts):
            # If the caller supplies a literal to match against, then use an
            # index to find the matching rules.
            bound_arguments = tuple([
                i for i, arg in enumerate(match_literal.arguments)
                if not arg.is_variable()
            ])
            if (bound_arguments
                    and not self.facts[key].has_index(bound_arguments)):
                # The index does not exist, so create it.
                self.facts[key].create_index(bound_arguments)

            partial_fact = tuple([
                (i, arg.name) for i, arg in enumerate(match_literal.arguments)
                if not arg.is_variable()
            ])
            facts = list(self.facts[key].find(partial_fact))
        else:
            # There is no usable match_literal, so get all facts for the
            # table.
            facts = list(self.facts.get(key, ()))

        # Convert native tuples to Rule objects.

        # TODO(alex): This is inefficient because it creates Literal and Rule
        # objects.  It would be more efficient to change the TopDownTheory and
        # unifier to handle Facts natively.
        fact_rules = []
        for fact in facts:
            # Setting use_modules=False so we don't split up tablenames.
            #   This allows us to choose at compile-time whether to split
            #   the tablename up.
            literal = compile.Literal(
                key, [compile.Term.create_from_python(x) for x in fact],
                use_modules=False)
            fact_rules.append(compile.Rule(literal, ()))

        return fact_rules + list(self.rules.get(key, ()))
예제 #5
0
 def consequences(self, filter=None, table_theories=None):
     """Return all the true instances of any table in this theory."""
     # find all table, theory pairs defined in this theory
     if table_theories is None:
         table_theories = set()
         for key in self.rules.keys():
             table_theories |= set([(rule.head.table, rule.head.theory)
                                    for rule in self.rules.get_rules(key)])
     results = set()
     # create queries: need table names and arities
     for (table, theory) in table_theories:
         if filter is None or filter(table):
             arity = self.get_arity(table, theory=theory, local_only=True)
             vs = []
             for i in xrange(0, arity):
                 vs.append("x" + str(i))
             vs = [compile.Variable(var) for var in vs]
             tablename = table
             if theory:
                 tablename = theory + ":" + tablename
             query = compile.Literal(tablename, vs)
             results |= set(self.select(query))
     return results
예제 #6
0
 def plug(row):
     """Plugs in found values in query litteral"""
     args = [(congress_constant(trans[arg].to_os(row[arg]))
              if isinstance(arg, int) else arg) for arg in pattern]
     return ast.Literal(query.table, args)
예제 #7
0
    def test_type_checkers(self):
        """Test the type checkers, e.g. is_atom, is_rule."""
        atom = compile.Literal("p", [])
        atom2 = compile.Literal("q", [])
        atom3 = compile.Literal("r", [])
        lit = compile.Literal("r", [], negated=True)
        regular_rule = compile.Rule(atom, [atom2, atom3])
        regular_rule2 = compile.Rule(atom, [lit, atom2])
        multi_rule = compile.Rule([atom, atom2], [atom3])
        fake_rule = compile.Rule([atom, 1], [atom2])
        fake_rule2 = compile.Rule(atom, [atom2, 1])

        # is_atom
        self.assertTrue(compile.is_atom(atom))
        self.assertTrue(compile.is_atom(atom2))
        self.assertTrue(compile.is_atom(atom3))
        self.assertFalse(compile.is_atom(lit))
        self.assertFalse(compile.is_atom(regular_rule))
        self.assertFalse(compile.is_atom(regular_rule2))
        self.assertFalse(compile.is_atom(multi_rule))
        self.assertFalse(compile.is_atom(fake_rule))
        self.assertFalse(compile.is_atom(fake_rule2))
        self.assertFalse(compile.is_atom("a string"))

        # is_literal
        self.assertTrue(compile.is_literal(atom))
        self.assertTrue(compile.is_literal(atom2))
        self.assertTrue(compile.is_literal(atom3))
        self.assertTrue(compile.is_literal(lit))
        self.assertFalse(compile.is_literal(regular_rule))
        self.assertFalse(compile.is_literal(regular_rule2))
        self.assertFalse(compile.is_literal(multi_rule))
        self.assertFalse(compile.is_literal(fake_rule))
        self.assertFalse(compile.is_literal(fake_rule2))
        self.assertFalse(compile.is_literal("a string"))

        # is_regular_rule
        self.assertFalse(compile.is_regular_rule(atom))
        self.assertFalse(compile.is_regular_rule(atom2))
        self.assertFalse(compile.is_regular_rule(atom3))
        self.assertFalse(compile.is_regular_rule(lit))
        self.assertTrue(compile.is_regular_rule(regular_rule))
        self.assertTrue(compile.is_regular_rule(regular_rule2))
        self.assertFalse(compile.is_regular_rule(multi_rule))
        self.assertFalse(compile.is_regular_rule(fake_rule))
        self.assertFalse(compile.is_regular_rule(fake_rule2))
        self.assertFalse(compile.is_regular_rule("a string"))

        # is_multi_rule
        self.assertFalse(compile.is_multi_rule(atom))
        self.assertFalse(compile.is_multi_rule(atom2))
        self.assertFalse(compile.is_multi_rule(atom3))
        self.assertFalse(compile.is_multi_rule(lit))
        self.assertFalse(compile.is_multi_rule(regular_rule))
        self.assertFalse(compile.is_multi_rule(regular_rule2))
        self.assertTrue(compile.is_multi_rule(multi_rule))
        self.assertFalse(compile.is_multi_rule(fake_rule))
        self.assertFalse(compile.is_multi_rule(fake_rule2))
        self.assertFalse(compile.is_multi_rule("a string"))

        # is_rule
        self.assertFalse(compile.is_rule(atom))
        self.assertFalse(compile.is_rule(atom2))
        self.assertFalse(compile.is_rule(atom3))
        self.assertFalse(compile.is_rule(lit))
        self.assertTrue(compile.is_rule(regular_rule))
        self.assertTrue(compile.is_rule(regular_rule2))
        self.assertTrue(compile.is_rule(multi_rule))
        self.assertFalse(compile.is_rule(fake_rule))
        self.assertFalse(compile.is_rule(fake_rule2))
        self.assertFalse(compile.is_rule("a string"))

        # is_datalog
        self.assertTrue(compile.is_datalog(atom))
        self.assertTrue(compile.is_datalog(atom2))
        self.assertTrue(compile.is_datalog(atom3))
        self.assertFalse(compile.is_datalog(lit))
        self.assertTrue(compile.is_datalog(regular_rule))
        self.assertTrue(compile.is_datalog(regular_rule2))
        self.assertFalse(compile.is_datalog(multi_rule))
        self.assertFalse(compile.is_datalog(fake_rule))
        self.assertFalse(compile.is_datalog(fake_rule2))
        self.assertFalse(compile.is_datalog("a string"))

        # is_extended_datalog
        self.assertTrue(compile.is_extended_datalog(atom))
        self.assertTrue(compile.is_extended_datalog(atom2))
        self.assertTrue(compile.is_extended_datalog(atom3))
        self.assertFalse(compile.is_extended_datalog(lit))
        self.assertTrue(compile.is_extended_datalog(regular_rule))
        self.assertTrue(compile.is_extended_datalog(regular_rule2))
        self.assertTrue(compile.is_extended_datalog(multi_rule))
        self.assertFalse(compile.is_extended_datalog(fake_rule))
        self.assertFalse(compile.is_extended_datalog(fake_rule2))
        self.assertFalse(compile.is_extended_datalog("a string"))
예제 #8
0
 def test_select(self):
     context = z3theory.Z3Context.get_context()
     context.select = mock.MagicMock()
     lit = ast.Literal(ast.Tablename('t'), [])
     self.theory.select(lit)
     context.select.assert_called_once_with(self.theory, lit, True)
예제 #9
0
 def test_arity(self):
     lit = ast.Literal(
         ast.Tablename('t'),
         [ast.Variable('x'), ast.Variable('x')])
     self.theory.insert(lit)
     self.assertEqual(2, self.theory.arity('t'))