/**
  * Constructs an ARCE strategy that will use the given translation log to relate the cnf clauses
  * back to the logic constraints from which they were generated.
  *
  * @ensures this.hardnessCutOff' = hardnessCutOff and this.recycleLimit' = recycleLimit and
  *     this.noRecycleRatio' = noRecycleRatio
  */
 public DynamicRCEStrategy(
     final TranslationLog log, double noRecycleRatio, double hardnessCutOff, double recycleLimit) {
   if (noRecycleRatio < 0 || noRecycleRatio > 1)
     throw new IllegalArgumentException("noRecycleRatio must be in [0..1]: " + noRecycleRatio);
   if (hardnessCutOff < 1)
     throw new IllegalArgumentException("hardnessCutOff must be >=1: " + hardnessCutOff);
   if (recycleLimit < 1)
     throw new IllegalArgumentException("recycleLimit must be >=1: " + recycleLimit);
   this.noRecycleRatio = noRecycleRatio;
   this.hardnessCutOff = hardnessCutOff;
   this.recycleLimit = recycleLimit;
   this.hits = new TreeSequence<IntSet>();
   for (IntIterator itr = StrategyUtils.rootVars(log).iterator(); itr.hasNext(); ) {
     hits.put(itr.next(), null);
   }
 }
  /**
   * Returns an array R of longs such that for each i, j in [0..R.length) i < j implies that the
   * formula identified by (int)R[i] in this.hits contributes fewer clauses to the core of the given
   * trace than the formula identified by (int)R[j].
   *
   * @return an array as described above
   */
  private long[] sortByRelevance(ResolutionTrace trace, IntSet relevantVars) {
    hits.indices().retainAll(relevantVars);

    if (hits.get(hits.indices().min()) == null) { // first call, initialize the hits
      for (IntIterator varItr = relevantVars.iterator(); varItr.hasNext(); ) {
        final int var = varItr.next();
        final IntSet varReachable = new IntBitSet(var + 1);
        varReachable.add(var);
        hits.put(var, varReachable);
      }
      for (Iterator<Clause> clauseItr = trace.reverseIterator(trace.axioms());
          clauseItr.hasNext(); ) {
        final Clause clause = clauseItr.next();
        final int maxVar = clause.maxVariable();
        for (IntSet reachableVars : hits.values()) {
          if (reachableVars.contains(maxVar)) {
            for (IntIterator lits = clause.literals(); lits.hasNext(); ) {
              reachableVars.add(StrictMath.abs(lits.next()));
            }
          }
        }
      }
    }

    final long[] counts = new long[hits.size()];

    for (Iterator<Clause> clauseItr = trace.iterator(trace.core()); clauseItr.hasNext(); ) {
      final Clause clause = clauseItr.next();
      final int maxVar = clause.maxVariable();
      int i = 0;
      for (IntSet reachableVars : hits.values()) {
        if (reachableVars.contains(maxVar)) {
          counts[i]++;
        }
        i++;
      }
    }

    int i = 0;
    for (IntIterator varItr = hits.indices().iterator(); varItr.hasNext(); ) {
      final int var = varItr.next();
      counts[i] = (counts[i] << 32) | var;
      i++;
    }

    Arrays.sort(counts);

    return counts;
  }