public static Set<DefaultRule> selectNonisomorphicDefaultRules(
     Iterable<DefaultRule> defaultRules) {
   List<Clause> candidates = new ArrayList<Clause>();
   for (DefaultRule rule : defaultRules) {
     DefaultRule preprocessed = preprocess(rule);
     candidates.add(
         new Clause(
             Sugar.<Literal>iterable(
                 preprocessed.antecedent().literals(), preprocessed.consequent().literals())));
   }
   Matching m = new Matching();
   Set<DefaultRule> retVal = new HashSet<DefaultRule>();
   for (Clause c : m.nonisomorphic(candidates)) {
     List<Literal> head = new ArrayList<Literal>();
     List<Literal> body = new ArrayList<Literal>();
     for (Literal l : c.literals()) {
       Literal newLiteral =
           new Literal(
               l.predicate().substring(l.predicate().indexOf(":") + 1), l.isNegated(), l.arity());
       for (int i = 0; i < l.arity(); i++) {
         newLiteral.set(l.get(i), i);
       }
       if (l.predicate().startsWith("antecedent:")
           || l.predicate().startsWith(SymmetricPredicates.PREFIX + "antecedent:")) {
         body.add(newLiteral);
       } else {
         head.add(newLiteral);
       }
     }
     retVal.add(new DefaultRule(new Clause(body), new Clause(head)));
   }
   return retVal;
 }
  public static DefaultRule representativeSubstitution(
      DefaultRule rule, List<Set<Constant>> interchangeable) {
    if (rule.antecedent().variables().isEmpty()) {
      return rule;
    } else {
      // a bit naive (but not too much), it can be improved later...
      List<Literal> auxLiteralsC = new ArrayList<Literal>();
      for (Variable v : rule.antecedent().variables()) {
        auxLiteralsC.add(new Literal("v", v));
      }

      List<Literal> auxLiteralsE = new ArrayList<Literal>();

      int typeIndex = 0;
      for (Set<Constant> interch : interchangeable) {
        int counter = 0;
        for (Term t : interch) {
          auxLiteralsE.add(new Literal("v", t));
          if (++counter >= rule.antecedent().variables().size()) {
            break;
          }
        }
      }
      Matching m = new Matching();
      m.setSubsumptionMode(Matching.OI_SUBSUMPTION);
      Pair<Term[], List<Term[]>> substitutions =
          m.allSubstitutions(new Clause(auxLiteralsC), new Clause(auxLiteralsE), 1);
      return DefaultTransformationUtils.substitute(rule, substitutions.r, substitutions.s.get(0));
    }
  }
 public static boolean isomorphic(DefaultRule a, DefaultRule b) {
   a = preprocess(a);
   b = preprocess(b);
   Matching m = new Matching();
   Clause ca = new Clause(Sugar.iterable(a.antecedent().literals(), a.consequent().literals()));
   Clause cb = new Clause(Sugar.iterable(b.antecedent().literals(), b.consequent().literals()));
   return ca.variables().size() == cb.variables().size()
       && ca.literals().size() == cb.literals().size()
       && m.isomorphism(ca, cb);
 }