// File: /workspace/github_cpp_makefile_star2_O2/redpony[P]cpyp/crp_test.cc
// Function: test_mh2()
void test_mh2() {
  cpyp::MT19937 eng;
  cpyp::crp<int> a(0.5, 1.0);
  cpyp::crp<int> b(0.5, 1.0);
  vector<int> hist_a(16, 0);
  vector<int> hist_b(16, 0);
  vector<double> ref_a = {3.70004e-06, 0.0144611, 0.0614236, 0.138702, 0.211308, 0.231733, 0.183865, 0.103685, 0.0409419, 0.0114253, 0.00214592, 0.000281003, 2.33002e-05, 7.00007e-07, 2.12303e-07, 0};
  vector<double> ref_b = {2.90003e-06, 0.00876079, 0.0471061, 0.115841, 0.187615, 0.221488, 0.196102, 0.130352, 0.063905, 0.0224984, 0.00542085, 0.000828908, 7.53008e-05, 4.90005e-06, 1.00001e-07, 0};
  double ref_t0b = 1.53498;

  vector<bool> z(15);
  double c = 0;
  double ac = 0;
  double tmh = 0;
  double zz = 0;
  double t0b = 0;
  for (int s = 0; s < 200000; ++s) {
    for (int i = 0; i < 15; ++i) {
      const unsigned int y_i = i % 3;
      const bool old_z = z[i];
      cpyp::crp<int> old_a = a;
      cpyp::crp<int> old_b = b;
      double lp_old = llh(a, p0_a) + llh(b, p0_b);

      double lq_old = 0;
      double lq_new = 0;
      if (s > 0) (z[i] ? b : a).decrement(y_i, eng, &lq_old);

      double aa = 0.5;  // these can be better estimates
      double bb = 0.5;
      z[i] = cpyp::sample_bernoulli(aa, bb, eng);
      (z[i] ? b : a).increment_no_base(y_i, eng, &lq_new);
      lq_new += log((z[i] ? bb : aa) / (aa + bb));
      lq_old += log((old_z ? bb : aa) / (aa + bb));

      if (s > 0) { 
        double lp_new = llh(a, p0_a) + llh(b, p0_b);
        double acc = exp(lp_new - lp_old + lq_old - lq_new);
        ++tmh;
        if (acc >= 1.0 || cpyp::sample_uniform01<double>(eng) < acc) { // mh accept
          ++ac;
        } else { // mh reject
          std::swap(a, old_a);
          std::swap(b, old_b);
          z[i] = old_z;
        }
      }
    }
    // record sample
    if (s> 200 && s % 10 == 9) {
      assert(a.num_tables() < hist_a.size());
      assert(b.num_tables() < hist_b.size());
      hist_a[a.num_tables()]++; hist_b[b.num_tables()]++; ++c;
      for (int i = 0; i < 15; ++i) {
        unsigned int y_i = i % 3;
        if (!z[i]) { t0b += y_i; ++zz; }
      }
    }
  }
  ac /= tmh;
  cerr << "ACCEPTANCE: " << ac << endl;
  int j =0;
  double te = 0;
  double me = 0;
  for (int i = 0; i < 15; ++i) {
    double a = hist_a[i];
    double b = hist_b[i];
    double err_a = (a / c - ref_a[j]);
    double err_b = (b / c - ref_b[j++]);
    cerr << err_a << "\t" << err_b << endl;
    te += fabs(err_a) + fabs(err_b);
    if (fabs(err_a) > me) { me = fabs(err_a); }
    if (fabs(err_b) > me) { me = fabs(err_b); }
  }
  te /= 30;
  cerr << "t0b = " << (t0b / zz) << endl;
  double ee = fabs((t0b / zz) - ref_t0b);
  cerr << "err t0b = " << ee;
  if (ee > 0.01) { cerr << "  ** TOO HIGH **"; }
  cerr << endl;
  cerr << "Average error: " << te;
  if (te > 0.01) { cerr << "  ** TOO HIGH **"; }
  cerr << endl << "    Max error: " << me;
  if (me > 0.01) { cerr << "  ** TOO HIGH **"; }
  cerr << endl;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1688, %rsp           # imm = 0x1688
leaq 0x300(%rsp), %rdi
callq 0x3f30
leaq 0x190(%rsp), %rdi
movsd 0x631f(%rip), %xmm0     # 0x9008
movsd 0x631f(%rip), %xmm1     # 0x9010
callq 0x3f80
leaq 0x118(%rsp), %rdi
movsd 0x6302(%rip), %xmm0     # 0x9008
movsd 0x6302(%rip), %xmm1     # 0x9010
callq 0x3f80
leaq 0x208(%rsp), %rdx
andl $0x0, (%rdx)
leaq 0xa8(%rsp), %rdi
pushq $0x10
popq %rsi
leaq 0x288(%rsp), %rcx
callq 0x3fe8
leaq 0x208(%rsp), %rdx
andl $0x0, (%rdx)
leaq 0x90(%rsp), %rdi
pushq $0x10
popq %rsi
leaq 0x288(%rsp), %rcx
callq 0x3fe8
leaq 0x6460(%rip), %rsi      # 0x91c0
pushq $0x10
popq %rdx
leaq 0x208(%rsp), %rax
movq %rdx, %rcx
movq %rax, %rdi
rep  movsq (%rsi), %es:(%rdi)
leaq 0xd8(%rsp), %rdi
leaq 0x288(%rsp), %rcx
movq %rax, %rsi
callq 0x3f4a
leaq 0x64ad(%rip), %rsi      # 0x9240
pushq $0x10
popq %rdx
leaq 0x208(%rsp), %rax
movq %rdx, %rcx
movq %rax, %rdi
rep  movsq (%rsi), %es:(%rdi)
leaq 0xc0(%rsp), %rdi
leaq 0x288(%rsp), %rcx
movq %rax, %rsi
callq 0x3f4a
leaq 0xf0(%rsp), %rdi
pushq $0xf
popq %rsi
leaq 0x208(%rsp), %rdx
callq 0x4414
xorpd %xmm0, %xmm0
movapd %xmm0, 0x30(%rsp)
xorl %r13d, %r13d
leaq 0xf0(%rsp), %r14
movapd %xmm0, 0x60(%rsp)
movapd %xmm0, 0x80(%rsp)
movapd %xmm0, 0x70(%rsp)
movapd %xmm0, 0x50(%rsp)
cmpl $0x30d40, %r13d         # imm = 0x30D40
je 0x31aa
xorl %r12d, %r12d
movl %r12d, %eax
xorl %edx, %edx
pushq $0x3
popq %rcx
divl %ecx
cmpq $0xf, %r12
je 0x30c0
movl %edx, %ebx
movq %r14, %rdi
movq %r12, %rsi
callq 0x4428
movq %rdx, %r15
andq (%rax), %r15
leaq 0x208(%rsp), %rdi
leaq 0x190(%rsp), %rsi
callq 0x403e
leaq 0x288(%rsp), %rdi
leaq 0x118(%rsp), %rsi
callq 0x403e
leaq 0x190(%rsp), %rdi
leaq 0x6449(%rip), %rsi      # 0x92c0
callq 0x23b1
movsd %xmm0, 0x8(%rsp)
leaq 0x118(%rsp), %rdi
leaq 0x644f(%rip), %rsi      # 0x92e0
callq 0x23b1
movsd %xmm0, 0x18(%rsp)
andq $0x0, 0x28(%rsp)
andq $0x0, 0x20(%rsp)
testl %r13d, %r13d
je 0x2eea
movq %r14, %rdi
movq %r12, %rsi
callq 0x4428
testq %rdx, (%rax)
leaq 0x118(%rsp), %rdi
leaq 0x190(%rsp), %rax
cmoveq %rax, %rdi
movl %ebx, 0x14(%rsp)
leaq 0x14(%rsp), %rsi
leaq 0x300(%rsp), %rdx
leaq 0x28(%rsp), %rcx
callq 0x4086
leaq 0x300(%rsp), %rdi
callq 0x427a
movsd %xmm0, 0x40(%rsp)
movq %r14, %rdi
movq %r12, %rsi
callq 0x4428
movsd 0x40(%rsp), %xmm0
ucomisd 0x60f2(%rip), %xmm0     # 0x9008
jbe 0x2f1d
orq (%rax), %rdx
jmp 0x2f23
notq %rdx
andq (%rax), %rdx
movq %rdx, (%rax)
movq %r14, %rdi
movq %r12, %rsi
callq 0x4428
testq %rdx, (%rax)
leaq 0x118(%rsp), %rdi
leaq 0x190(%rsp), %rax
cmoveq %rax, %rdi
movl %ebx, 0x14(%rsp)
leaq 0x14(%rsp), %rsi
leaq 0x300(%rsp), %rdx
leaq 0x20(%rsp), %rcx
callq 0x42ea
movq %r14, %rdi
movq %r12, %rsi
callq 0x4428
movsd 0x20(%rsp), %xmm0
movsd 0x60ac(%rip), %xmm1     # 0x9028
addsd %xmm1, %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x28(%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x28(%rsp)
testl %r13d, %r13d
je 0x3057
leaq 0x190(%rsp), %rdi
leaq 0x6312(%rip), %rsi      # 0x92c0
callq 0x23b1
movsd %xmm0, 0x40(%rsp)
leaq 0x118(%rsp), %rdi
leaq 0x6318(%rip), %rsi      # 0x92e0
callq 0x23b1
movsd 0x8(%rsp), %xmm1
addsd 0x18(%rsp), %xmm1
movsd 0x40(%rsp), %xmm2
addsd %xmm0, %xmm2
subsd %xmm1, %xmm2
addsd 0x28(%rsp), %xmm2
subsd 0x20(%rsp), %xmm2
movapd %xmm2, %xmm0
callq 0x2250
movapd %xmm0, %xmm2
movsd 0x6008(%rip), %xmm0     # 0x9010
movapd 0x80(%rsp), %xmm1
addsd %xmm0, %xmm1
movapd %xmm1, 0x80(%rsp)
movsd %xmm2, 0x40(%rsp)
ucomisd %xmm0, %xmm2
jae 0x3043
leaq 0x300(%rsp), %rdi
callq 0x427a
movsd 0x40(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0x3079
movapd 0x70(%rsp), %xmm0
addsd 0x5fbf(%rip), %xmm0     # 0x9010
movapd %xmm0, 0x70(%rsp)
leaq 0x290(%rsp), %rdi
callq 0x5008
leaq 0x210(%rsp), %rdi
callq 0x5008
incq %r12
jmp 0x2e17
leaq 0x190(%rsp), %rdi
leaq 0x208(%rsp), %rsi
callq 0x429b
leaq 0x118(%rsp), %rdi
leaq 0x288(%rsp), %rsi
callq 0x429b
movq %r14, %rdi
movq %r12, %rsi
callq 0x4428
testq %r15, %r15
je 0x30b8
orq %rdx, (%rax)
jmp 0x3057
notq %rdx
andq %rdx, (%rax)
jmp 0x3057
movl %r13d, %eax
xorl %edx, %edx
pushq $0xa
popq %rcx
divl %ecx
cmpl $0xc9, %r13d
jb 0x31a2
cmpl $0x9, %edx
jne 0x31a2
movl 0x190(%rsp), %eax
movq 0xa8(%rsp), %rcx
movq 0xb0(%rsp), %rdx
subq %rcx, %rdx
sarq $0x2, %rdx
cmpq %rax, %rdx
jbe 0x3487
movl 0x118(%rsp), %esi
movq 0x90(%rsp), %rdx
movq 0x98(%rsp), %rdi
subq %rdx, %rdi
sarq $0x2, %rdi
cmpq %rsi, %rdi
jbe 0x34a6
incl (%rcx,%rax,4)
movl 0x118(%rsp), %eax
incl (%rdx,%rax,4)
movapd 0x50(%rsp), %xmm0
addsd 0x5ec7(%rip), %xmm0     # 0x9010
movapd %xmm0, 0x50(%rsp)
xorl %ebx, %ebx
movzbl %bl, %eax
movb $0x3, %cl
divb %cl
movzbl %ah, %ebp
cmpq $0xf, %rbx
je 0x31a2
movq %r14, %rdi
movq %rbx, %rsi
callq 0x4428
movapd 0x60(%rsp), %xmm0
addsd 0x5e96(%rip), %xmm0     # 0x9010
testq %rdx, (%rax)
jne 0x319d
movsbl %bpl, %eax
cvtsi2sd %eax, %xmm1
movapd 0x30(%rsp), %xmm2
addsd %xmm1, %xmm2
movapd %xmm2, 0x30(%rsp)
movapd %xmm0, 0x60(%rsp)
incq %rbx
jmp 0x3151
incl %r13d
jmp 0x2e07
movq 0xae3f(%rip), %rdi      # 0xdff0
leaq 0x61f1(%rip), %rsi      # 0x93a9
callq 0x2170
movapd 0x70(%rsp), %xmm0
divsd 0x80(%rsp), %xmm0
movq %rax, %rdi
callq 0x2200
movq %rax, %rdi
callq 0x2080
movapd 0x50(%rsp), %xmm0
unpcklpd %xmm0, %xmm0            # xmm0 = xmm0[0,0]
movapd %xmm0, 0x50(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
xorl %r15d, %r15d
movq 0xadf0(%rip), %rbx      # 0xdff0
leaq 0x61af(%rip), %r14      # 0x93b6
movsd %xmm0, 0x18(%rsp)
cmpq $0xf, %r15
je 0x32d0
movq 0xa8(%rsp), %rax
movq 0x90(%rsp), %rcx
movq 0xd8(%rsp), %rdx
movq 0xc0(%rsp), %rsi
movss (%rcx,%r15,4), %xmm0
movss (%rax,%r15,4), %xmm1
unpcklps %xmm0, %xmm1            # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
cvtdq2pd %xmm1, %xmm0
divpd 0x50(%rsp), %xmm0
movsd (%rdx,%r15,8), %xmm1
movhpd (%rsi,%r15,8), %xmm1    # xmm1 = xmm1[0],mem[0]
subpd %xmm1, %xmm0
movq %rbx, %rdi
movapd %xmm0, 0x40(%rsp)
callq 0x2200
movq %rax, %rdi
movq %r14, %rsi
callq 0x2170
movapd 0x40(%rsp), %xmm0
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
movq %rax, %rdi
callq 0x2200
movq %rax, %rdi
callq 0x2080
movdqa 0x40(%rsp), %xmm3
pand 0x5dff(%rip), %xmm3     # 0x90a0
pshufd $0xee, %xmm3, %xmm0     # xmm0 = xmm3[2,3,2,3]
movdqa %xmm3, %xmm1
addsd %xmm0, %xmm1
movsd 0x8(%rsp), %xmm2
addsd %xmm1, %xmm2
movsd %xmm2, 0x8(%rsp)
maxsd 0x18(%rsp), %xmm3
maxsd %xmm3, %xmm0
incq %r15
jmp 0x3207
movq 0xad19(%rip), %rdi      # 0xdff0
leaq 0x6169(%rip), %rsi      # 0x9447
callq 0x2170
movapd 0x30(%rsp), %xmm0
divsd 0x60(%rsp), %xmm0
movq %rax, %rdi
movapd %xmm0, 0x30(%rsp)
callq 0x2200
movq %rax, %rdi
callq 0x2080
movq 0xace4(%rip), %rdi      # 0xdff0
leaq 0x6130(%rip), %rsi      # 0x9443
callq 0x2170
movapd 0x30(%rsp), %xmm0
addsd 0x5d12(%rip), %xmm0     # 0x9038
andpd 0x5d72(%rip), %xmm0     # 0x90a0
movapd %xmm0, 0x30(%rsp)
movq %rax, %rdi
movaps 0x30(%rsp), %xmm0
callq 0x2200
movapd 0x30(%rsp), %xmm0
ucomisd 0x5cd1(%rip), %xmm0     # 0x9020
jbe 0x3364
movq 0xac98(%rip), %rdi      # 0xdff0
leaq 0x6069(%rip), %rsi      # 0x93c8
callq 0x2170
movq 0xac85(%rip), %rdi      # 0xdff0
callq 0x2080
movq 0xac79(%rip), %rdi      # 0xdff0
leaq 0x603a(%rip), %rsi      # 0x93b8
callq 0x2170
movsd 0x8(%rsp), %xmm0
divsd 0x5c9f(%rip), %xmm0     # 0x9030
movq %rax, %rdi
movsd %xmm0, 0x8(%rsp)
callq 0x2200
movsd 0x8(%rsp), %xmm0
ucomisd 0x5c73(%rip), %xmm0     # 0x9020
jbe 0x33c2
movq 0xac3a(%rip), %rdi      # 0xdff0
leaq 0x600b(%rip), %rsi      # 0x93c8
callq 0x2170
movq 0xac27(%rip), %rdi      # 0xdff0
callq 0x2080
leaq 0x6004(%rip), %rsi      # 0x93d9
movq %rax, %rdi
callq 0x2170
movq %rax, %rdi
movsd 0x18(%rsp), %xmm0
callq 0x2200
movsd 0x18(%rsp), %xmm0
ucomisd 0x5c27(%rip), %xmm0     # 0x9020
jbe 0x340e
movq 0xabee(%rip), %rdi      # 0xdff0
leaq 0x5fbf(%rip), %rsi      # 0x93c8
callq 0x2170
movq 0xabdb(%rip), %rdi      # 0xdff0
callq 0x2080
leaq 0xf0(%rsp), %rdi
callq 0x4478
leaq 0xc0(%rsp), %rdi
callq 0x59a8
leaq 0xd8(%rsp), %rdi
callq 0x59a8
leaq 0x90(%rsp), %rdi
callq 0x5be4
leaq 0xa8(%rsp), %rdi
callq 0x5be4
leaq 0x120(%rsp), %rdi
callq 0x5008
leaq 0x198(%rsp), %rdi
callq 0x5008
addq $0x1688, %rsp           # imm = 0x1688
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x5f5b(%rip), %rdi      # 0x93e9
leaq 0x5f73(%rip), %rsi      # 0x9408
leaq 0x5f78(%rip), %rcx      # 0x9414
movl $0xb7, %edx
callq 0x20d0
leaq 0x5f77(%rip), %rdi      # 0x9424
leaq 0x5f54(%rip), %rsi      # 0x9408
leaq 0x5f59(%rip), %rcx      # 0x9414
movl $0xb8, %edx
callq 0x20d0
movq %rax, %rbx
jmp 0x3546
movq %rax, %rbx
jmp 0x3553
movq %rax, %rbx
jmp 0x3560
movq %rax, %rbx
jmp 0x356d
movq %rax, %rbx
jmp 0x357a
movq %rax, %rbx
jmp 0x3587
jmp 0x3515
jmp 0x3515
jmp 0x3515
jmp 0x3515
jmp 0x351c
jmp 0x351c
jmp 0x3515
jmp 0x351c
jmp 0x351c
movq %rax, %rbx
jmp 0x352c
jmp 0x351c
jmp 0x351c
jmp 0x351c
jmp 0x351c
jmp 0x351c
jmp 0x3515
movq %rax, %rbx
jmp 0x3539
jmp 0x351c
movq %rax, %rbx
leaq 0x290(%rsp), %rdi
callq 0x5008
leaq 0x210(%rsp), %rdi
callq 0x5008
leaq 0xf0(%rsp), %rdi
callq 0x4478
leaq 0xc0(%rsp), %rdi
callq 0x59a8
leaq 0xd8(%rsp), %rdi
callq 0x59a8
leaq 0x90(%rsp), %rdi
callq 0x5be4
leaq 0xa8(%rsp), %rdi
callq 0x5be4
leaq 0x120(%rsp), %rdi
callq 0x5008
leaq 0x198(%rsp), %rdi
callq 0x5008
movq %rbx, %rdi
callq 0x2240