// File: /workspace/github_cpp_makefile_star2_O2/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 $0xf8, %rsp
movq %rdi, %rbx
cmpl $0x1, 0x160(%rdi)
jne 0x32dd
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)
andl $0x0, 0x154(%rbx)
leaq -0xa84(%rip), %rax      # 0x2819
movq %rax, 0x168(%rbx)
leaq 0x170(%rbx), %rdi
movq 0x170(%rbx), %rax
cmpq %rax, 0x178(%rbx)
je 0x32c2
movq %rax, 0x178(%rbx)
fldz
fstpt 0xb0(%rsp)
leaq 0xb0(%rsp), %rsi
callq 0x73a0
jmp 0x3803
movq %rsi, %r14
movslq 0x20(%rbx), %rax
movl %eax, 0x4c(%rsp)
fildl 0x4c(%rsp)
movq 0x10(%rbx), %rcx
movq %rcx, 0xa0(%rsp)
fildll 0xa0(%rsp)
fdiv %st(1), %st
fld %st(0)
fstpt 0x60(%rsp)
movq 0x18(%rbx), %rdx
movq %rdx, 0xa8(%rsp)
fildll 0xa8(%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 0x3c(%rsp)
faddp %st, %st(4)
fxch %st(1)
fdivp %st, %st(3)
fld %st(2)
fstpt 0x70(%rsp)
movq 0x170(%rbx), %rsi
cmpq %rsi, 0x178(%rbx)
je 0x3353
movq %rsi, 0x178(%rbx)
leaq 0x170(%rbx), %r15
imulq %rax, %rdx
movq %rcx, %rsi
imulq %rcx, %rsi
subq %rsi, %rdx
decl %eax
cltq
imulq %rcx, %rax
cmpq %rax, %rdx
jne 0x3459
fstp %st(2)
fstp %st(0)
fstpt (%rsp)
callq 0x2050
fstpt 0x2c(%rsp)
leaq 0x60(%rsp), %rsi
movq %r15, %rdi
callq 0x5e22
leaq -0xb84(%rip), %rax      # 0x2819
movq %rax, 0x168(%rbx)
cmpq $0x1, 0x10(%rbx)
ja 0x3589
cmpb $0x0, 0x8ec2(%rip)      # 0xc278
jne 0x3589
movq 0x8c2d(%rip), %rdi      # 0xbff0
leaq 0x50bb(%rip), %rsi      # 0x8485
callq 0x21e0
movq 0x188(%rbx), %rsi
movq %rax, %rdi
callq 0x21c0
pushq $0x3a
popq %rsi
movq %rax, %rdi
callq 0x2260
movl (%rbx), %esi
movq %rax, %rdi
callq 0x2340
pushq $0x2d
popq %rsi
movq %rax, %rdi
callq 0x2260
movl 0x4(%rbx), %esi
movq %rax, %rdi
callq 0x2340
leaq 0x508a(%rip), %rsi      # 0x849a
movq %rax, %rdi
callq 0x21e0
leaq 0x50c5(%rip), %rsi      # 0x84e4
movq %rax, %rdi
callq 0x21e0
leaq 0x5119(%rip), %rsi      # 0x8547
movq %rax, %rdi
callq 0x21e0
leaq 0x514c(%rip), %rsi      # 0x8589
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20e0
movb $0x1, 0x8e24(%rip)      # 0xc278
jmp 0x3589
fstp %st(0)
fxch %st(1)
fucomi %st(1), %st
fld %st(1)
fmul %st(2), %st
jbe 0x34c3
fxch %st(1)
fsubp %st, %st(2)
fdivp %st, %st(1)
fstpt 0xb0(%rsp)
leaq 0x60(%rsp), %rsi
movq %r15, %rdi
callq 0x5e22
leaq 0xb0(%rsp), %rsi
movq %r15, %rdi
callq 0x5e22
fldt 0xb0(%rsp)
fldt 0x60(%rsp)
fadd %st(1), %st
fdivr %st(1), %st
fxch %st(1)
fstpt 0x10(%rsp)
fstpt (%rsp)
callq 0x2330
leaq -0xe2c(%rip), %rax      # 0x2687
movq %rax, 0x168(%rbx)
fld1
fxch %st(1)
jmp 0x358f
fld %st(2)
fstpt 0x2c(%rsp)
fxch %st(2)
fsubp %st, %st(1)
fdivrp %st, %st(1)
fadds 0x4b2f(%rip)            # 0x8004
fstpt (%rsp)
callq 0x20f0
fld %st(0)
fstpt 0xb0(%rsp)
movl 0x110(%rbx), %eax
movl %eax, 0x48(%rsp)
fildl 0x48(%rsp)
fld %st(1)
faddl 0x4b24(%rip)            # 0x8020
fxch %st(1)
fucomi %st(1), %st
fstp %st(1)
jbe 0x3511
fstp %st(1)
fld %st(0)
fstpt 0xb0(%rsp)
fldz
fstp %st(0)
fldt 0x2c(%rsp)
fld %st(0)
fdiv %st(2), %st
fld1
fsubp %st, %st(1)
fmul %st(1), %st
fld %st(0)
fstpt 0x70(%rsp)
fdivp %st, %st(1)
fxch %st(1)
fstpt 0x10(%rsp)
fstpt (%rsp)
callq 0x2330
fstpt 0x2c(%rsp)
leaq 0x60(%rsp), %rsi
movq %r15, %rdi
callq 0x5e22
leaq 0x70(%rsp), %rsi
movq %r15, %rdi
callq 0x5e22
leaq 0xb0(%rsp), %rsi
movq %r15, %rdi
callq 0x5e22
fldt 0x70(%rsp)
fldl 0x4aa1(%rip)            # 0x8010
fxch %st(1)
fucompi %st(1), %st
fstp %st(0)
jbe 0x3815
leaq -0xe1f(%rip), %rax      # 0x2763
movq %rax, 0x168(%rbx)
fld1
fldt 0x2c(%rsp)
fld %st(0)
fstpt 0x50(%rsp)
movl 0x3c(%rbx), %eax
pushq $0x2
popq %rcx
cltd
idivl %ecx
movl %eax, 0x2c(%rsp)
movl (%r14), %ebp
cmpl $-0x1, %ebp
movq %r14, 0x88(%rsp)
je 0x35d8
movslq 0x154(%rbx), %rax
cmpq $-0x1, %rax
je 0x35e0
fstp %st(0)
movq 0x50(%rbx), %rcx
movq %rax, %rdx
shlq $0x6, %rdx
fldt 0x10(%rcx,%rdx)
fstpt 0x50(%rsp)
incl %eax
jmp 0x35ea
movl 0x160(%rbx), %ebp
decl %ebp
movq 0x50(%rbx), %rax
fstpt 0x10(%rax)
pushq $0x1
popq %rax
leaq 0x50(%rbx), %r12
movl 0x2c(%rsp), %ecx
movl %ecx, %edx
notl %edx
movq %rdx, 0x98(%rsp)
movslq %ecx, %rcx
leaq 0x28(%rsp), %r13
leaq 0x50(%rsp), %r14
shlq $0x6, %rcx
movq %rcx, 0x90(%rsp)
movl %eax, 0x28(%rsp)
cmpl %ebp, %eax
jg 0x3727
fstp %st(0)
movq %r13, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq *0x168(%rbx)
fld %st(0)
fstpt 0x50(%rsp)
movq 0x50(%rbx), %rcx
movq 0x58(%rbx), %rdx
subq %rcx, %rdx
shrq $0x6, %rdx
movl 0x28(%rsp), %eax
cmpl %edx, %eax
jne 0x3711
fstp %st(0)
andl $0x0, 0xb0(%rsp)
fldt 0x3c(%rsp)
fld %st(0)
fstpt 0xd0(%rsp)
fstpt 0xc0(%rsp)
orl $-0x1, 0xe0(%rsp)
movq %r12, %rdi
leaq 0xb0(%rsp), %rsi
callq 0x5dc4
movslq 0x28(%rsp), %rax
movl 0x3c(%rbx), %ecx
cmpl %ecx, %eax
jge 0x36b8
decl %ecx
cmpl %eax, %ecx
jne 0x3705
movq (%r12), %rcx
xorl %edx, %edx
movq %rcx, %rsi
xorl %edi, %edi
cmpq %rax, %rdx
jg 0x36f9
addl (%rsi), %edi
incq %rdx
addq $0x40, %rsi
jmp 0x36a8
movq 0x98(%rsp), %rdx
addl %eax, %edx
movslq %edx, %rdx
movq (%r12), %rsi
shlq $0x6, %rdx
movl 0x30(%rsi,%rdx), %edx
movl %eax, %edi
subl %ecx, %edi
movslq %edi, %rcx
shlq $0x6, %rcx
subl (%rsi,%rcx), %edx
movq %rax, %rcx
shlq $0x6, %rcx
addl (%rsi,%rcx), %edx
subl 0x2c(%rsp), %eax
cltq
shlq $0x6, %rax
movl %edx, 0x30(%rsi,%rax)
jmp 0x3705
movq 0x90(%rsp), %rax
movl %edi, 0x30(%rcx,%rax)
fldt 0x50(%rsp)
movl 0x28(%rsp), %eax
movq (%r12), %rcx
cltq
movq %rax, %rdx
shlq $0x6, %rdx
fstpt 0x10(%rcx,%rdx)
incl %eax
fld1
jmp 0x3617
decl %eax
movl %eax, 0x28(%rsp)
leaq 0x38(%rsp), %r14
leaq 0xb0(%rsp), %r13
fldl 0x48e8(%rip)            # 0x8028
fstpt 0x2c(%rsp)
fld %st(0)
fstpt 0x3c(%rsp)
fstpt 0xb0(%rsp)
movq 0x168(%rbx), %rcx
incl %eax
movl %eax, 0x38(%rsp)
movq %r14, %rdi
movq %r13, %rsi
movq %r15, %rdx
callq *%rcx
fldt 0x2c(%rsp)
fxch %st(1)
fucomi %st(1), %st
fstp %st(1)
jbe 0x3785
fldt 0x3c(%rsp)
fadd %st(1), %st
fstpt 0x3c(%rsp)
movl 0x38(%rsp), %eax
jmp 0x374a
fstp %st(0)
movl 0x28(%rsp), %eax
movslq %eax, %rdx
movq (%r12), %rcx
movq %rdx, %rsi
shlq $0x6, %rsi
fldt 0x10(%rcx,%rsi)
fldt 0x3c(%rsp)
fmulp %st, %st(1)
fstpt 0x20(%rcx,%rsi)
movq %rax, %rsi
shlq $0x6, %rsi
leaq 0x20(%rcx), %rdi
decl %edx
shlq $0x6, %rdx
movq 0x88(%rsp), %r8
cmpl $0x2, %eax
jl 0x37d9
fldt -0x10(%rdi,%rdx)
fldt (%rdi,%rsi)
faddp %st, %st(1)
fstpt (%rdi,%rdx)
addq $-0x40, %rdi
decl %eax
jmp 0x37c0
fld1
fstpt 0x20(%rcx)
movl (%r8), %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 $0xf8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
andq $0x0, 0x168(%rbx)
jmp 0x3803
nop