def visit_negated_atom( self, atom: NegatedAtom, e: DatalogValidationException) -> DatalogValidationException: if not self.allowNegatedBodyAtom: return DatalogValidationException( "Negated body atoms are not allowed:") TermHelpers.fold(atom.getArgs(), self.tv, self.possiblyUnboundVars) return e
def visit_binary_disunifier( self, u: BinaryDisunifier, e: DatalogValidationException) -> DatalogValidationException: if not self.allowBinaryDisunification: return DatalogValidationException( "Binary disunification is not allowed") TermHelpers.fold(u.get_args_iterable(), self.tv, self.possiblyUnboundVars) return e
def visit_binary_unifier( self, u: BinaryUnifier, e: DatalogValidationException) -> DatalogValidationException: if not self.allowBinaryUnification: return DatalogValidationException( "Binary unification is not allowed") TermHelpers.fold(u.getArgsIterable(), self.tv, self.possiblyUnboundVars) TermHelpers.unify_term_unifier(u.getLeft(), u.getRight(), self.subst) return e
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 unify(xs: List[Term], ys: List[Term]) -> Optional["SimpleConstSubstitution"]: if len(xs) != len(ys): return None r = SimpleConstSubstitution() z = zip(xs, ys) for x, y in z: if not TermHelpers.unify_const_only_substitution(x, y, r): return None return r
def visit_negated_atom(self, atom: NegatedAtom, count: int): self.idxByConj.append(count) return TermHelpers.fold(atom.getArgs(), self.tv, count)
def visit_binary_disunifier(self, u: BinaryDisunifier, count: int) -> int: self.idxByConj.append(count) return TermHelpers.fold(u.get_args_iterable(), self.tv, count)
def visit_positive_atom( self, atom: PositiveAtom, e: DatalogValidationException) -> DatalogValidationException: TermHelpers.fold(atom.getArgs(), self.tv, self.boundVars) self.hasPositiveAtom.value = True return e