@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()); }