// File: /workspace/github_cpp_makefile_star2_O1/redpony[P]cpyp/crp_test.cc
// Function: test_mfcrp()
void test_mfcrp() {
  vector<double> ref_up = {0.0152302, 0.0754287, 0.153957, 0.209485, 0.213071, 0.16726, 0.101233, 0.0460308, 0.0149256, 0.003075, 0.00030408};
  vector<double> ref_down = {0.185252, 0.32385, 0.271888, 0.145849, 0.0548223, 0.0149361, 0.00294062, 0.0004185, 4.074e-05, 2.3e-06, 4e-08};

  cpyp::MT19937 eng;
  long double p0[2]{1.0,1.0}; // pa(0), pb(0)
  double lam[2]{0.3,0.7};
  vector<double> hist_upstairs(11, 0);
  vector<double> hist_downstairs(11, 0);
  int c = 0;
  for (int n = 0; n < 200000; ++n) {
    cpyp::mf_crp<2, unsigned> crp(0.5, 1.0);
    int upstairs = 0;
    int downstairs = 0;
    for (int i = 0; i < 10; ++i) {
      unsigned obs = 0;
      pair<unsigned, int> floor_count = crp.increment(obs, p0, lam, eng);
      if (floor_count.second) (floor_count.first ? upstairs : downstairs)++;
    }
    // resample some stuff
    for (int j = 0; j < 4; ++j) {
      for (int i = 0; i < 10; ++i) {
        unsigned obs = 0;
        pair<unsigned, int> floor_count = crp.decrement(obs, eng);
        if (floor_count.second) (floor_count.first ? upstairs : downstairs)--;
        floor_count = crp.increment(obs, p0, lam, eng);
        if (floor_count.second) (floor_count.first ? upstairs : downstairs)++;
      }
    }
    hist_downstairs[downstairs] += 1.0;
    hist_upstairs[upstairs] += 1.0;
    ++c;
  }
  cerr << "Upstairs:\n";
  int j = 0;
  double max_up = 0;
  double tot_up = 0;
  for (auto& d : hist_upstairs) {
    double diff = d / c - ref_up[j++];
    cerr << diff << endl;
    if (fabs(diff) > max_up) max_up = fabs(diff);
    tot_up += fabs(diff);
  }
  if (max_up > 0.01) { cerr << "** TOO BIG "; }
  cerr << "max_up=" << max_up << endl;
  tot_up /= 11;
  if (tot_up > 0.005) { cerr << "*** TOO BIG "; }
  cerr << "avg_up=" << tot_up << endl;
  cerr << "Downstairs:\n";
  j = 0;
  double tot_down = 0;
  double max_down = 0;
  for (auto& d : hist_downstairs) {
    double diff = (d / c - ref_down[j++]);
    cerr << diff << endl;
    if (fabs(diff) > max_down) max_down = fabs(diff);
    tot_down += fabs(diff);
  }
  if (max_down > 0.01) { cerr << "** TOO BIG "; }
  cerr << "max_down=" << max_down << endl;
  tot_down /= 11;
  if (tot_down > 0.005) { cerr << "*** TOO BIG "; }
  cerr << "avg_down=" << tot_down << endl;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x14a8, %rsp           # imm = 0x14A8
leaq 0x638a(%rip), %rsi      # 0xa328
leaq 0x120(%rsp), %rax
movl $0xb, %ecx
movq %rax, %rdi
rep  movsq (%rsi), %es:(%rdi)
leaq 0x68(%rsp), %rdi
leaq 0xa8(%rsp), %rcx
movl $0xb, %edx
movq %rax, %rsi
callq 0x4ca0
leaq 0x63ae(%rip), %rsi      # 0xa380
leaq 0x120(%rsp), %rax
movl $0xb, %ecx
movq %rax, %rdi
rep  movsq (%rsi), %es:(%rdi)
leaq 0x50(%rsp), %rdi
leaq 0xa8(%rsp), %rcx
movl $0xb, %edx
movq %rax, %rsi
callq 0x4ca0
leaq 0x120(%rsp), %rdi
callq 0x4c22
movaps 0x6b2d(%rip), %xmm0     # 0xab40
movaps %xmm0, 0x90(%rsp)
movaps 0x6b0e(%rip), %xmm0     # 0xab30
movaps %xmm0, 0x80(%rsp)
movapd 0x60ee(%rip), %xmm0     # 0xa120
movapd %xmm0, 0x40(%rsp)
movl $0x58, %edi
callq 0x21b0
xorpd %xmm0, %xmm0
movupd %xmm0, 0x40(%rax)
movupd %xmm0, 0x30(%rax)
movupd %xmm0, 0x20(%rax)
movupd %xmm0, 0x10(%rax)
movupd %xmm0, (%rax)
movq %rax, 0x38(%rsp)
movq $0x0, 0x50(%rax)
movl $0x58, %edi
callq 0x21b0
xorpd %xmm0, %xmm0
movupd %xmm0, 0x40(%rax)
movupd %xmm0, 0x30(%rax)
movupd %xmm0, 0x20(%rax)
movupd %xmm0, 0x10(%rax)
movupd %xmm0, (%rax)
movq %rax, 0x30(%rsp)
movq $0x0, 0x50(%rax)
xorl %r14d, %r14d
leaq 0xa8(%rsp), %r12
movsd 0x5f5f(%rip), %xmm1     # 0xa010
leaq 0xc(%rsp), %r13
leaq 0x120(%rsp), %rbx
movq %r14, 0x10(%rsp)
movq %r12, %rdi
movsd 0x5f3a(%rip), %xmm0     # 0xa008
callq 0x5242
xorl %r14d, %r14d
movl $0xa, %r15d
xorl %ebp, %ebp
movl $0x0, 0xc(%rsp)
movq %r12, %rdi
movq %r13, %rsi
leaq 0x80(%rsp), %rdx
leaq 0x40(%rsp), %rcx
movq %rbx, %r8
callq 0x52ac
movq %rax, %rcx
shrq $0x20, %rcx
je 0x411d
testl %eax, %eax
movl %r14d, %ecx
cmovel %ebp, %ecx
incl %ecx
testl %eax, %eax
cmovel %ecx, %ebp
cmovnel %ecx, %r14d
decl %r15d
jne 0x40de
xorl %eax, %eax
movl %eax, (%rsp)
movl $0xa, %r15d
movl $0x0, 0xc(%rsp)
movq %r12, %rdi
movq %r13, %rsi
movq %rbx, %rdx
xorl %ecx, %ecx
callq 0x54fc
movq %rax, %rcx
shrq $0x20, %rcx
je 0x4161
testl %eax, %eax
movl %r14d, %ecx
cmovel %ebp, %ecx
decl %ecx
testl %eax, %eax
cmovel %ecx, %ebp
cmovnel %ecx, %r14d
movq %r12, %rdi
movq %r13, %rsi
leaq 0x80(%rsp), %rdx
leaq 0x40(%rsp), %rcx
movq %rbx, %r8
callq 0x52ac
movq %rax, %rcx
shrq $0x20, %rcx
je 0x4198
testl %eax, %eax
movl %r14d, %ecx
cmovel %ebp, %ecx
incl %ecx
testl %eax, %eax
cmovel %ecx, %ebp
cmovnel %ecx, %r14d
decl %r15d
jne 0x412d
movl (%rsp), %eax
incl %eax
cmpl $0x4, %eax
jne 0x4124
movslq %ebp, %rax
movq 0x30(%rsp), %rcx
movsd (%rcx,%rax,8), %xmm0
movsd 0x5e50(%rip), %xmm1     # 0xa010
addsd %xmm1, %xmm0
movsd %xmm0, (%rcx,%rax,8)
movslq %r14d, %rax
movq 0x38(%rsp), %rcx
movsd (%rcx,%rax,8), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rcx,%rax,8)
movq 0x10(%rsp), %r14
incl %r14d
leaq 0xb0(%rsp), %rdi
callq 0x5d3e
movsd 0x5e14(%rip), %xmm1     # 0xa010
cmpl $0x30d40, %r14d         # imm = 0x30D40
jne 0x40be
movq 0x9de0(%rip), %rdi      # 0xdff0
leaq 0x6266(%rip), %rsi      # 0xa47d
movl $0xa, %edx
callq 0x21c0
xorpd %xmm0, %xmm0
movsd %xmm0, (%rsp)
xorl %r14d, %r14d
movq 0x9dbc(%rip), %rbx      # 0xdff0
movsd %xmm0, 0x28(%rsp)
movq 0x38(%rsp), %rax
movsd (%rax,%r14), %xmm0
divsd 0x5df3(%rip), %xmm0     # 0xa040
movq 0x68(%rsp), %rax
subsd (%rax,%r14), %xmm0
movq %rbx, %rdi
movapd %xmm0, 0x10(%rsp)
callq 0x2230
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2190
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2100
movapd 0x10(%rsp), %xmm1
andpd 0x5e02(%rip), %xmm1     # 0xa0a0
movsd (%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rsp)
maxsd 0x28(%rsp), %xmm1
addq $0x8, %r14
movapd %xmm1, %xmm0
cmpq $0x58, %r14
jne 0x4234
movapd %xmm1, 0x10(%rsp)
ucomisd 0x5d4e(%rip), %xmm1     # 0xa020
jbe 0x42ec
movq 0x9d15(%rip), %rdi      # 0xdff0
leaq 0x61af(%rip), %rsi      # 0xa491
movl $0xb, %edx
callq 0x21c0
movq 0x9cfd(%rip), %rdi      # 0xdff0
leaq 0x618e(%rip), %rsi      # 0xa488
movl $0x7, %edx
callq 0x21c0
movq 0x9ce5(%rip), %rdi      # 0xdff0
movapd 0x10(%rsp), %xmm0
callq 0x2230
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2190
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2100
movsd (%rsp), %xmm0
divsd 0x5cfb(%rip), %xmm0     # 0xa048
movsd %xmm0, (%rsp)
ucomisd 0x5cf6(%rip), %xmm0     # 0xa050
jbe 0x4374
movq 0x9c8d(%rip), %rdi      # 0xdff0
leaq 0x6126(%rip), %rsi      # 0xa490
movl $0xc, %edx
callq 0x21c0
movq 0x9c75(%rip), %rdi      # 0xdff0
leaq 0x611b(%rip), %rsi      # 0xa49d
movl $0x7, %edx
callq 0x21c0
movq 0x9c5d(%rip), %rdi      # 0xdff0
movsd (%rsp), %xmm0
callq 0x2230
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2190
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2100
movq 0x9c22(%rip), %rdi      # 0xdff0
leaq 0x60d0(%rip), %rsi      # 0xa4a5
movl $0xc, %edx
callq 0x21c0
xorpd %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
xorl %r14d, %r14d
movq 0x9bfd(%rip), %rbx      # 0xdff0
movsd %xmm0, (%rsp)
movq 0x30(%rsp), %rax
movsd (%rax,%r14), %xmm0
divsd 0x5c35(%rip), %xmm0     # 0xa040
movq 0x50(%rsp), %rax
subsd (%rax,%r14), %xmm0
movq %rbx, %rdi
movapd %xmm0, 0x10(%rsp)
callq 0x2230
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2190
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2100
movapd 0x10(%rsp), %xmm1
andpd 0x5c44(%rip), %xmm1     # 0xa0a0
movsd (%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rsp)
maxsd 0x28(%rsp), %xmm1
addq $0x8, %r14
movsd %xmm1, 0x28(%rsp)
cmpq $0x58, %r14
jne 0x43f8
movapd %xmm1, 0x10(%rsp)
ucomisd 0x5b8e(%rip), %xmm1     # 0xa020
jbe 0x44ac
movq 0x9b55(%rip), %rdi      # 0xdff0
leaq 0x5fef(%rip), %rsi      # 0xa491
movl $0xb, %edx
callq 0x21c0
movq 0x9b3d(%rip), %rdi      # 0xdff0
leaq 0x5ff8(%rip), %rsi      # 0xa4b2
movl $0x9, %edx
callq 0x21c0
movq 0x9b25(%rip), %rdi      # 0xdff0
movapd 0x10(%rsp), %xmm0
callq 0x2230
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2190
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2100
movsd (%rsp), %xmm0
divsd 0x5b3b(%rip), %xmm0     # 0xa048
movsd %xmm0, (%rsp)
ucomisd 0x5b36(%rip), %xmm0     # 0xa050
jbe 0x4534
movq 0x9acd(%rip), %rdi      # 0xdff0
leaq 0x5f66(%rip), %rsi      # 0xa490
movl $0xc, %edx
callq 0x21c0
movq 0x9ab5(%rip), %rdi      # 0xdff0
leaq 0x5f7a(%rip), %rsi      # 0xa4bc
movl $0x9, %edx
callq 0x21c0
movq 0x9a9d(%rip), %rdi      # 0xdff0
movsd (%rsp), %xmm0
callq 0x2230
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2190
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2100
movq 0x30(%rsp), %rdi
callq 0x2180
movq 0x38(%rsp), %rdi
callq 0x2180
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x45aa
callq 0x2180
movq 0x68(%rsp), %rdi
testq %rdi, %rdi
je 0x45b9
callq 0x2180
addq $0x14a8, %rsp           # imm = 0x14A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x45e6
movq %rax, %rbx
jmp 0x4609
jmp 0x45d4
movq %rax, %rbx
jmp 0x4613
movq %rax, %rbx
jmp 0x4622
jmp 0x45e6
jmp 0x45e6
jmp 0x45e6
jmp 0x45e6
movq %rax, %rbx
jmp 0x45ff
jmp 0x45ef
jmp 0x45ef
movq %rax, %rbx
leaq 0xb0(%rsp), %rdi
callq 0x5d3e
movq 0x30(%rsp), %rdi
callq 0x2180
movq 0x38(%rsp), %rdi
callq 0x2180
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x4622
callq 0x2180
movq 0x68(%rsp), %rdi
testq %rdi, %rdi
je 0x4631
callq 0x2180
movq %rbx, %rdi
callq 0x2270