def valid_clause(self, clause: Clause) -> ValidClause: bound_vars: Set[Variable] = set() possibly_unbound_vars: Set[Variable] = set() subst: TermUnifier = UnionFindBasedUnifier() def add_set(a_x, a_set: Set): a_set.add(a_x) return a_set tv: TermVisitor = (TermVisitorBuilder().onVariable(add_set).or_( lambda a_x, a_set: a_set)) TermHelpers.fold( HeadHelpers.force_positive_atom(clause.getHead()).getArgs(), tv, possibly_unbound_vars, ) has_positive_atom_box: Box[bool] = Box(False) cv: PremiseVisitor = LocalCrashPremiseVisitor( tv, subst, has_positive_atom_box, bound_vars, possibly_unbound_vars, self.allowBinaryUnification, self.allowBinaryDisunification, self.allowNegatedBodyAtom, ) p: Premise for p in clause.getBody(): e: DatalogValidationException = p.accept_premise_visitor(cv, None) if e: raise e x: Variable for x in possibly_unbound_vars: if x not in bound_vars and not isinstance(subst.get(x), Constant): raise DatalogValidationException( f"Every variable in a rule must be bound, but {x} is not bound in " f"the rule {clause}. A variable X is bound if 1) it appears in a " f"positive(non-negated) body atom or 2) it is explicitly unified " f"with a constant(e.g. X=a) or with a variable that is bound " f"(e.g. X=Y where Y is bound). ") new_body_list: List[Premise] = list(copy.deepcopy(clause.getBody())) if not has_positive_atom_box.value and new_body_list: new_body_list.insert(0, TrueAtom.getTrueAtom()) new_body = tuple(new_body_list) return ValidClause(clause.getHead(), new_body)
def test_error(): x = Variable.create("X") y = Variable.create("Y") z = Variable.create("Z") w = Variable.create("W") p = PredicateSym.create("p", 2) q = PredicateSym.create("q", 2) qXY = PositiveAtom.create(q, [x, y]) pXW = PositiveAtom.create(p, [x, w]) qZW = PositiveAtom.create(q, [z, w]) body = [qXY, qZW] cl = Clause(pXW, tuple(body)) prog: UnstratifiedProgram = DatalogValidator( ).withBinaryUnificationInRuleBody().withBinaryDisunificationInRuleBody( ).validate({cl}) annotator = SemiNaiveClauseAnnotator(list(prog.getIdbPredicateSyms())) it = iter(prog.getRules()) rule = next(it) annotated = annotator.annotate_single(rule) assert str(annotated) == "[p(X, W) :- q(X, Y)<EDB>, q(Z, W)<EDB>.]"
def verify(body: List[Premise]): cl = Clause(pXW, tuple(body)) prog: UnstratifiedProgram = DatalogValidator( ).withBinaryUnificationInRuleBody().withBinaryDisunificationInRuleBody( ).validate({cl}) annotator = SemiNaiveClauseAnnotator(list(prog.getIdbPredicateSyms())) it = iter(prog.getRules()) rule = next(it) annotated = annotator.annotate_single(rule) it_annotated = iter(annotated) ordered = next(it_annotated) def facts_func_result(fact, s, result): r = fact.applySubst(s) result.append(r) from functools import partial result = [] facts_func = partial(facts_func_result, result=result) eval = ClauseEvaluator(ordered, facts_func, lambda atom, s: facts) eval.evaluate(qab) return result
def test_evaluation_error(): x = Variable.create("X") y = Variable.create("Y") z = Variable.create("Z") w = Variable.create("W") p = PredicateSym.create("p", 2) q = PredicateSym.create("q", 2) qXY = PositiveAtom.create(q, [x, y]) pXW = PositiveAtom.create(p, [x, w]) qZW = PositiveAtom.create(q, [z, w]) body = [qXY, qZW] cl = Clause(pXW, tuple(body)) prog: UnstratifiedProgram = DatalogValidator().withBinaryUnificationInRuleBody().withBinaryDisunificationInRuleBody().validate( {cl}) annotator = SemiNaiveClauseAnnotator(list(prog.getIdbPredicateSyms())) it = iter(prog.getRules()) rule = next(it) annotated = annotator.annotate_single(rule) it_annotated = iter(annotated) ordered = next(it_annotated) subst = ClauseSubstitution.make_with_seminaive_clause(ordered) assert subst.index == {z: 2, w: 3, x: 0, y: 1} assert str(subst) == "{ ^ <0> X -> None, Y -> None, <1> Z -> None, W -> None }"
def get_head_predicate(clause: Clause): # OLD AbcDatalog code: Start # get_head_pred: HeadVisitor = LocalHeadVisitor() # return clause.getHead().accept_head_visitor(get_head_pred, None) # OLD AbcDatalog code: End return clause.getHead().getPred()
def test_create_substitution_1(): p0 = PredicateSym.create("p", 0) q2 = PredicateSym.create("q", 2) r2 = PredicateSym.create("r", 2) s3 = PredicateSym.create("s", 3) x: Variable y: Variable z: Variable x = Variable.create("X") y = Variable.create("Y") z = Variable.create("Z") a: Constant b: Constant a = Constant.create("a") b = Constant.create("b") idbPreds: List = [q2, s3] pAtom = PositiveAtom.create(p0, []) qAtom: Premise = PositiveAtom.create(q2, [x, y]) rAtom: Premise = PositiveAtom.create(r2, [x, x]) sAtom: Premise = PositiveAtom.create(s3, [a, x, z]) u1: Premise = BinaryUnifier(x, b) u2: Premise = BinaryUnifier(z, z) validator: DatalogValidator = DatalogValidator().withBinaryUnificationInRuleBody() annotator: SemiNaiveClauseAnnotator = SemiNaiveClauseAnnotator(idbPreds) expected_value = "{ }" input_clause = {Clause(pAtom, tuple([pAtom]))} #ignore assert_annotation(validator, annotator, input_clause, expected_value) assert_annotation(validator, annotator, {Clause(pAtom, tuple([qAtom]))}, "{ ^ <0> X -> None, Y -> None }") l: List[Premise] = [qAtom, rAtom] assert_annotation(validator, annotator, {Clause(pAtom, tuple(l))}, "{ ^ <0> X -> None, Y -> None }") l[0], l[1] = l[1], l[0] assert_annotation(validator, annotator, [Clause(pAtom, tuple(l))], "{ ^ <0> X -> None, Y -> None }") l = [qAtom, sAtom] subst = clause_substitution(annotator, [Clause(pAtom, tuple(l))], validator) assert str(subst) == "{ ^ <0> X -> None, Y -> None, <1> Z -> None }" subst.add(x, a) assert str(subst) == "{ <0> X -> a, ^ Y -> None, <1> Z -> None }" with pytest.raises(AssertionError): #Correctly threw error when adding in wrong order" subst.add(z, a) subst.add(y, b) assert str(subst) == "{ <0> X -> a, Y -> b, ^ <1> Z -> None }" with pytest.raises(AssertionError): # Correctly threw error when adding in wrong order subst.add(x, a) subst.add(z, a) assert str(subst) == "{ <0> X -> a, Y -> b, <1> Z -> a }" with pytest.raises(AssertionError): # Correctly threw error when adding a variable not in substitution subst.add(Variable.create("w"), b) subst.resetState(0) assert not subst.get(x) subst.add(x, a) assert subst.get(x) == a subst.add(y, b) assert subst.get(x) == a assert subst.get(y) == b subst.add(z, a) assert subst.get(x) == a assert subst.get(y) == b assert subst.get(z) == a subst.resetState(1) assert subst.get(x) == a assert subst.get(y) == b assert not subst.get(z)
def sort(original: Clause, firstConjunctPos: int) -> SemiNaiveClause: # List<Premise> body = new ArrayList<>(original.getBody()); body: List[Premise] = list(original.getBody()) # if (body.isEmpty()) { # return new SemiNaiveClause(original.getHead(), body); # } if not body: return SemiNaiveClause(original.getHead(), body) # PremiseVisitor<Set<Variable>, Void> boundVarUpdater = new DefaultConjunctVisitor<Set<Variable>, Void>() { boundVarUpdater: PremiseVisitor[Set[Variable]] = LocalDefaultConjunctVisitor() # @Override # public Void visit(AnnotatedAtom atom, Set<Variable> boundVars) { # for (Term t : atom.getArgs()) { # if (t instanceof Variable) { # boundVars.add((Variable) t); # } # } # return null; # } # # @Override # public Void visit(BinaryUnifier u, Set<Variable> boundVars) { # for (Term t : u.getArgsIterable()) { # if (t instanceof Variable) { # boundVars.add((Variable) t); # } # } # return null; # } # }; # # PremiseVisitor<Set<Variable>, Double> scorer = new CrashPremiseVisitor<Set<Variable>, Double>() { scorer: PremiseVisitor[Set[Variable], float] = LocalCrashPremiseVisitor() # @Override # public Double visit(AnnotatedAtom atom, Set<Variable> boundVars) { # int count = 0, total = 0; # for (Term t : atom.getArgs()) { # if (t instanceof Constant || boundVars.contains(t)) { # ++count; # } # ++total; # } # return (total == 0) ? 1.0 : count / total; # } # # @Override # public Double visit(BinaryUnifier u, Set<Variable> boundVars) { # for (Term t : u.getArgsIterable()) { # if (t instanceof Constant || boundVars.contains(t)) { # return Double.POSITIVE_INFINITY; # } # } # return Double.NEGATIVE_INFINITY; # } # # @Override # public Double visit(BinaryDisunifier u, Set<Variable> boundVars) { # for (Term t : u.getArgsIterable()) { # if (!(t instanceof Constant || boundVars.contains(t))) { # return Double.NEGATIVE_INFINITY; # } # } # return Double.POSITIVE_INFINITY; # } # # @Override # public Double visit(NegatedAtom atom, Set<Variable> boundVars) { # for (Term t : atom.getArgs()) { # if (!(t instanceof Constant || boundVars.contains(t))) { # return Double.NEGATIVE_INFINITY; # } # } # return Double.POSITIVE_INFINITY; # } # }; # # Collections.swap(body, 0, firstConjunctPos); body[0], body[firstConjunctPos] = body[firstConjunctPos], body[0] # int size = body.size(); size: int = len(body) # Set<Variable> boundVars = new HashSet<>(); boundVars: Set[Variable] = set() # for (int i = 1; i < size; ++i) { for i in range(1, size): # body.get(i - 1).accept(boundVarUpdater, boundVars); body[i - 1].accept_premise_visitor(boundVarUpdater, boundVars) # int bestPos = -1; bestPos: int = -1 # double bestScore = Double.NEGATIVE_INFINITY; bestScore: float = float("-inf") # for (int j = i; j < size; ++j) { j: int = i while j < size: # Double score = body.get(j).accept(scorer, boundVars); score: float = body[j].accept_premise_visitor(scorer, boundVars) # if (score > bestScore) { if score > bestScore: # bestScore = score; bestScore = score # bestPos = j; bestPos = j # } j += 1 # } # assert bestPos != -1; assert bestPos != -1 # Collections.swap(body, i, bestPos); body[i], body[bestPos] = body[bestPos], body[i] # } # # return new SemiNaiveClause(original.getHead(), body); return SemiNaiveClause(original.getHead(), tuple(body))
def annotate_single(self, original: ValidClause) -> List[SemiNaiveClause]: body: Tuple[Premise] = original.getBody() if not body: raise ValueError("Cannot annotate a bodiless clause") body2: List[Premise] = [] idbPositions: List[int] = [] edbPos: Box[int] = Box() def add_to_body2(atom, pos): if atom.getPred() in self.idbPreds: idbPositions.append(pos) body2.append(atom) else: if edbPos.value is None: edbPos.value = pos body2.append(AnnotatedAtom(atom, Annotation.EDB)) return None def simple_add_to_body2(premise, ignore): body2.append(premise) findIdbs: PremiseVisitor[int, None] = ( PremiseVisitorBuilder() .onPositiveAtom(add_to_body2) .or_(simple_add_to_body2) ) pos: int = 0 c: Premise for c in body: c.accept_premise_visitor(findIdbs, pos) pos += 1 # RA: something happens above c.accept_premise_visitor to change edPos value to 1 # body = body2; body = tuple(body2) # # if (idbPositions.isEmpty()) { # if (edbPos.value == null) { # edbPos.value = 0; # } # return Collections.singleton(sort(new Clause(original.getHead(), body), edbPos.value)); # } # if not idbPositions: if not edbPos.value: edbPos.value = 0 # singleton_set = set() singleton_set = [] # singleton_set.add(SemiNaiveClauseAnnotator.sort(Clause(original.getHead(), body), edbPos.value)) singleton_set.append( SemiNaiveClauseAnnotator.sort( Clause(original.getHead(), body), edbPos.value ) ) assert len(singleton_set) == 1, "Supposed to be a singleton set" return singleton_set # Set<SemiNaiveClause> r = new HashSet<>(); # r: Set[SemiNaiveClause] = set() r: List[SemiNaiveClause] = [] def add1(l_newBody: List, atom, anno): l_newBody.append(AnnotatedAtom(atom, anno)) return None def add2(l_newBody: List, premise, ignore): l_newBody.append(premise) return None # for (Integer i : idbPositions) { i: int for i in idbPositions: # List<Premise> newBody = new ArrayList<>(); newBody: List[Premise] = [] # PremiseVisitor<AnnotatedAtom.Annotation, Void> annotator = (new PremiseVisitorBuilder<AnnotatedAtom.Annotation, Void>()) add1_l = lambda atom, anno: add1(newBody, atom, anno) add2_l = lambda premise, ignore: add2(newBody, premise, ignore) annotator: PremiseVisitor[Annotation, None] = ( PremiseVisitorBuilder().onPositiveAtom(add1_l).or_(add2_l) ) # .onPositiveAtom((atom, anno) -> { # newBody.add(new AnnotatedAtom(atom, anno)); # return null; # }).or((premise, ignore) -> { # newBody.add(premise); # return null; # }); # Iterator<Premise> it = body.iterator(); # for (int j = 0; j < i; ++j) { # it.next().accept(annotator, AnnotatedAtom.Annotation.IDB); # } it = iter(body) item = None for j, _ in enumerate(body): if j >= i: break item = next(it) item.accept_premise_visitor(annotator, Annotation.IDB) # it.next().accept(annotator, AnnotatedAtom.Annotation.DELTA); item = next(it) item.accept_premise_visitor(annotator, Annotation.DELTA) # while (it.hasNext()) { # it.next().accept(annotator, AnnotatedAtom.Annotation.IDB_PREV); # } while True: try: item = next(it) item.accept_premise_visitor(annotator, Annotation.IDB_PREV) except StopIteration: break # r.add(sort(new Clause(original.getHead(), newBody), i)); r.append( SemiNaiveClauseAnnotator.sort( Clause(original.getHead(), tuple(newBody)), i ) ) # } r = unique(r) return r