/** {@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;
  }