// File: /workspace/github_cpp_makefile_star2_O3/Altius[P]hotspot2/src/hotspot2_part1.cpp
// Function: BackgroundRegionManager::computeStats(int const&)
void BackgroundRegionManager::computeStats(const int& this_k)
{
  if (1 == m_sampledDataDistnSize)
    {
      // All observations within this region were of count == 0.
      m_distn[0].pmf = m_distn[0].pval = 1.;
      m_runningSum_count_duringPrevComputation = m_runningSum_count;
      m_runningSum_countSquared_duringPrevComputation = m_runningSum_countSquared;
      m_numPtsInNullRegion = m_distn[0].numOccs;
      m_numPtsInNullRegion_duringPrevComputation = m_numPtsInNullRegion;
      m_prev_k = 0;
      m_pmf = &nextProbPoisson;
      m_pmfParams.clear();
      m_pmfParams.push_back(0.);
      return;
    }

  int k;
  // Make *pmf() and params private member variables,
  // so they can be accessed elsewhere during debugging.
  long double prob0; // probability of observing 0 counts by random chance
  long double m; // mean
  long double v; // variance
  long double N(static_cast<long double>(m_numPtsInNullRegion));
  m = static_cast<long double>(m_runningSum_count) / N;
  v = (static_cast<long double>(m_runningSum_countSquared) - N * m * m) / (N - 1.);
  m_pmfParams.clear();
  static bool warningAlreadyIssued(false);

  // Set up the negative binomial model.
  // Double-check that m < v; if m >= v, which is extremely unlikely,
  // use a more appropriate model (binomial or Poisson).
  // Use the definitions of variance and mean to perform an integer (exact) test for m == v.
  if (m_numPtsInNullRegion * m_runningSum_countSquared - m_runningSum_count*m_runningSum_count == m_runningSum_count*(m_numPtsInNullRegion - 1))
    {
      // Poisson, m = v
      prob0 = exp(-m);
      m_pmfParams.push_back(m);
      m_pmf = &nextProbPoisson;
      if ((0 == m_runningSum_count || 1 == m_runningSum_count) && !warningAlreadyIssued)
        {
          cerr << "Warning:  In region " << *m_pCurChrom << ':' << m_posL << '-' << m_posR
               << ", all counts used for statistics were 0, or all were 0 except one was 1.\n"
               << "This generally should not happen.  If this region is unmappable or problematic for other reasons,\n"
               << "it would almost certainly be best to filter it out of the input.\n"
               << "There may be other such regions in the input; this warning will only be issued once during this run."
               << endl;
          warningAlreadyIssued = true;
        }
    }
  else
    {
      if (m < v)
        {
          // negative binomial
          long double r = m * m / (v - m);
          m_pmfParams.push_back(m);
          m_pmfParams.push_back(r);
          prob0 = pow(r / (r + m), r);
          m_pmf = &nextProbNegativeBinomial;
        }
      else // m > v (this is very unlikely)
        {
          // binomial
          long double n(floor(m * m / (m - v) + 0.5)); // estimate n of the fit from the observed mean and variance
          long double kk_max(static_cast<long double>(m_kcutoff)); // BUGBUG if m_kcutoff has 0 observations, do we still want to use it here??!?
          if (kk_max > n + 0.1) // + 0.1 to account for roundoff error, e.g. k=16.00001 and n=15.99999
            {
              // We don't expect this to happen, but if the estimated n is smaller than the observed m_kcutoff,
              // then we need to set n = m_kcutoff to allow m_kcutoff to be generated by the binomial model.
              n = kk_max;
            }
          // Now that we've set n, there's inconsistency among n, m, and v, with respect to the binomial.
          // We choose to keep m as observed, and update the variance parameter v so that consistency is achieved.
          v = m * (1. - m / n); // Now m*m/(m-v) = the integer n. Example: m=1.8952, v=1.6747, n=16.2893-->16, v-->1.6701.
          prob0 = pow(v / m, n);
          m_pmfParams.push_back(m);
          m_pmfParams.push_back(v);
          m_pmfParams.push_back(n);
          if (v > 1.0e-8)
            m_pmf = &nextProbBinomial;
          else
            {
              m_pmf = NULL;
              return;
            }
        }
    }

  // Now compute the minimum necessary number of pmf values, from the null model (e.g. negative binomial fit).

  // BUGBUG potential speed-up:  Allow the user to specify a minimum pmf,
  // such that no pmf values below it will be computed and
  // the P-values reported will asymptote at the P-value corresponding to that cutoff.
  // E.g., the user might specify a minimum pmf of numeric_limits<double>::epsilon().
  // If a P-value is, say, 1.23456e-218, do we really want to know that,
  // or are we content to know that it's something smaller than, say, 1e-40?

  long double curPMF(prob0);
  int k_begin(1), k_end(m_sampledDataDistnSize - 1); // default (-1 == this_k):  compute for all k observed in the background window
  const int MAlenOver2(m_MAlength / 2);
  if (-1 == this_k)
    m_distn[0].pmf = curPMF;
  else
    {
      k_end = this_k;
      if (-1 == m_prev_k) // compute for 0 <= k <= this_k.
        m_distn[0].pmf = curPMF;
      else // compute for (highest k previously handled) < k <= this_k.
        {
          curPMF = m_distn[m_prev_k].pmf;
          k_begin = m_prev_k + 1;
        }
    }
  for (k = k_begin; k <= k_end; k++)
    {
      curPMF = m_pmf(k, curPMF, m_pmfParams); // note:  if pmf == binomial and k > binomial's n, 0 is returned
      if (static_cast<int>(m_distn.size()) == k)
        {
          StatsForCount sc;
          sc.numOccs = 0;
          sc.pmf = sc.pval = -1.;
          sc.MAxN = -1; // don't compute moving averages until/unless we're sliding, for efficiency's sake
          m_distn.push_back(sc); // be sure not to increment m_sampledDataDistnSize...
          if (k >= m_MAlength)
            m_distn[k - MAlenOver2].MAxN = m_distn[k - MAlenOver2 - 1].MAxN - m_distn[k - m_MAlength].numOccs + m_distn[k].numOccs;
          else
            {
              if (m_MAlength - 1 == k)
                {
                  int sum(0);
                  for (int j = 0; j <= k; j++)
                    sum += m_distn[j].numOccs;
                  m_distn[MAlenOver2].MAxN = sum;
                }
            }
        }
      m_distn[k].pmf = curPMF;
    }

  // Because pmf(k) happens to be a multiple of pmf(k-1) for every k for each model (negative binomial, binomial, Poisson),
  // we can write the P-value for observing k counts as
  //
  // pval(k) = pmf(k) * (1 + term(k+1) + term(k+2) + term(k+3) + ...),
  //
  // where the terms in the sum decrease monotonically with k.
  // We can cap the sum at, say, 5 significant digits for pval(k),
  // and then work backwards, filling in pval(k-1) = pmf(k-1) + pval(k),
  // ending with pval(0) = 1.
  k--; // reset so that k corresponds to the last pmf computed
  int j = k;
  long double sum(1.), prevTerm(1.), curTerm;
  const long double SMALL_VALUE(5.0e-7); // restrict the correctness of the final P-value to ~5 significant digits
  while ((curTerm = m_pmf(++j, prevTerm, m_pmfParams)) > SMALL_VALUE)
    {
      sum += curTerm;
      prevTerm = curTerm;
    }
  m_distn[k].pval = m_distn[k].pmf * sum;
  //  if (m_distn[k].pval < numeric_limits<double>::min())
  //    m_distn[k].pval = numeric_limits<double>::min();
  while (k > 1)
    {
      m_distn[k - 1].pval = m_distn[k - 1].pmf + m_distn[k].pval;
      //      if (m_distn[k].pval < numeric_limits<double>::min())
      //	m_distn[k].pval = numeric_limits<double>::min();
      k--;
    }
  m_distn[0].pval = 1.; // explicitly set it to 1, to avoid potential round-off error

  if (-1 != this_k)
    m_prev_k = this_k;
  else
    m_prev_k = m_sampledDataDistnSize - 1;

  m_runningSum_count_duringPrevComputation = m_runningSum_count;
  m_runningSum_countSquared_duringPrevComputation = m_runningSum_countSquared;
  m_numPtsInNullRegion_duringPrevComputation = m_numPtsInNullRegion;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xe8, %rsp
movq %rdi, %rbx
cmpl $0x1, 0x160(%rdi)
jne 0x36dd
movq 0x50(%rbx), %rax
fld1
fld %st(0)
fstpt 0x20(%rax)
fstpt 0x10(%rax)
movaps 0x10(%rbx), %xmm0
movups %xmm0, 0x28(%rbx)
movl (%rax), %eax
movl %eax, 0x20(%rbx)
movl %eax, 0x38(%rbx)
movl $0x0, 0x154(%rbx)
leaq -0xb9f(%rip), %rax      # 0x2af3
movq %rax, 0x168(%rbx)
movq 0x170(%rbx), %rax
movq 0x178(%rbx), %rsi
cmpq %rax, %rsi
je 0x36b6
movq %rax, 0x178(%rbx)
movq %rax, %rsi
fldz
fld %st(0)
fstpt 0x60(%rsp)
cmpq 0x180(%rbx), %rsi
je 0x37f1
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3de1
movq %rsi, %r12
movslq 0x20(%rbx), %rax
movl %eax, 0x50(%rsp)
fildl 0x50(%rsp)
movq 0x10(%rbx), %rcx
movq %rcx, 0xd8(%rsp)
fildll 0xd8(%rsp)
fdiv %st(1), %st
fld %st(0)
fstpt 0xc0(%rsp)
movq 0x18(%rbx), %rdx
movq %rdx, 0xe0(%rsp)
fildll 0xe0(%rsp)
fld %st(1)
fchs
fld %st(3)
fmul %st(3), %st
fmul %st(3), %st
fsubrp %st, %st(2)
fld1
fchs
fld %st(0)
fstpt 0x54(%rsp)
faddp %st, %st(4)
fxch %st(1)
fdivp %st, %st(3)
fld %st(2)
fstpt 0xb0(%rsp)
movq 0x170(%rbx), %rdi
movq 0x178(%rbx), %rsi
cmpq %rdi, %rsi
je 0x375f
movq %rdi, 0x178(%rbx)
movq %rdi, %rsi
leaq 0x170(%rbx), %r15
imulq %rax, %rdx
movq %rcx, %rdi
imulq %rcx, %rdi
subq %rdi, %rdx
decl %eax
cltq
imulq %rcx, %rax
cmpq %rax, %rdx
jne 0x37b9
fstp %st(2)
fstpt 0x28(%rsp)
fstpt (%rsp)
callq 0x2060
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x38ae
fldt 0x28(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x38c6
fstp %st(0)
fxch %st(1)
fucomi %st(1), %st
fld %st(1)
fmul %st(2), %st
jbe 0x380c
fxch %st(1)
fsub %st(2), %st
fdivrp %st, %st(1)
fstpt 0x60(%rsp)
movq 0x180(%rbx), %rax
cmpq %rax, %rsi
je 0x39ef
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3a0f
fstp %st(0)
addq $0x170, %rbx            # imm = 0x170
leaq 0x60(%rsp), %rdx
movq %rbx, %rdi
callq 0x8356
jmp 0x3de1
fld %st(2)
fstpt 0x28(%rsp)
fxch %st(2)
fsubp %st, %st(1)
fdivrp %st, %st(1)
fadds 0x57e6(%rip)            # 0x9004
fstpt (%rsp)
callq 0x20f0
fld %st(0)
fstpt 0x60(%rsp)
movl 0x110(%rbx), %eax
movl %eax, 0x4c(%rsp)
fildl 0x4c(%rsp)
fld %st(1)
faddl 0x57de(%rip)            # 0x9020
fxch %st(1)
fucomi %st(1), %st
fstp %st(1)
jbe 0x3854
fstp %st(1)
fld %st(0)
fstpt 0x60(%rsp)
fldz
fstp %st(0)
fldt 0x28(%rsp)
fld %st(0)
fdiv %st(2), %st
fld1
fsubp %st, %st(1)
fmul %st(1), %st
fld %st(0)
fstpt 0xb0(%rsp)
fdivp %st, %st(1)
fxch %st(1)
fstpt 0x10(%rsp)
fstpt (%rsp)
callq 0x2370
fstpt 0x38(%rsp)
movq 0x178(%rbx), %rsi
movq 0x180(%rbx), %rax
cmpq %rax, %rsi
je 0x3a29
fldt 0x28(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3a47
leaq 0xc0(%rsp), %rdx
movq %r15, %rdi
fstpt 0x38(%rsp)
callq 0x8494
fldt 0x38(%rsp)
leaq -0xdda(%rip), %rax      # 0x2af3
movq %rax, 0x168(%rbx)
cmpq $0x1, 0x10(%rbx)
ja 0x3b0a
cmpb $0x0, 0x99b2(%rip)      # 0xd298
jne 0x3b0a
movq 0x96fd(%rip), %r14      # 0xcff0
leaq 0x5bab(%rip), %rsi      # 0x94a5
movl $0x14, %edx
movq %r14, %rdi
fstpt 0x38(%rsp)
callq 0x2270
movq 0x188(%rbx), %rax
movq (%rax), %rsi
movq 0x8(%rax), %rdx
movq %r14, %rdi
callq 0x2270
leaq 0x60(%rsp), %r14
movb $0x3a, (%r14)
movl $0x1, %edx
movq %rax, %rdi
movq %r14, %rsi
callq 0x2270
movl (%rbx), %esi
movq %rax, %rdi
callq 0x2390
movb $0x2d, (%r14)
leaq 0x60(%rsp), %rsi
movl $0x1, %edx
movq %rax, %rdi
callq 0x2270
movl 0x4(%rbx), %esi
movq %rax, %rdi
callq 0x2390
movq %rax, %r14
leaq 0x5b4b(%rip), %rsi      # 0x94ba
movl $0x49, %edx
movq %rax, %rdi
callq 0x2270
leaq 0x5b81(%rip), %rsi      # 0x9504
movl $0x62, %edx
movq %r14, %rdi
callq 0x2270
leaq 0x5bd0(%rip), %rsi      # 0x9567
movl $0x41, %edx
movq %r14, %rdi
callq 0x2270
leaq 0x5bfe(%rip), %rsi      # 0x95a9
movl $0x64, %edx
movq %r14, %rdi
callq 0x2270
movq (%r14), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2200
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2140
fldt 0x38(%rsp)
movb $0x1, 0x98ae(%rip)      # 0xd298
jmp 0x3b0a
fstp %st(0)
leaq 0xc0(%rsp), %rdx
movq %r15, %rdi
callq 0x8494
movq 0x178(%rbx), %rsi
movq 0x180(%rbx), %rax
cmpq %rax, %rsi
je 0x3a62
fldt 0x60(%rsp)
fld %st(0)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3a73
leaq 0xc0(%rsp), %rdx
movq %r15, %rdi
callq 0x8494
movq 0x178(%rbx), %rsi
movq 0x180(%rbx), %rax
cmpq %rax, %rsi
je 0x3a9c
fldt 0xb0(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3aba
leaq 0x60(%rsp), %rdx
movq %r15, %rdi
callq 0x8494
fldt 0x60(%rsp)
fldt 0xc0(%rsp)
fadd %st(1), %st
fdivr %st(1), %st
fxch %st(1)
fstpt 0x10(%rsp)
fstpt (%rsp)
callq 0x2370
leaq -0x1136(%rip), %rax     # 0x295d
movq %rax, 0x168(%rbx)
jmp 0x3b0a
leaq 0xb0(%rsp), %rdx
movq %r15, %rdi
callq 0x8494
movq 0x178(%rbx), %rsi
movq 0x180(%rbx), %rax
cmpq %rax, %rsi
je 0x3ad2
fldt 0x60(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3adf
leaq 0x60(%rsp), %rdx
movq %r15, %rdi
callq 0x8494
fldt 0xb0(%rsp)
fldl 0x5524(%rip)            # 0x9010
fxch %st(1)
fucompi %st(1), %st
fstp %st(0)
jbe 0x3df3
leaq -0x10c4(%rip), %rax     # 0x2a3b
movq %rax, 0x168(%rbx)
fldt 0x38(%rsp)
fld %st(0)
fstpt 0xa0(%rsp)
movl 0x3c(%rbx), %eax
movl (%r12), %r14d
cmpl $-0x1, %r14d
je 0x3b49
movslq 0x154(%rbx), %rcx
cmpq $-0x1, %rcx
je 0x3b53
fstp %st(0)
movq 0x50(%rbx), %rdx
movq %rcx, %rsi
shlq $0x6, %rsi
fldt 0x10(%rdx,%rsi)
fstpt 0xa0(%rsp)
incl %ecx
jmp 0x3b5f
movl 0x160(%rbx), %r14d
decl %r14d
movq 0x50(%rbx), %rcx
fstpt 0x10(%rcx)
movl $0x1, %ecx
movq %r12, 0xd0(%rsp)
movl %ecx, 0x24(%rsp)
cmpl %r14d, %ecx
jg 0x3cdd
movl %eax, %r12d
shrl $0x1f, %r12d
addl %eax, %r12d
sarl %r12d
leaq 0x50(%rbx), %rax
movq %rax, 0x38(%rsp)
movl %r12d, %eax
notl %eax
movq %rax, 0x28(%rsp)
leaq 0x24(%rsp), %r13
leaq 0xa0(%rsp), %rbp
movq %r13, %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq *0x168(%rbx)
fld %st(0)
fstpt 0xa0(%rsp)
movq 0x50(%rbx), %rax
movq 0x58(%rbx), %rsi
movq %rsi, %rcx
subq %rax, %rcx
shrq $0x6, %rcx
movl 0x24(%rsp), %edx
cmpl %ecx, %edx
jne 0x3cbf
fstp %st(0)
movl $0x0, 0x60(%rsp)
fldt 0x54(%rsp)
fld %st(0)
fstpt 0x80(%rsp)
fstpt 0x70(%rsp)
movl $0xffffffff, 0x90(%rsp) # imm = 0xFFFFFFFF
cmpq 0x60(%rbx), %rsi
je 0x3c33
movaps 0x60(%rsp), %xmm0
movaps 0x70(%rsp), %xmm1
movaps 0x80(%rsp), %xmm2
movaps 0x90(%rsp), %xmm3
movaps %xmm3, 0x30(%rsi)
movaps %xmm2, 0x20(%rsi)
movaps %xmm1, 0x10(%rsi)
movaps %xmm0, (%rsi)
addq $0x40, 0x58(%rbx)
jmp 0x3c46
movq 0x38(%rsp), %rdi
leaq 0x60(%rsp), %rdx
callq 0x7e82
movl 0x24(%rsp), %ecx
movl 0x3c(%rbx), %edx
movl %ecx, %esi
movq 0x50(%rbx), %rax
subl %edx, %esi
jge 0x3c79
decl %edx
cmpl %ecx, %edx
jne 0x3cb4
testl %ecx, %ecx
js 0x3ca4
movl %ecx, %ecx
shlq $0x6, %rcx
addq $0x40, %rcx
xorl %esi, %esi
xorl %edx, %edx
addl (%rax,%rsi), %edx
addq $0x40, %rsi
cmpq %rsi, %rcx
jne 0x3c6b
jmp 0x3ca6
movq 0x28(%rsp), %rdx
addl %ecx, %edx
movslq %edx, %rdx
shlq $0x6, %rdx
movl 0x30(%rax,%rdx), %edx
movslq %esi, %rsi
shlq $0x6, %rsi
subl (%rax,%rsi), %edx
movslq %ecx, %rsi
shlq $0x6, %rsi
addl (%rax,%rsi), %edx
subl %r12d, %ecx
jmp 0x3ca9
xorl %edx, %edx
movl %r12d, %ecx
movslq %ecx, %rcx
shlq $0x6, %rcx
movl %edx, 0x30(%rax,%rcx)
fldt 0xa0(%rsp)
movl 0x24(%rsp), %edx
movslq %edx, %rdx
movq %rdx, %rcx
shlq $0x6, %rcx
fstpt 0x10(%rax,%rcx)
leal 0x1(%rdx), %ecx
movl %ecx, 0x24(%rsp)
cmpl %r14d, %edx
jl 0x3ba1
leal -0x1(%rcx), %eax
movl %eax, 0x24(%rsp)
fld1
fstpt 0x60(%rsp)
movq 0x168(%rbx), %rax
leaq 0x48(%rsp), %rdi
movl %ecx, (%rdi)
leaq 0x60(%rsp), %rsi
movq %r15, %rdx
callq *%rax
fld1
fldl 0x531e(%rip)            # 0x9028
fxch %st(2)
fucomi %st(2), %st
jbe 0x3d62
fstp %st(1)
fld1
leaq 0x48(%rsp), %r14
leaq 0x60(%rsp), %r12
fxch %st(2)
fstpt 0x28(%rsp)
fldz
fxch %st(2)
fxch %st(1)
fstp %st(2)
fadd %st(1), %st
fstpt 0x54(%rsp)
fstpt 0x60(%rsp)
movq 0x168(%rbx), %rax
incl 0x48(%rsp)
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq *%rax
fldt 0x28(%rsp)
fldt 0x54(%rsp)
fxch %st(2)
fucomi %st(1), %st
fstp %st(1)
fldz
fxch %st(2)
fxch %st(1)
ja 0x3d2a
fstp %st(0)
fstp %st(1)
movslq 0x24(%rsp), %rax
movq %rax, %rdx
shlq $0x6, %rdx
movq 0x50(%rbx), %rcx
fldt 0x10(%rcx,%rdx)
fmulp %st, %st(1)
fstpt 0x20(%rcx,%rdx)
cmpq $0x2, %rax
fldz
jl 0x3dae
fstp %st(0)
fldt 0x20(%rdx,%rcx)
incq %rax
addq %rcx, %rdx
addq $-0x20, %rdx
fldt -0x10(%rdx)
faddp %st, %st(1)
fld %st(0)
fstpt (%rdx)
decq %rax
addq $-0x40, %rdx
cmpq $0x2, %rax
ja 0x3d98
fstp %st(0)
fld1
fstpt 0x20(%rcx)
movq 0xd0(%rsp), %rax
movl (%rax), %eax
movl 0x160(%rbx), %ecx
decl %ecx
cmpl $-0x1, %eax
cmovnel %eax, %ecx
movl %ecx, 0x154(%rbx)
movaps 0x10(%rbx), %xmm0
movups %xmm0, 0x28(%rbx)
movl 0x20(%rbx), %eax
movl %eax, 0x38(%rbx)
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq $0x0, 0x168(%rbx)
jmp 0x3de1