public boolean verify(KnowledgeBase kb) {

    final Map<KnowledgeElement, Boolean> results = new LinkedHashMap<KnowledgeElement, Boolean>();

    KnowledgeBaseVisitor visitor =
        new AbstractKnowledgeBaseVisitor() {
          Collection<Variable> vars = null;
          Collection<Variable> varsInBody = new HashSet<Variable>();
          Collection<Variable> varsInHead = new ArrayList<Variable>();
          DerivationRule context = null;

          public boolean visit(DerivationRule r) {
            context = r;
            varsInHead.clear();
            varsInBody.clear();
            return true;
          }

          public void endVisit(DerivationRule r) {
            context = null;
            Variable var = null;
            for (Variable v : varsInHead) {
              if (!varsInBody.contains(v)) var = v;
            }
            if (var == null) reportOK(r);
            else reportViolation("variable ", var, " in ", r, " occurs only in rule head");
            results.put(r, var == null);
          }

          public boolean visit(Fact f) {
            if (context == null) {
              return false;
            } else if (context.getHead() == f) {
              vars = varsInHead;
            } else if (context.getBody().contains(f)) {
              vars = varsInBody;
            }
            return true;
          }

          public boolean visit(Variable t) {
            vars.add(t);
            return true;
          }
        };

    kb.accept(visitor);
    for (boolean b : results.values()) {
      if (!b) return false;
    }
    return true;
  }