/** {@inheritDoc} */ @Override public double subComputeReadLikelihoodGivenHaplotypeLog10( final byte[] haplotypeBases, final byte[] readBases, final byte[] readQuals, final byte[] insertionGOP, final byte[] deletionGOP, final byte[] overallGCP, int hapStartIndex, final boolean recacheReadValues, final int nextHapStartIndex) { if (!constantsAreInitialized) { initializeProbabilities(transition, insertionGOP, deletionGOP, overallGCP); // note that we initialized the constants constantsAreInitialized = true; } initializePriors(haplotypeBases, readBases, readQuals, hapStartIndex); // Some housekeeping to be done if we are starting a new read if (recacheReadValues) { hapStartIndex = 0; initializeProbabilities(transition, insertionGOP, deletionGOP, overallGCP); // note that we initialized the constants constantsAreInitialized = true; // Read length may have changed, so we need to set zero-value padding at the appropriate // position. padMatchAndInsertArrays(readBases.length); } // if we have not cached from a previous haplotype, clear any info we may have accumulated in a // previous HMM iteration if (hapStartIndex == 0) { clearPreviouslyCachedInfo(readBases.length); // Haplotype length may have changed, so we need to set initial-value padding at the // appropriate position. padDeleteArrays(haplotypeBases.length, readBases.length); } // We build up our solution by looking at position [0] in the match, insert arrays. Need to set // these to 0 before we start. clearArraySolutionPosition(); // Some parameters to control behavior during the dynamic programming loop final int maxDiagonals = readBases.length + haplotypeBases.length - hapStartIndex - 1; // Number of diagonals for a matrix = rows + cols - 1; int startFill; // The lower bound of the array indices we want to over-write int endFill; // The upper bound of the array indices we want to over-write final int cacheSumIndex = nextHapStartIndex - hapStartIndex + readBases.length - 1; // This array will contain the partial sum to cache for the next haplotype double finalArraySumProbabilities = partialSum; // The final answer prior to log10 correction // Perform dynamic programming using arrays, as if over diagonals of a hypothetical // read/haplotype alignment matrix for (int i = 1; i <= maxDiagonals; i++) { // set the bounds for cells we wish to fill in the arrays startFill = Math.max(readBases.length - i, 0); endFill = Math.min(maxDiagonals - i + 1, readBases.length); // apply any previously cached array information if (i <= readBases.length) applyPreviouslyCachedInfo(startFill); // fill in the cells for our current arrays updateArrays(readBases.length, hapStartIndex, nextHapStartIndex, startFill, endFill, i); // final probability is the log10 sum of the last element in the Match and Insertion state // arrays // this way we ignore all paths that ended in deletions! (huge) // but we have to sum all the paths ending in the M and I arrays, because they're no longer // extended. // Where i > readBases.length, array[0] corresponds to bottom row of a [read] x [haplotype] // matrix. Before this, they carries the 0's we set above. finalArraySumProbabilities += currentInsertArray[0] + currentMatchArray[0]; // Partial sum for caching the next haplotype: // At the position of the last similar base between this haplotype and the next one... // ...remember the partial sum, so that we can start here on the next hap. if (i == cacheSumIndex) partialSum = finalArraySumProbabilities; rotateArrayReferences(); } // The cache arrays we wrote for this haplotype will be read for the next haplotype. rotateCacheArrays(); // return result return Math.log10(finalArraySumProbabilities) - INITIAL_CONDITION_LOG10; }