@Override
  protected AFCalculationResult computeLog10PNonRef(
      final VariantContext vc,
      final int defaultPloidy,
      final double[] log10AlleleFrequencyPriors,
      final StateTracker stateTracker) {
    Utils.nonNull(vc, "vc is null");
    Utils.nonNull(log10AlleleFrequencyPriors, "log10AlleleFrequencyPriors is null");
    Utils.nonNull(stateTracker, "stateTracker is null");
    final int numAlternateAlleles = vc.getNAlleles() - 1;

    final List<double[]> genotypeLikelihoods = getGLs(vc.getGenotypes(), true);
    final int numSamples = genotypeLikelihoods.size() - 1;
    final int numChr = 2 * numSamples;

    // queue of AC conformations to process
    final Deque<ExactACset> ACqueue = new LinkedList<>();

    // mapping of ExactACset indexes to the objects
    final Map<ExactACcounts, ExactACset> indexesToACset = new HashMap<>(numChr + 1);

    // add AC=0 to the queue
    final int[] zeroCounts = new int[numAlternateAlleles];
    final ExactACset zeroSet = new ExactACset(numSamples + 1, new ExactACcounts(zeroCounts));
    ACqueue.add(zeroSet);
    indexesToACset.put(zeroSet.getACcounts(), zeroSet);

    while (!ACqueue.isEmpty()) {

      // compute log10Likelihoods
      final ExactACset set = ACqueue.remove();

      calculateAlleleCountConformation(
          set,
          genotypeLikelihoods,
          numChr,
          ACqueue,
          indexesToACset,
          log10AlleleFrequencyPriors,
          stateTracker);

      // clean up memory
      indexesToACset.remove(set.getACcounts());
    }

    return getResultFromFinalState(vc, log10AlleleFrequencyPriors, stateTracker);
  }
  private static void pushData(
      final ExactACset targetSet,
      final ExactACset dependentSet,
      final int PLsetIndex,
      final List<double[]> genotypeLikelihoods) {
    final int totalK = targetSet.getACsum();

    for (int j = 1; j < targetSet.getLog10Likelihoods().length; j++) {
      if (totalK <= 2 * j) { // skip impossible conformations
        final double[] gl = genotypeLikelihoods.get(j);
        final double conformationValue =
            determineCoefficient(PLsetIndex, j, targetSet.getACcounts().getCounts(), totalK)
                + dependentSet.getLog10Likelihoods()[j - 1]
                + gl[PLsetIndex];
        targetSet.getLog10Likelihoods()[j] =
            MathUtils.approximateLog10SumLog10(
                targetSet.getLog10Likelihoods()[j], conformationValue);
      }
    }
  }
  private double calculateAlleleCountConformation(
      final ExactACset set,
      final List<double[]> genotypeLikelihoods,
      final int numChr,
      final Deque<ExactACset> ACqueue,
      final Map<ExactACcounts, ExactACset> indexesToACset,
      final double[] log10AlleleFrequencyPriors,
      final StateTracker stateTracker) {

    // compute the log10Likelihoods
    computeLofK(set, genotypeLikelihoods, log10AlleleFrequencyPriors, stateTracker);

    final double log10LofK = set.getLog10Likelihoods()[set.getLog10Likelihoods().length - 1];

    // can we abort early because the log10Likelihoods are so small?
    if (stateTracker.abort(log10LofK, set.getACcounts(), true, false)) {
      return log10LofK;
    }

    // iterate over higher frequencies if possible
    final int ACwiggle = numChr - set.getACsum();
    if (ACwiggle
        == 0) { // all alternate alleles already sum to 2N so we cannot possibly go to higher
                // frequencies
      return log10LofK;
    }

    final int numAltAlleles = set.getACcounts().getCounts().length;

    // add conformations for the k+1 case
    for (int allele = 0; allele < numAltAlleles; allele++) {
      final int[] ACcountsClone = set.getACcounts().getCounts().clone();
      ACcountsClone[allele]++;
      // to get to this conformation, a sample would need to be AB (remember that ref=0)
      final int PLindex = GenotypeLikelihoods.calculatePLindex(0, allele + 1);
      updateACset(
          ACcountsClone, numChr, set, PLindex, ACqueue, indexesToACset, genotypeLikelihoods);
    }

    // add conformations for the k+2 case if it makes sense; note that the 2 new alleles may be the
    // same or different
    if (ACwiggle > 1) {
      final List<DependentSet> differentAlleles = new ArrayList<>(numAltAlleles * numAltAlleles);
      final List<DependentSet> sameAlleles = new ArrayList<>(numAltAlleles);

      for (int allele_i = 0; allele_i < numAltAlleles; allele_i++) {
        for (int allele_j = allele_i; allele_j < numAltAlleles; allele_j++) {
          final int[] ACcountsClone = set.getACcounts().getCounts().clone();
          ACcountsClone[allele_i]++;
          ACcountsClone[allele_j]++;

          // to get to this conformation, a sample would need to be BB or BC (remember that ref=0,
          // so add one to the index)
          final int PLindex = GenotypeLikelihoods.calculatePLindex(allele_i + 1, allele_j + 1);
          if (allele_i == allele_j) {
            sameAlleles.add(new DependentSet(ACcountsClone, PLindex));
          } else {
            differentAlleles.add(new DependentSet(ACcountsClone, PLindex));
          }
        }
      }

      // IMPORTANT: we must first add the cases where the 2 new alleles are different so that the
      // queue maintains its ordering
      for (final DependentSet dependent : differentAlleles) {
        updateACset(
            dependent.ACcounts,
            numChr,
            set,
            dependent.PLindex,
            ACqueue,
            indexesToACset,
            genotypeLikelihoods);
      }
      for (final DependentSet dependent : sameAlleles) {
        updateACset(
            dependent.ACcounts,
            numChr,
            set,
            dependent.PLindex,
            ACqueue,
            indexesToACset,
            genotypeLikelihoods);
      }
    }

    return log10LofK;
  }
  private static void computeLofK(
      final ExactACset set,
      final List<double[]> genotypeLikelihoods,
      final double[] log10AlleleFrequencyPriors,
      final StateTracker stateTracker) {

    set.getLog10Likelihoods()[0] = 0.0; // the zero case
    final int totalK = set.getACsum();

    // special case for k = 0 over all k
    if (totalK == 0) {
      for (int j = 1; j < set.getLog10Likelihoods().length; j++) {
        set.getLog10Likelihoods()[j] =
            set.getLog10Likelihoods()[j - 1] + genotypeLikelihoods.get(j)[HOM_REF_INDEX];
      }

      final double log10Lof0 = set.getLog10Likelihoods()[set.getLog10Likelihoods().length - 1];
      stateTracker.setLog10LikelihoodOfAFzero(log10Lof0);
      stateTracker.setLog10PosteriorOfAFzero(log10Lof0 + log10AlleleFrequencyPriors[0]);
      return;
    }

    // if we got here, then k > 0 for at least one k.
    // the non-AA possible conformations were already dealt with by pushes from dependent sets;
    // now deal with the AA case (which depends on previous cells in this column) and then update
    // the L(j,k) value
    for (int j = 1; j < set.getLog10Likelihoods().length; j++) {
      if (totalK < 2 * j - 1) {
        final double[] gl = genotypeLikelihoods.get(j);
        final double conformationValue =
            MathUtils.log10(2 * j - totalK)
                + MathUtils.log10(2 * j - totalK - 1)
                + set.getLog10Likelihoods()[j - 1]
                + gl[HOM_REF_INDEX];
        set.getLog10Likelihoods()[j] =
            MathUtils.approximateLog10SumLog10(set.getLog10Likelihoods()[j], conformationValue);
      }

      final double logDenominator = MathUtils.log10(2 * j) + MathUtils.log10(2 * j - 1);
      set.getLog10Likelihoods()[j] = set.getLog10Likelihoods()[j] - logDenominator;
    }

    double log10LofK = set.getLog10Likelihoods()[set.getLog10Likelihoods().length - 1];

    // update the MLE if necessary
    stateTracker.updateMLEifNeeded(log10LofK, set.getACcounts().getCounts());

    // apply the priors over each alternate allele
    for (final int ACcount : set.getACcounts().getCounts()) {
      if (ACcount > 0) {
        log10LofK += log10AlleleFrequencyPriors[ACcount];
      }
    }

    stateTracker.updateMAPifNeeded(log10LofK, set.getACcounts().getCounts());
  }