public static List<Clause> clausesFromDefaults(Iterable<DefaultRule> rules) {
   List<Clause> retVal = new ArrayList<Clause>();
   for (DefaultRule rule : rules) {
     retVal.add(clauseFromDefault(rule));
   }
   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));
    }
  }
 private static Clause preprocessClause(Clause c, String prefix) {
   List<Literal> newLiterals = new ArrayList<Literal>();
   int specialID = 0;
   for (Literal l : c.literals()) {
     String predicate = l.predicate();
     if (predicate.equals(SpecialBinaryPredicates.NEQ)
         || predicate.equals(SpecialBinaryPredicates.EQ)
         || predicate.equals(SpecialVarargPredicates.ALLDIFF)) {
       predicate = SymmetricPredicates.PREFIX + prefix + predicate;
     } else {
       predicate = prefix + predicate;
     }
     Literal newLit = new Literal(predicate, l.isNegated(), l.arity());
     for (int i = 0; i < l.arity(); i++) {
       newLit.set(l.get(i), i);
     }
     newLiterals.add(newLit);
   }
   return new Clause(newLiterals);
 }
 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 MultiMap<DefaultRule, DefaultRule> representativeBodySpecializations(
      DefaultRule rule, List<Set<Constant>> interchangeableConstants) {
    Clause body = rule.antecedent();
    Clause head = rule.consequent();
    final MultiMap<Variable, Variable> different = surelyDifferent(rule);

    final List<Variable> variables = Sugar.<Variable>listFromCollections(body.variables());
    List<Integer> indices = VectorUtils.toList(VectorUtils.sequence(0, variables.size() - 1));
    List<Tuple<Integer>> unifications =
        Combinatorics.<Integer>cartesianPower(
            indices,
            indices.size(),
            new Sugar.Fun<Tuple<Integer>, Boolean>() {
              @Override
              public Boolean apply(Tuple<Integer> integerTuple) {
                for (int i = 0; i < integerTuple.size(); i++) {
                  if (integerTuple.get(i) > i
                      || !integerTuple.get(i).equals(integerTuple.get(integerTuple.get(i)))
                      || different
                          .get(variables.get(integerTuple.get(i)))
                          .contains(variables.get(i))
                      || !sameType(variables.get(integerTuple.get(i)), variables.get(i))) {
                    return Boolean.FALSE;
                  }
                }
                return Boolean.TRUE;
              }
            });

    Set<DefaultRule> nonIsomorphicUnifications = new HashSet<DefaultRule>();
    for (Tuple<Integer> unification : unifications) {
      Map<Term, Term> substitution = new HashMap<Term, Term>();
      for (int i = 0; i < unification.size(); i++) {
        substitution.put(variables.get(i), variables.get(unification.get(i)));
      }
      Clause newBody = LogicUtils.substitute(rule.antecedent(), substitution);
      Clause newHead = LogicUtils.substitute(rule.consequent(), substitution);
      nonIsomorphicUnifications.add(
          new DefaultRule(
              newBody.variables().size() > 1
                  ? new Clause(Sugar.union(newBody.literals(), allDiffLiteral(newBody)))
                  : newBody,
              newHead));
    }

    nonIsomorphicUnifications =
        DefaultTransformationUtils.selectNonisomorphicDefaultRules(nonIsomorphicUnifications);

    MultiMap<DefaultRule, DefaultRule> retVal = new MultiMap<DefaultRule, DefaultRule>();

    // this needs to be improved... e.g. using typing information...
    MultiList<Integer, Constant> consts = new MultiList<Integer, Constant>();
    int index = 0;
    for (Set<Constant> interch : interchangeableConstants) {
      consts.putAll(index++, interch);
    }
    for (DefaultRule unifiedRule : nonIsomorphicUnifications) {
      List<Variable> unifsVariables = Sugar.listFromCollections(unifiedRule.variables());
      if (unifsVariables.isEmpty()) {
        retVal.put(unifiedRule, unifiedRule);
      } else {
        Set<DefaultRule> substituted = new HashSet<DefaultRule>();
        middleLoop:
        for (Tuple<Integer> tuple :
            Combinatorics.cartesianPower(
                new NaturalNumbersList(0, interchangeableConstants.size()),
                unifsVariables.size())) {
          Counters<Integer> used = new Counters<Integer>();
          Map<Term, Term> substitution = new HashMap<Term, Term>();
          for (int i = 0; i < unifsVariables.size(); i++) {
            int j = used.incrementPost(tuple.get(i));
            if (j >= consts.get(tuple.get(i)).size()) {
              continue middleLoop;
            } else {
              if (unifsVariables.get(i).type() == null) {
                substitution.put(
                    unifsVariables.get(i),
                    Variable.construct(
                        unifsVariables.get(i).name(), consts.get(tuple.get(i)).get(j).type()));
              } else {
                if (unifsVariables.get(i).type().equals(consts.get(tuple.get(i)).get(j).type())) {
                  substitution.put(
                      unifsVariables.get(i),
                      Variable.construct(
                          unifsVariables.get(i).name(), consts.get(tuple.get(i)).get(j).type()));
                } else {
                  continue middleLoop;
                }
              }
            }
          }
          substituted.add(DefaultTransformationUtils.substitute(unifiedRule, substitution));
        }
        retVal.putAll(
            unifiedRule, DefaultTransformationUtils.selectNonisomorphicDefaultRules(substituted));
      }
    }
    return retVal;
  }
  private static MultiList<Object, Set<Constant>> partitionExchangeable_impl(
      Iterable<DefaultRule> rules) {
    MultiMap<Term, Term> partitioning = new MultiMap<Term, Term>();

    List<Term> constants = Sugar.arrayListFromCollections(constants(rules));
    Set<Term> closed = new HashSet<Term>();

    // checking interchangeability pairwise
    for (int i = 0; i < constants.size(); i++) {
      if (!closed.contains(constants.get(i))) {
        partitioning.put(constants.get(i), constants.get(i));
        for (int j = i + 1; j < constants.size(); j++) {
          if (areExchangeable(constants.get(i), constants.get(j), rules)) {
            partitioning.put(constants.get(i), constants.get(j));
            closed.add(constants.get(j));
          }
        }
      }
    }
    Map<Constant, Constant> map = new HashMap<Constant, Constant>();
    for (Map.Entry<Term, Set<Term>> entry : partitioning.entrySet()) {
      Constant lexmin = null;
      for (Term t : entry.getValue()) {
        if (t instanceof Constant) {
          if (lexmin == null || t.toString().compareTo(lexmin.toString()) < 0) {
            lexmin = (Constant) t;
          }
        }
      }
      for (Term t : entry.getValue()) {
        if (t instanceof Constant) {
          map.put((Constant) t, lexmin);
        }
      }
    }

    MultiMap<Pair<Object, Constant>, Constant> mm =
        new MultiMap<Pair<Object, Constant>, Constant>();
    for (Map.Entry<Constant, Constant> entry : map.entrySet()) {
      mm.put(
          new Pair<Object, Constant>(
              entry.getValue().type() == null ? Sugar.NIL : entry.getValue().type(),
              entry.getValue()),
          entry.getKey());
    }

    MultiList<Object, Set<Constant>> retVal = new MultiList<Object, Set<Constant>>();
    for (Map.Entry<Pair<Object, Constant>, Set<Constant>> entry : mm.entrySet()) {
      retVal.put(entry.getKey().r, entry.getValue());
    }
    return retVal;
  }