// File: redpony[P]cpyp/crp_test.cc
// Function: test_mh1a()
void test_mh1a() {
  cpyp::MT19937 eng;
  const vector<double> ref = {0, 0, 0, 0.00466121, 0.0233846, 0.0647365, 0.125693, 0.183448, 0.204806, 0.177036, 0.119629, 0.0627523, 0.02507, 0.00725451, 0.0013911};
  cpyp::crp<int> crp(0.5, 1.0);
  vector<int> hist(15, 0);
  double c = 0;
  double ac = 0;
  double tmh = 0;
  for (int s = 0; s < 200000; ++s) {
    for (int i = 0; i < 15; ++i) {
      int y_i = i % 3;
      cpyp::crp<int> prev = crp;  // save old state
      double lq_old = 0;
      double lp_old = llh(crp, p0);
      if (s > 0) crp.decrement(y_i, eng, &lq_old);

      double lq_new = 0;
      crp.increment_no_base(y_i, eng, &lq_new);
      if (s > 0) {
        double lp_new = llh(crp, p0);
        double a = exp(lp_new - lp_old + lq_old - lq_new);
        ++tmh;
        if (a >= 1.0 || cpyp::sample_uniform01<double>(eng) < a) { // mh accept
          ++ac;
        } else { // mh reject
          std::swap(crp, prev);  // swap is faster than =
        }
      }
    }
    if (s > 300 && s % 4 == 3) { ++c; hist[crp.num_tables()]++; }
  }
  ac /= tmh;
  cerr << "ACCEPTANCE: " << ac << endl;
  int j =0;
  double te = 0;
  double me = 0;
  for (auto i : hist) {
    double err = (i / c - ref[j++]);
    cerr << err << "\t" << i/c << endl;
    te += fabs(err);
    if (fabs(err) > me) { me = fabs(err); }
  }
  te /= 12;
  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:
subq $0x1658, %rsp           # imm = 0x1658
leaq 0x2d0(%rsp), %rdi
callq 0x5e30
movabsq $0x3f56cab240598c63, %rax # imm = 0x3F56CAB240598C63
movq %rax, 0x2a0(%rsp)
movups 0x1242b(%rip), %xmm0    # 0x151e8
movaps %xmm0, 0x290(%rsp)
movups 0x1240c(%rip), %xmm0    # 0x151d8
movaps %xmm0, 0x280(%rsp)
movups 0x123ed(%rip), %xmm0    # 0x151c8
movaps %xmm0, 0x270(%rsp)
movups 0x123ce(%rip), %xmm0    # 0x151b8
movaps %xmm0, 0x260(%rsp)
movups 0x123af(%rip), %xmm0    # 0x151a8
movaps %xmm0, 0x250(%rsp)
movups 0x12390(%rip), %xmm0    # 0x15198
movaps %xmm0, 0x240(%rsp)
movups 0x12371(%rip), %xmm0    # 0x15188
movaps %xmm0, 0x230(%rsp)
leaq 0x230(%rsp), %rax
movq %rax, 0x2a8(%rsp)
movq $0xf, 0x2b0(%rsp)
leaq 0x22f(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x5e60
movq 0x70(%rsp), %rcx
movq 0x2a8(%rsp), %rsi
movq 0x2b0(%rsp), %rdx
leaq 0x2b8(%rsp), %rdi
callq 0x5e70
jmp 0x2e71
leaq 0x22f(%rsp), %rdi
callq 0x5f00
leaq 0x1a0(%rsp), %rdi
movsd 0x1217a(%rip), %xmm0    # 0x15008
movsd 0x1217a(%rip), %xmm1    # 0x15010
callq 0x5f10
jmp 0x2e9d
movl $0x0, 0x184(%rsp)
leaq 0x183(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x5fd0
movq 0x68(%rsp), %rcx
leaq 0x188(%rsp), %rdi
movl $0xf, %esi
leaq 0x184(%rsp), %rdx
callq 0x5fe0
jmp 0x2edb
leaq 0x183(%rsp), %rdi
callq 0x6060
xorps %xmm0, %xmm0
movsd %xmm0, 0x178(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x170(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x168(%rsp)
movl $0x0, 0x164(%rsp)
cmpl $0x30d40, 0x164(%rsp) # imm = 0x30D40
jge 0x326e
movl $0x0, 0x160(%rsp)
cmpl $0xf, 0x160(%rsp)
jge 0x31e8
movslq 0x160(%rsp), %rcx
movl %ecx, %eax
imulq $0x55555556, %rcx, %rdx # imm = 0x55555556
movq %rdx, %rcx
shrq $0x3f, %rcx
shrq $0x20, %rdx
addl %ecx, %edx
movl %edx, %ecx
leal (%rcx,%rcx,2), %ecx
subl %ecx, %eax
movl %eax, 0x15c(%rsp)
leaq 0xe0(%rsp), %rdi
leaq 0x1a0(%rsp), %rsi
callq 0x6070
jmp 0x2f84
movq $0x0, 0xd8(%rsp)
leaq 0x121d9(%rip), %rsi     # 0x15170
leaq 0x1a0(%rsp), %rdi
callq 0x2410
movsd %xmm0, 0x60(%rsp)
jmp 0x2fac
movsd 0x60(%rsp), %xmm0
movsd %xmm0, 0xd0(%rsp)
cmpl $0x0, 0x164(%rsp)
jle 0x3099
leaq 0x1a0(%rsp), %rdi
leaq 0x15c(%rsp), %rsi
leaq 0x2d0(%rsp), %rdx
leaq 0xd8(%rsp), %rcx
callq 0x60d0
jmp 0x2ff0
jmp 0x3099
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
leaq 0x22f(%rsp), %rdi
callq 0x5f00
jmp 0x35e6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
jmp 0x35d9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
leaq 0x183(%rsp), %rdi
callq 0x6060
jmp 0x35cc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
jmp 0x35bf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0x65a0
jmp 0x35bf
movq $0x0, 0xc8(%rsp)
leaq 0x1a0(%rsp), %rdi
leaq 0x15c(%rsp), %rsi
leaq 0x2d0(%rsp), %rdx
leaq 0xc8(%rsp), %rcx
callq 0x67a0
jmp 0x30cc
cmpl $0x0, 0x164(%rsp)
jle 0x31c5
leaq 0x1208f(%rip), %rsi     # 0x15170
leaq 0x1a0(%rsp), %rdi
callq 0x2410
movsd %xmm0, 0x58(%rsp)
jmp 0x30f6
movsd 0x58(%rsp), %xmm0
movsd %xmm0, 0xc0(%rsp)
movsd 0xc0(%rsp), %xmm0
subsd 0xd0(%rsp), %xmm0
addsd 0xd8(%rsp), %xmm0
subsd 0xc8(%rsp), %xmm0
callq 0x2270
movsd %xmm0, 0xb8(%rsp)
movsd 0x11ed1(%rip), %xmm0    # 0x15010
addsd 0x168(%rsp), %xmm0
movsd %xmm0, 0x168(%rsp)
movsd 0xb8(%rsp), %xmm0
movsd 0x11eae(%rip), %xmm1    # 0x15010
ucomisd %xmm1, %xmm0
jae 0x3192
leaq 0x2d0(%rsp), %rdi
callq 0x6510
movsd %xmm0, 0x50(%rsp)
jmp 0x317d
movsd 0x50(%rsp), %xmm1
movsd 0xb8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x31ae
movsd 0x11e76(%rip), %xmm0    # 0x15010
addsd 0x170(%rsp), %xmm0
movsd %xmm0, 0x170(%rsp)
jmp 0x31c3
leaq 0x1a0(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0x6540
jmp 0x31c5
leaq 0xe0(%rsp), %rdi
callq 0x65a0
movl 0x160(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x160(%rsp)
jmp 0x2f33
cmpl $0x12c, 0x164(%rsp) # imm = 0x12C
jle 0x3256
movl 0x164(%rsp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
cmpl $0x3, %edx
jne 0x3256
movsd 0x178(%rsp), %xmm0
movsd 0x11df6(%rip), %xmm1    # 0x15010
addsd %xmm1, %xmm0
movsd %xmm0, 0x178(%rsp)
leaq 0x1a0(%rsp), %rdi
callq 0x65e0
movl %eax, 0x4c(%rsp)
jmp 0x323a
movl 0x4c(%rsp), %eax
movl %eax, %eax
movl %eax, %esi
leaq 0x188(%rsp), %rdi
callq 0x65c0
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
jmp 0x3258
movl 0x164(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x164(%rsp)
jmp 0x2f17
movsd 0x168(%rsp), %xmm1
movsd 0x170(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x170(%rsp)
movq 0x1ad5c(%rip), %rdi     # 0x1dff0
leaq 0x1214e(%rip), %rsi     # 0x153e9
callq 0x2180
movq %rax, 0x40(%rsp)
jmp 0x32a7
movq 0x40(%rsp), %rdi
movsd 0x170(%rsp), %xmm0
callq 0x2290
movq %rax, 0x38(%rsp)
jmp 0x32c1
movq 0x38(%rsp), %rdi
movq 0x1acfb(%rip), %rsi     # 0x1dfc8
callq 0x21a0
jmp 0x32d4
movl $0x0, 0xb4(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xa8(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xa0(%rsp)
leaq 0x188(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0x98(%rsp), %rdi
callq 0x65f0
movq %rax, 0x90(%rsp)
movq 0x98(%rsp), %rdi
callq 0x6620
movq %rax, 0x88(%rsp)
leaq 0x90(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x6650
testb $0x1, %al
jne 0x334f
jmp 0x348d
leaq 0x90(%rsp), %rdi
callq 0x6690
movl (%rax), %eax
movl %eax, 0x84(%rsp)
cvtsi2sdl 0x84(%rsp), %xmm0
movsd 0x178(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x28(%rsp)
movslq 0xb4(%rsp), %rsi
movl %esi, %eax
incl %eax
movl %eax, 0xb4(%rsp)
leaq 0x2b8(%rsp), %rdi
callq 0x66a0
movsd 0x28(%rsp), %xmm0
movsd (%rax), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0x78(%rsp), %xmm0
movq 0x1ac2e(%rip), %rdi     # 0x1dff0
callq 0x2290
movq %rax, 0x30(%rsp)
jmp 0x33ce
movq 0x30(%rsp), %rdi
leaq 0x1201c(%rip), %rsi     # 0x153f6
callq 0x2180
movq %rax, 0x20(%rsp)
jmp 0x33e6
movq 0x20(%rsp), %rdi
cvtsi2sdl 0x84(%rsp), %xmm0
movsd 0x178(%rsp), %xmm1
divsd %xmm1, %xmm0
callq 0x2290
movq %rax, 0x18(%rsp)
jmp 0x340d
movq 0x18(%rsp), %rdi
movq 0x1abaf(%rip), %rsi     # 0x1dfc8
callq 0x21a0
jmp 0x3420
movsd 0x78(%rsp), %xmm0
movaps 0x11c53(%rip), %xmm1    # 0x15080
pand %xmm1, %xmm0
addsd 0xa8(%rsp), %xmm0
movsd %xmm0, 0xa8(%rsp)
movsd 0x78(%rsp), %xmm0
movaps 0x11c30(%rip), %xmm1    # 0x15080
pand %xmm1, %xmm0
ucomisd 0xa0(%rsp), %xmm0
jbe 0x3479
movsd 0x78(%rsp), %xmm0
movaps 0x11c14(%rip), %xmm1    # 0x15080
pand %xmm1, %xmm0
movsd %xmm0, 0xa0(%rsp)
jmp 0x347b
leaq 0x90(%rsp), %rdi
callq 0x66c0
jmp 0x3331
movsd 0xa8(%rsp), %xmm0
movsd 0x11b7a(%rip), %xmm1    # 0x15018
divsd %xmm1, %xmm0
movsd %xmm0, 0xa8(%rsp)
movq 0x1ab3e(%rip), %rdi     # 0x1dff0
leaq 0x11f3f(%rip), %rsi     # 0x153f8
callq 0x2180
movq %rax, 0x10(%rsp)
jmp 0x34c5
movq 0x10(%rsp), %rdi
movsd 0xa8(%rsp), %xmm0
callq 0x2290
jmp 0x34da
movsd 0xa8(%rsp), %xmm0
movsd 0x11b35(%rip), %xmm1    # 0x15020
ucomisd %xmm1, %xmm0
jbe 0x3508
movq 0x1aaf8(%rip), %rdi     # 0x1dff0
leaq 0x11f09(%rip), %rsi     # 0x15408
callq 0x2180
jmp 0x3506
jmp 0x3508
movq 0x1aae1(%rip), %rdi     # 0x1dff0
movq 0x1aab2(%rip), %rsi     # 0x1dfc8
callq 0x21a0
movq %rax, 0x8(%rsp)
jmp 0x3522
movq 0x8(%rsp), %rdi
leaq 0x11eeb(%rip), %rsi     # 0x15419
callq 0x2180
movq %rax, (%rsp)
jmp 0x3539
movq (%rsp), %rdi
movsd 0xa0(%rsp), %xmm0
callq 0x2290
jmp 0x354d
movsd 0xa0(%rsp), %xmm0
movsd 0x11ac2(%rip), %xmm1    # 0x15020
ucomisd %xmm1, %xmm0
jbe 0x357b
movq 0x1aa85(%rip), %rdi     # 0x1dff0
leaq 0x11e96(%rip), %rsi     # 0x15408
callq 0x2180
jmp 0x3579
jmp 0x357b
movq 0x1aa6e(%rip), %rdi     # 0x1dff0
movq 0x1aa3f(%rip), %rsi     # 0x1dfc8
callq 0x21a0
jmp 0x3590
leaq 0x188(%rsp), %rdi
callq 0x66e0
leaq 0x1a0(%rsp), %rdi
callq 0x65a0
leaq 0x2b8(%rsp), %rdi
callq 0x6740
addq $0x1658, %rsp           # imm = 0x1658
retq
leaq 0x188(%rsp), %rdi
callq 0x66e0
leaq 0x1a0(%rsp), %rdi
callq 0x65a0
leaq 0x2b8(%rsp), %rdi
callq 0x6740
movq 0x220(%rsp), %rdi
callq 0x2260
nopw %cs:(%rax,%rax)