예제 #1
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
예제 #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 _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)
예제 #4
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)
예제 #5
0
 def receive_data_update(self, msg):
     """Handler for when dataservice publishes a delta."""
     LOG.info("%s:: received update data msg for %s: %s",
              self.name, msg.header['dataindex'],
              ";".join(str(x) for x in msg.body.data))
     new_events = []
     for event in msg.body.data:
         assert compile.is_atom(event.formula), (
             "receive_data_update received non-atom: " +
             str(event.formula))
         # prefix tablename with data source
         actual_table = compile.Tablename.build_service_table(
             msg.replyTo, event.formula.table.table)
         values = [term.name for term in event.formula.arguments]
         newevent = compile.Event(compile.Fact(actual_table, values),
                                  insert=event.insert)
         new_events.append(newevent)
     (permitted, changes) = self.policy.update(new_events)
     if not permitted:
         raise exception.CongressException(
             "Update not permitted." + '\n'.join(str(x) for x in changes))
     else:
         tablename = msg.header['dataindex']
         service = msg.replyTo
         LOG.debug("update data msg for %s from %s caused %d "
                   "changes: %s", tablename, service, len(changes),
                   ";".join(str(x) for x in changes))
예제 #6
0
 def receive_data_update(self, msg):
     """Handler for when dataservice publishes a delta."""
     LOG.info("%s:: received update data msg for %s: %s", self.name,
              msg.header['dataindex'],
              ";".join(str(x) for x in msg.body.data))
     new_events = []
     for event in msg.body.data:
         assert compile.is_atom(
             event.formula), ("receive_data_update received non-atom: " +
                              str(event.formula))
         # prefix tablename with data source
         actual_table = compile.Tablename.build_service_table(
             msg.replyTo, event.formula.table.table)
         values = [term.name for term in event.formula.arguments]
         newevent = compile.Event(compile.Fact(actual_table, values),
                                  insert=event.insert)
         new_events.append(newevent)
     (permitted, changes) = self.policy.update(new_events)
     if not permitted:
         raise exception.CongressException("Update not permitted." +
                                           '\n'.join(
                                               str(x) for x in changes))
     else:
         tablename = msg.header['dataindex']
         service = msg.replyTo
         LOG.debug(
             "update data msg for %s from %s caused %d "
             "changes: %s", tablename, service, len(changes),
             ";".join(str(x) for x in changes))
예제 #7
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)
예제 #8
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))
예제 #9
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))
예제 #10
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]
예제 #11
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]
예제 #12
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
예제 #13
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]
예제 #14
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
예제 #15
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
예제 #16
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]
예제 #17
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
예제 #18
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]
예제 #19
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)
예제 #20
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)
예제 #21
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]
예제 #22
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), "Explain 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.table 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
예제 #23
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)
예제 #24
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"))
예제 #25
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"))
예제 #26
0
 def __contains__(self, formula):
     if compile.is_atom(formula):
         return self.rules.contains(formula.table, formula)
     else:
         return self.rules.contains(formula.head.table, formula)