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
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
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)
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, ()))
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
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)
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"))
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)
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'))