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
def update_would_cause_errors(self, events): """Return a list of PolicyException. Return a list of PolicyException if we were to apply the insert/deletes of policy statements dictated by EVENTS to the current policy. """ self.log(None, "update_would_cause_errors %s", iterstr(events)) errors = [] for event in events: if not compile.is_datalog(event.formula): errors.append(PolicyException( "Non-formula found: {}".format( str(event.formula)))) else: if event.formula.is_atom(): errors.extend(compile.fact_errors( event.formula, self.theories, self.name)) else: errors.extend(compile.rule_errors( event.formula, self.theories, self.name)) # Would also check that rules are non-recursive, but that # is currently being handled by Runtime. The current implementation # disallows recursion in all theories. return errors
def update_would_cause_errors(self, events): """Return a list of PolicyException. 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_datalog(event.formula): errors.append( exception.PolicyException("Non-formula found: {}".format( str(event.formula)))) else: if event.formula.is_atom(): errors.extend( compile.fact_errors(event.formula, self.theories, self.name)) else: errors.extend( compile.rule_head_has_no_theory( event.formula, permit_head=lambda lit: lit.is_update())) # Should put this back in place, but there are some # exceptions that we don't handle right now. # Would like to mark some tables as only being defined # for certain bound/free arguments and take that into # account when doing error checking. # errors.extend(compile.rule_negation_safety(event.formula)) return errors
def update_would_cause_errors(self, events): """Return a list of PolicyException. 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", iterstr(events)) errors = [] for event in events: if not compile.is_datalog(event.formula): errors.append(PolicyException( "Non-formula found: {}".format( str(event.formula)))) else: if event.formula.is_atom(): errors.extend(compile.fact_errors( event.formula, self.theories, self.name)) else: errors.extend(compile.rule_head_has_no_theory( event.formula, permit_head=lambda lit: lit.is_update())) # Should put this back in place, but there are some # exceptions that we don't handle right now. # Would like to mark some tables as only being defined # for certain bound/free arguments and take that into # account when doing error checking. # errors.extend(compile.rule_negation_safety(event.formula)) return errors
def update_would_cause_errors(self, events): """Return a list of PolicyException. Return a list of PolicyException if we were to apply the insert/deletes of policy statements dictated by 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_datalog(event.formula): errors.append( exception.PolicyException("Non-formula found: {}".format( str(event.formula)))) else: if event.formula.is_atom(): errors.extend( compile.fact_errors(event.formula, self.theories, self.name)) else: errors.extend( compile.rule_errors(event.formula, self.theories, self.name)) # Would also check that rules are non-recursive, but that # is currently being handled by Runtime. The current implementation # disallows recursion in all theories. return errors
def update(self, events): """Apply inserts/deletes described by EVENTS and return changes. Does not check if EVENTS would cause errors. """ for event in events: assert compile.is_datalog(event.formula), "Non-formula not allowed: {}".format(str(event.formula)) self.enqueue_any(event) changes = self.process_queue() return changes
def update(self, events): """Apply inserts/deletes described by EVENTS and return changes. Does not check if EVENTS would cause errors. """ for event in events: assert compile.is_datalog( event.formula), ("Non-formula not allowed: {}".format( str(event.formula))) self.enqueue_any(event) changes = self.process_queue() return changes
def update_would_cause_errors(self, events): """Return a list of PolicyException. 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 = [] # compute new rule set for event in events: assert compile.is_datalog(event.formula), "update_would_cause_errors operates only on objects" self.log(None, "Updating %s", event.formula) if event.formula.is_atom(): errors.extend(compile.fact_errors(event.formula, self.theories, self.name)) else: errors.extend(compile.rule_errors(event.formula, self.theories, self.name)) return errors
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]
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]
def update_would_cause_errors(self, events): """Return a list of PolicyException. 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", iterstr(events)) errors = [] # compute new rule set for event in events: assert compile.is_datalog(event.formula), ( "update_would_cause_errors operates only on objects") self.log(None, "Updating %s", event.formula) if event.formula.is_atom(): errors.extend( compile.fact_errors(event.formula, self.theories, self.name)) else: errors.extend( compile.rule_errors(event.formula, self.theories, self.name)) return errors
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
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"))