Пример #1
0
 def _delete_actual(self, rule):
     """Delete RULE and return True if there was a change."""
     self.dirty = True
     if compile.is_atom(rule):
         rule = compile.Rule(rule, [], rule.location)
     self.log(rule.head.table.table, "Delete: %s", rule)
     return self.rules.discard_rule(rule.head.table.table, rule)
Пример #2
0
 def _insert_actual(self, rule):
     """Insert RULE and return True if there was a change."""
     self.dirty = True
     if compile.is_atom(rule):
         rule = compile.Rule(rule, [], rule.location)
     self.log(rule.head.table.table, "Insert: %s", repr(rule))
     return self.rules.add_rule(rule.head.table.table, rule)
Пример #3
0
 def __contains__(self, formula):
     if not compile.is_atom(formula):
         return False
     if formula.table.table not in self.data:
         return False
     event_data = self.data[formula.table.table]
     raw_tuple = tuple(formula.argument_names())
     return any((dbtuple.tuple == raw_tuple for dbtuple in event_data))
Пример #4
0
 def explain(self, query, tablenames, find_all):
     """Returns a list of proofs if QUERY is true or None if else."""
     assert compile.is_atom(query), "Explain requires an atom"
     # ignoring TABLENAMES and FIND_ALL
     #    except that we return the proper type.
     proof = self.explain_aux(query, 0)
     if proof is None:
         return None
     else:
         return [proof]
Пример #5
0
    def delete_actual(self, atom, proofs=None):
        """Workhorse for deleting ATOM from the DB.

        Along with the proofs that are no longer true.
        """
        assert compile.is_atom(atom), "Delete requires Atom"
        self.log(atom.table.table, "Delete: %s", atom)
        table, dbtuple = self.atom_to_internal(atom, proofs)
        if table not in self.data:
            return
        for i in range(0, len(self.data[table])):
            existingtuple = self.data[table][i]
            if existingtuple.tuple == dbtuple.tuple:
                existingtuple.proofs -= dbtuple.proofs
                if len(existingtuple.proofs) == 0:
                    del self.data[table][i]
                return
Пример #6
0
    def modify(self, event):
        """Insert/Delete atom.

        Inserts/deletes ATOM and returns a list of changes that
        were caused. That list contains either 0 or 1 Event.
        """
        assert compile.is_atom(event.formula), "Modify requires Atom"
        atom = event.formula
        self.log(atom.table.table, "Modify: %s", atom)
        if self.is_noop(event):
            self.log(atom.table.table, "Event %s is a noop", event)
            return []
        if event.insert:
            self.insert_actual(atom, proofs=event.proofs)
        else:
            self.delete_actual(atom, proofs=event.proofs)
        return [event]
Пример #7
0
    def update_would_cause_errors(self, events):
        """Return a list of Policyxception.

        Return a list of PolicyException if we were
        to apply the events EVENTS to the current policy.
        """
        self.log(None, "update_would_cause_errors %s", utility.iterstr(events))
        errors = []
        for event in events:
            if not compile.is_atom(event.formula):
                errors.append(exception.PolicyException(
                    "Non-atomic formula is not permitted: {}".format(
                        str(event.formula))))
            else:
                errors.extend(compile.fact_errors(
                    event.formula, self.theories, self.name))
        return errors
Пример #8
0
    def select(self, query, find_all=True):
        """Return list of instances of QUERY that are true.

        If FIND_ALL is False, the return list has at most 1 element.
        """
        assert compile.is_datalog(query), "Query must be atom/rule"
        if compile.is_atom(query):
            literals = [query]
        else:
            literals = query.body
        # Because our output is instances of QUERY, need all the variables
        #   in QUERY.
        bindings = self.top_down_evaluation(query.variables(),
                                            literals,
                                            find_all=find_all)
        # LOG.debug("Top_down_evaluation returned: %s", bindings)
        if len(bindings) > 0:
            self.log(
                query.tablename(), "Found answer %s",
                "[" + ",".join([str(query.plug(x)) for x in bindings]) + "]")
        return [query.plug(x) for x in bindings]
Пример #9
0
    def insert_actual(self, atom, proofs=None):
        """Workhorse for inserting ATOM into the DB.

        Along with proofs explaining how ATOM was computed from other tables.
        """
        assert compile.is_atom(atom), "Insert requires Atom"
        table, dbtuple = self.atom_to_internal(atom, proofs)
        self.log(table, "Insert: %s", atom)
        if table not in self.data:
            self.data[table] = [dbtuple]
            self.log(atom.table.table, "First tuple in table %s", table)
            return
        else:
            for existingtuple in self.data[table]:
                assert existingtuple.proofs is not None
                if existingtuple.tuple == dbtuple.tuple:
                    assert existingtuple.proofs is not None
                    existingtuple.proofs |= dbtuple.proofs
                    assert existingtuple.proofs is not None
                    return
            self.data[table].append(dbtuple)
Пример #10
0
    def abduce(self, query, tablenames, find_all=True):
        """Compute additional literals.

        Computes additional literals that if true would make
        (some instance of) QUERY true.  Returns a list of rules
        where the head represents an instance of the QUERY and
        the body is the collection of literals that must be true
        in order to make that instance true.  If QUERY is a rule,
        each result is an instance of the head of that rule, and
        the computed literals if true make the body of that rule
        (and hence the head) true.  If FIND_ALL is true, the
        return list has at most one element.
        Limitation: every negative literal relevant to a proof of
        QUERY is unconditionally true, i.e. no literals are saved
        when proving a negative literal is true.
        """
        assert compile.is_datalog(query), "abduce requires a formula"
        if compile.is_atom(query):
            literals = [query]
            output = query
        else:
            literals = query.body
            output = query.head
        # We need all the variables we will be using in the output, which
        #   here is just the head of QUERY (or QUERY itself if it is an atom)
        abductions = self.top_down_abduction(
            output.variables(),
            literals,
            find_all=find_all,
            save=lambda lit, binding: lit.tablename() in tablenames)
        results = [
            compile.Rule(output.plug(abd.binding), abd.support)
            for abd in abductions
        ]
        self.log(query.tablename(), "abduction result:")
        self.log(query.tablename(), "\n".join([str(x) for x in results]))
        return results
Пример #11
0
 def __contains__(self, formula):
     if compile.is_atom(formula):
         return self.rules.contains(formula.table.table, formula)
     else:
         return self.rules.contains(formula.head.table.table, formula)