예제 #1
0
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
예제 #2
0
 def make_safe(self, q: ConjunctiveQuery):
     """
     Adds atoms to make safe the rule
     :param q:       A ConjunctiveQuery
     """
     i = 0
     atoms = list(self.atoms)
     for var in self.head.all_variables():
         k = 0
         while k < len(atoms) and (not isinstance(atoms[k], Atom)
                                   or self.neg[atoms[k]]
                                   or var not in atoms[k].content):
             k += 1
         if k == len(atoms):
             for atom in q.get_atoms():
                 content = atom.content
                 if var in content:
                     new_vars = generate_new_variables(
                         "F",
                         len(content) - 1, i)
                     new_content = []
                     j = 0
                     for value in content:
                         if value != var:
                             new_content.append(new_vars[j])
                             j += 1
                         else:
                             new_content.append(var)
                     new_atom = Atom(atom.name, new_content)
                     new_atom.released = set(new_content).intersection(
                         self.head.content)
                     self.add_atom(new_atom)
                     break
         i += 1
예제 #3
0
def fd_is_internal(fd: FunctionalDependency, q: ConjunctiveQuery) -> bool:
    """
    Checks if a FD is internal
    :param fd:      A FD
    :param q:       A ConjunctiveQuery
    :return:        True if fd is internal, otherwise returns False
    """
    in_atom = False
    atoms = q.get_atoms()
    for atom in atoms:
        if fd.left.issubset(set(atom.variables())):
            in_atom = True
    if not in_atom:
        return False
    sps = sequential_proofs(fd, q)
    variables = fd.left.union({fd.right})
    for sp in sps:
        valid = True
        for atom in sp.steps:
            for var in variables:
                if atom_attacks_variables(atom, var, q):
                    valid = False
        if valid:
            return True
    return False
예제 #4
0
def sequential_proof_rec(fd: FunctionalDependency, acc: Set[AtomValue],
                         q: ConjunctiveQuery, current_sp: List[Atom],
                         current_res: List[SequentialProof]) -> None:
    """
    Recursive function used to compute sequential proofs for a given FD X -> z
    :param fd:              A FD of the form X -> z
    :param acc:             A set of Variables containing the variables implied by X with the current sequential proof
    :param q:               A ConjunctiveQuery
    :param current_sp:      Current sequential proof
    :param current_res:     List that will contain all the sequential proofs for X -> z
    """
    if fd.right in acc:
        sequential_proof = SequentialProof(fd, current_sp)
        to_remove = []
        for sp in current_res:
            if sequential_proof.is_subset_of(sp):
                to_remove.append(sp)
            elif sp.is_subset_of(sequential_proof):
                return None
        for sp in to_remove:
            current_res.remove(sp)
        current_res.append(sequential_proof)
    else:
        for atom in [atom for atom in q.get_atoms() if atom not in current_sp]:
            if set(q.get_key_vars(atom)).issubset(acc):
                sequential_proof_rec(fd, acc.union(set(atom.variables())), q,
                                     current_sp + [atom], current_res)
예제 #5
0
def gen_attack_graph(q: ConjunctiveQuery) -> nx.DiGraph:
    """
    Computes the attack graph of a given ConjunctiveQuery q.
    :param q:   A ConjunctiveQuery
    :return:    Generated Attack Graph
    """
    g = nx.DiGraph()
    atoms = q.get_atoms()
    for atom in atoms:
        g.add_node(atom)
    for atom in atoms:
        plus = atom_plus(atom, q)
        reachable = {atom}
        candidates = atoms - {atom}
        size = -1
        while len(reachable) != size:
            size = len(reachable)
            new_reachable = set()
            for atom1 in reachable:
                for atom2 in candidates:
                    intersection = set(atom1.variables()).intersection(
                        set(atom2.variables()))
                    without_plus = intersection - plus
                    if without_plus:
                        new_reachable.add(atom2)
            reachable = reachable.union(new_reachable)
            candidates = candidates - new_reachable
        for other in reachable - {atom}:
            g.add_edge(atom, other)
    return g
예제 #6
0
def is_self_join_free(q: ConjunctiveQuery) -> bool:
    """
    Returns True is given bcq q is a sjfbcq
    :param q:   A conjunctive query
    :return:    True if q is a sjfbcq, otherwise returns False
    """
    atoms = list(q.get_atoms())
    for i in range(len(atoms)):
        atom = atoms[i]
        for other in atoms[:i] + atoms[i + 1:]:
            if atom.name == other.name:
                return False
    return True
예제 #7
0
def gen_m_graph(q: ConjunctiveQuery) -> nx.DiGraph:
    """
    Computes the M-graph of a given ConjunctiveQuery q.
    :param q:   A ConjunctiveQuery
    :return:    Generated M-Graph
    """
    atoms = q.get_atoms()
    g = nx.DiGraph()
    for atom1 in atoms:
        g.add_node(atom1)
        closure = transitive_closure(set(atom1.variables()),
                                     q.get_consistent_fd())
        for atom2 in [atom for atom in atoms if atom != atom1]:
            if set(q.get_key_vars(atom2)).issubset(closure):
                g.add_edge(atom1, atom2)
    return g