def saturate(q: structures.ConjunctiveQuery, bad_fd: FrozenSet[structures.FunctionalDependency]) \ -> Tuple[structures.ConjunctiveQuery, List[structures.DatalogQuery]]: """ Saturates a non saturated query. :param q: A non saturated ConjunctiveQuery. :param bad_fd: Set of internal FD that makes q non saturated :return: The saturated query and a set of Datalog rules. """ n_index = 0 atoms = q.get_atoms() output = [] new_q = q for fd in bad_fd: content = list(fd.left) + [fd.right] n_atom = structures.Atom("N_" + str(n_index), content) fd_set = structures.FunctionalDependencySet() fd_set.add(fd) new_q = q.add_atom(n_atom, fd_set, [True] * len(fd.left) + [False], True) valuation = algorithms.generate_renaming(1, list(new_q.get_all_variables()))[0] n_rule = structures.DatalogQuery(n_atom) for atom in atoms: n_rule.add_atom(atom) bad_atom = structures.Atom("BadFact_" + str(n_index), content) n_rule.add_atom(bad_atom, True) bad_rule = structures.DatalogQuery(bad_atom) for atom in atoms: bad_rule.add_atom(atom) bad_rule.add_atom(algorithms.apply_renaming_to_atom(atom, valuation)) for var in fd.left: bad_rule.add_atom(structures.EqualityAtom(var, valuation[var])) bad_rule.add_atom(structures.EqualityAtom(fd.right, valuation[fd.right], True)) output += [n_rule, bad_rule] return new_q, output
def atom_attacks_variables(atom: Atom, var: AtomValue, q: ConjunctiveQuery) -> bool: """ Returns True if the given atom attacks the given Variable :param atom: An Atom :param var: A Variable :param q: A ConjunctiveQuery :return: True if atom attacks var, else returns False """ n = Atom("N", [var]) q_new = q.add_atom(n, FunctionalDependencySet(), [True], False) g = gen_attack_graph(q_new) return g.has_edge(atom, n)
def parse_query(string): pattern = re.compile("\[[A-Za-z_,0-9]*\]:[A-Za-z_,\(\)\[\]\*0-9]*$") if pattern.match(string): try: free_var_body, query_body = string.split(":") free_var_body = free_var_body[1:-1] free_vars = parse_atoms_values(free_var_body) q = ConjunctiveQuery() for atom, fd_set, is_key, is_consistent in parse_atoms(query_body): q = q.add_atom(atom, fd_set, is_key, is_consistent) for value in free_vars: if value.var: q = q.release_variable(value) return q except MalformedQuery: raise else: raise MalformedQuery(string, "ConjunctiveQuery")
def reduce_cycle(cycle: List[structures.Atom], q: structures.ConjunctiveQuery, rewriting_index: int) -> Tuple[structures.ConjunctiveQuery, List[structures.DatalogQuery]]: """ Reduces a cycle in the M-graph corresponding to an initial strong component in the attack graph of q. :param cycle: Cycle to be reduced :param q: A ConjunctiveQuery :param rewriting_index: Index used to enumerate the Datalog rules :return: A list of Datalog rules and a ConjunctiveQuery that corresponds to q\{atom} U {T} U {Nc} (Just as described in the report) """ rules = [] k = len(cycle) renamings = algorithms.generate_renaming(2 * k + 2, list(q.get_all_variables())) rules += [templates.EqQuery(atom, q) for atom in cycle] rules += [templates.NeqQuery(atom, q, renamings[0]) for atom in cycle] rules += garbage_set_rules(cycle, q, rewriting_index, renamings) rules += new_atoms_rules(cycle, q, rewriting_index, renamings) t, n_atoms = new_atoms(cycle, q, rewriting_index, renamings[0]) new_q = q.add_atom(*t) for n_atom in n_atoms: new_q = new_q.add_atom(*n_atom) for atom in cycle: new_q = new_q.remove_atom(atom) return new_q, rules
atom_s = Atom("S", [y, z]) # Initialize functional dependencies # First parameter : Left side of the FD (List of variables) # Second parameter : Right side of the FD (must be a single variable) fd1 = FunctionalDependencySet() fd1.add(FunctionalDependency([x], y)) fd2 = FunctionalDependencySet() fd2.add(FunctionalDependency([y], z)) # Initialize the conjunctive query q = ConjunctiveQuery() # Add atoms to q # First parameter : The atom to be added # Second parameter : The set of FD (must be a frozenset as in the example) # Third parameter : A List of booleans describing the "key positions" of the atom # Fourth Parameter : A boolean that must be True if the atom is consistent, False if not q = q.add_atom(atom_r, fd1, [True, True, False], False) q = q.add_atom(atom_s, fd2, [True, False], False) # Choose free variables (creates a new instance) q = q.release_variable(x) q = q.release_variable(y) # Launch rewriting program = rewrite(q) # You can print the Datalog program print(program)