// File: /workspace/github_cpp_makefile_star2_O1/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 0x36fe
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 -0xbaa(%rip), %rax      # 0x2b08
movq %rax, 0x168(%rbx)
movq 0x170(%rbx), %rax
cmpq %rax, 0x178(%rbx)
je 0x36d0
movq %rax, 0x178(%rbx)
fldz
fld %st(0)
fstpt 0x50(%rsp)
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x380e
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3e1f
movq %rsi, %r12
movslq 0x20(%rbx), %rax
movl %eax, 0x3c(%rsp)
fildl 0x3c(%rsp)
movq 0x10(%rbx), %rcx
movq %rcx, 0xd8(%rsp)
fildll 0xd8(%rsp)
fdiv %st(1), %st
fld %st(0)
fstpt 0x40(%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 0x94(%rsp)
faddp %st, %st(4)
fxch %st(1)
fdivp %st, %st(3)
fld %st(2)
fstpt 0xb0(%rsp)
movq 0x170(%rbx), %rsi
cmpq %rsi, 0x178(%rbx)
je 0x377a
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 0x37d2
fstp %st(2)
fstp %st(0)
fstpt (%rsp)
callq 0x2060
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x38ca
fldt 0x40(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x38df
fstp %st(0)
fxch %st(1)
fucomi %st(1), %st
fld %st(1)
fmul %st(2), %st
jbe 0x3829
fxch %st(1)
fsub %st(2), %st
fdivrp %st, %st(1)
fstpt 0x50(%rsp)
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x3a08
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3a17
fstp %st(0)
addq $0x170, %rbx            # imm = 0x170
leaq 0x50(%rsp), %rdx
movq %rbx, %rdi
callq 0x8014
jmp 0x3e1f
fld %st(2)
fstpt 0x28(%rsp)
fxch %st(2)
fsubp %st, %st(1)
fdivrp %st, %st(1)
fadds 0x57c9(%rip)            # 0x9004
fstpt (%rsp)
callq 0x20f0
fld %st(0)
fstpt 0x50(%rsp)
movl 0x110(%rbx), %eax
movl %eax, 0x38(%rsp)
fildl 0x38(%rsp)
fxch %st(1)
faddl 0x57c1(%rip)            # 0x9020
fxch %st(1)
fucomi %st(1), %st
fstp %st(1)
jbe 0x386d
fstpt 0x50(%rsp)
fldz
fstp %st(0)
fldt 0x50(%rsp)
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
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
fld %st(0)
fstpt 0x28(%rsp)
je 0x3a3a
fldt 0x40(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3a4d
leaq 0x40(%rsp), %rdx
movq %r15, %rdi
fstpt 0x28(%rsp)
callq 0x8152
fldt 0x28(%rsp)
leaq -0xdde(%rip), %rax      # 0x2b08
movq %rax, 0x168(%rbx)
cmpq $0x1, 0x10(%rbx)
ja 0x3b23
cmpb $0x0, 0x9999(%rip)      # 0xd298
jne 0x3b23
movq 0x96e4(%rip), %r14      # 0xcff0
leaq 0x5b62(%rip), %rsi      # 0x9475
movl $0x14, %edx
movq %r14, %rdi
fstpt 0x28(%rsp)
callq 0x2270
movq 0x188(%rbx), %rax
movq (%rax), %rsi
movq 0x8(%rax), %rdx
movq %r14, %rdi
callq 0x2270
leaq 0x50(%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 0x50(%rsp), %rsi
movl $0x1, %edx
movq %rax, %rdi
callq 0x2270
movl 0x4(%rbx), %esi
movq %rax, %rdi
callq 0x2390
movq %rax, %r14
leaq 0x5b02(%rip), %rsi      # 0x948a
movl $0x49, %edx
movq %rax, %rdi
callq 0x2270
leaq 0x5b38(%rip), %rsi      # 0x94d4
movl $0x62, %edx
movq %r14, %rdi
callq 0x2270
leaq 0x5b87(%rip), %rsi      # 0x9537
movl $0x41, %edx
movq %r14, %rdi
callq 0x2270
leaq 0x5bb5(%rip), %rsi      # 0x9579
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 0x28(%rsp)
movb $0x1, 0x9895(%rip)      # 0xd298
jmp 0x3b23
fstp %st(0)
leaq 0x40(%rsp), %rdx
movq %r15, %rdi
callq 0x8152
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x3a73
fldt 0x50(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3a80
fstp %st(0)
leaq 0x40(%rsp), %rdx
movq %r15, %rdi
callq 0x8152
fldt 0x28(%rsp)
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x3aaa
fldt 0xb0(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3ac0
leaq 0x50(%rsp), %rdx
movq %r15, %rdi
callq 0x8152
fldt 0x50(%rsp)
fldt 0x40(%rsp)
fadd %st(1), %st
fdivr %st(1), %st
fxch %st(1)
fstpt 0x10(%rsp)
fstpt (%rsp)
callq 0x2370
leaq -0x112f(%rip), %rax     # 0x2972
movq %rax, 0x168(%rbx)
jmp 0x3b23
fstp %st(0)
leaq 0xb0(%rsp), %rdx
movq %r15, %rdi
callq 0x8152
fldt 0x28(%rsp)
movq 0x178(%rbx), %rsi
cmpq 0x180(%rbx), %rsi
je 0x3ae3
fldt 0x50(%rsp)
fstpt (%rsi)
addq $0x10, %rsi
movq %rsi, 0x178(%rbx)
jmp 0x3af6
fstp %st(0)
leaq 0x50(%rsp), %rdx
movq %r15, %rdi
callq 0x8152
fldt 0x28(%rsp)
fldt 0xb0(%rsp)
xorl %eax, %eax
fldl 0x550b(%rip)            # 0x9010
fxch %st(1)
fucompi %st(1), %st
fstp %st(0)
leaq -0x10c2(%rip), %rcx     # 0x2a50
cmovaq %rcx, %rax
movq %rax, 0x168(%rbx)
jbe 0x3e1d
fld %st(0)
fstpt 0xa0(%rsp)
movl 0x3c(%rbx), %eax
movl (%r12), %r14d
cmpl $-0x1, %r14d
je 0x3b62
movslq 0x154(%rbx), %rcx
cmpq $-0x1, %rcx
je 0x3b6c
fstp %st(0)
movq 0x50(%rbx), %rdx
movq %rcx, %rsi
shlq $0x6, %rsi
fldt 0x10(%rdx,%rsi)
fstpt 0xa0(%rsp)
incl %ecx
jmp 0x3b78
movl 0x160(%rbx), %r14d
decl %r14d
movq 0x50(%rbx), %rcx
fstpt 0x10(%rcx)
movl $0x1, %ecx
movq %r12, 0xc0(%rsp)
movl %ecx, 0x24(%rsp)
cmpl %r14d, %ecx
jg 0x3d08
movl %eax, %ecx
shrl $0x1f, %ecx
addl %eax, %ecx
sarl %ecx
leaq 0x50(%rbx), %r12
movl %ecx, %eax
notl %eax
movq %rax, 0xd0(%rsp)
movl %ecx, 0x28(%rsp)
movslq %ecx, %rax
leaq 0x24(%rsp), %r13
leaq 0xa0(%rsp), %rbp
shlq $0x6, %rax
movq %rax, 0xc8(%rsp)
movq %r13, %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq *0x168(%rbx)
fstpt 0xa0(%rsp)
movq 0x58(%rbx), %rsi
movq %rsi, %rax
subq 0x50(%rbx), %rax
shrq $0x6, %rax
cmpl %eax, 0x24(%rsp)
jne 0x3cdd
movl $0x0, 0x50(%rsp)
fldt 0x94(%rsp)
fld %st(0)
fstpt 0x70(%rsp)
fstpt 0x60(%rsp)
movl $0xffffffff, 0x80(%rsp) # imm = 0xFFFFFFFF
cmpq 0x60(%rbx), %rsi
je 0x3c4c
movaps 0x50(%rsp), %xmm0
movaps 0x60(%rsp), %xmm1
movaps 0x70(%rsp), %xmm2
movaps 0x80(%rsp), %xmm3
movaps %xmm3, 0x30(%rsi)
movaps %xmm2, 0x20(%rsi)
movaps %xmm1, 0x10(%rsi)
movaps %xmm0, (%rsi)
addq $0x40, 0x58(%rbx)
jmp 0x3c59
movq %r12, %rdi
leaq 0x50(%rsp), %rdx
callq 0x7b3e
movl 0x24(%rsp), %eax
movl 0x3c(%rbx), %edx
movl %eax, %ecx
subl %edx, %ecx
jge 0x3c8e
decl %edx
cmpl %eax, %edx
jne 0x3cdd
testl %eax, %eax
js 0x3ccb
movq (%r12), %rcx
shlq $0x6, %rax
addq $0x40, %rax
xorl %esi, %esi
xorl %edx, %edx
addl (%rcx,%rsi), %edx
addq $0x40, %rsi
cmpq %rsi, %rax
jne 0x3c80
jmp 0x3ccd
movq 0xd0(%rsp), %rdx
addl %eax, %edx
movslq %edx, %rdx
movq (%r12), %rsi
shlq $0x6, %rdx
movl 0x30(%rsi,%rdx), %edx
movslq %ecx, %rcx
shlq $0x6, %rcx
subl (%rsi,%rcx), %edx
movslq %eax, %rcx
shlq $0x6, %rcx
addl (%rsi,%rcx), %edx
subl 0x28(%rsp), %eax
cltq
shlq $0x6, %rax
movl %edx, 0x30(%rsi,%rax)
jmp 0x3cdd
xorl %edx, %edx
movq (%r12), %rax
movq 0xc8(%rsp), %rcx
movl %edx, 0x30(%rax,%rcx)
fldt 0xa0(%rsp)
movslq 0x24(%rsp), %rax
movq (%r12), %rcx
movq %rax, %rdx
shlq $0x6, %rdx
fstpt 0x10(%rcx,%rdx)
leal 0x1(%rax), %ecx
movl %ecx, 0x24(%rsp)
cmpl %r14d, %eax
jl 0x3bc6
leal -0x1(%rcx), %eax
movl %eax, 0x24(%rsp)
leaq 0x34(%rsp), %rdi
movl %eax, (%rdi)
fld1
fstpt 0x50(%rsp)
movq 0x168(%rbx), %rax
movl %ecx, (%rdi)
leaq 0x50(%rsp), %rsi
movq %r15, %rdx
callq *%rax
fld1
fldl 0x52f1(%rip)            # 0x9028
fxch %st(2)
fucomi %st(2), %st
jbe 0x3d95
fstp %st(1)
fld1
leaq 0x34(%rsp), %r14
leaq 0x50(%rsp), %r12
fxch %st(2)
fstpt 0x28(%rsp)
fldz
fxch %st(2)
fxch %st(1)
fstp %st(2)
fadd %st(1), %st
fstpt 0x94(%rsp)
fstpt 0x50(%rsp)
movq 0x168(%rbx), %rax
incl 0x34(%rsp)
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq *%rax
fldt 0x28(%rsp)
fldt 0x94(%rsp)
fxch %st(2)
fucomi %st(1), %st
fstp %st(1)
fldz
fxch %st(2)
fxch %st(1)
ja 0x3d57
fstp %st(0)
fstp %st(1)
movslq 0x24(%rsp), %rcx
movq 0x50(%rbx), %rax
shlq $0x6, %rcx
fldt 0x10(%rax,%rcx)
fmulp %st, %st(1)
fstpt 0x20(%rax,%rcx)
movslq 0x24(%rsp), %rcx
cmpq $0x2, %rcx
movq 0xc0(%rsp), %rdi
jl 0x3df2
leaq 0x1(%rcx), %rdx
movq %rcx, %rsi
shlq $0x6, %rsi
addq %rax, %rsi
addq $-0x30, %rsi
fldt (%rsi)
fldt 0x50(%rsi)
faddp %st, %st(1)
fstpt 0x10(%rsi)
decq %rdx
addq $-0x40, %rsi
decl %ecx
cmpq $0x2, %rdx
jg 0x3dd5
movl %ecx, 0x24(%rsp)
fld1
fstpt 0x20(%rax)
movl (%rdi), %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)
fldz
fstp %st(0)
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop