// File: redpony[P]cpyp/crp_test.cc
// Function: test_mh1()
void test_mh1() {
  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
      bool wasrem = false;
      if (s > 0)
        wasrem = crp.decrement(y_i, eng);

      bool wasnew = crp.increment(y_i, q0[y_i], eng);
      if (s > 0) {
        double p_new = 1, q_new = 1;
        if (wasnew) { p_new = p0[y_i]; q_new = q0[y_i]; }
        double p_old = 1, q_old = 1;
        if (wasrem) { p_old = p0[y_i]; q_old = q0[y_i]; }
        double a = p_new / p_old * q_old / q_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 0x12c63(%rip), %xmm0    # 0x15130
movaps %xmm0, 0x290(%rsp)
movups 0x12c44(%rip), %xmm0    # 0x15120
movaps %xmm0, 0x280(%rsp)
movups 0x12c25(%rip), %xmm0    # 0x15110
movaps %xmm0, 0x270(%rsp)
movups 0x12c06(%rip), %xmm0    # 0x15100
movaps %xmm0, 0x260(%rsp)
movups 0x12be7(%rip), %xmm0    # 0x150f0
movaps %xmm0, 0x250(%rsp)
movups 0x12bc8(%rip), %xmm0    # 0x150e0
movaps %xmm0, 0x240(%rsp)
movups 0x12ba9(%rip), %xmm0    # 0x150d0
movaps %xmm0, 0x230(%rsp)
leaq 0x230(%rsp), %rax
movq %rax, 0x2a8(%rsp)
movq $0xf, 0x2b0(%rsp)
leaq 0x22f(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x5e60
movq 0x68(%rsp), %rcx
movq 0x2a8(%rsp), %rsi
movq 0x2b0(%rsp), %rdx
leaq 0x2b8(%rsp), %rdi
callq 0x5e70
jmp 0x2581
leaq 0x22f(%rsp), %rdi
callq 0x5f00
leaq 0x1a0(%rsp), %rdi
movsd 0x12a6a(%rip), %xmm0    # 0x15008
movsd 0x12a6a(%rip), %xmm1    # 0x15010
callq 0x5f10
jmp 0x25ad
movl $0x0, 0x184(%rsp)
leaq 0x183(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x5fd0
movq 0x60(%rsp), %rcx
leaq 0x188(%rsp), %rdi
movl $0xf, %esi
leaq 0x184(%rsp), %rdx
callq 0x5fe0
jmp 0x25eb
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 0x2a14
movl $0x0, 0x160(%rsp)
cmpl $0xf, 0x160(%rsp)
jge 0x298e
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 0x2694
movb $0x0, 0xdf(%rsp)
cmpl $0x0, 0x164(%rsp)
jle 0x278d
xorl %eax, %eax
movl %eax, %ecx
leaq 0x1a0(%rsp), %rdi
leaq 0x15c(%rsp), %rsi
leaq 0x2d0(%rsp), %rdx
callq 0x60d0
movl %eax, 0x5c(%rsp)
jmp 0x26d1
movl 0x5c(%rsp), %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, 0xdf(%rsp)
jmp 0x278d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
leaq 0x22f(%rsp), %rdi
callq 0x5f00
jmp 0x2d83
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
jmp 0x2d76
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
leaq 0x183(%rsp), %rdi
callq 0x6060
jmp 0x2d69
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
jmp 0x2d5c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x220(%rsp)
movl %eax, 0x21c(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0x65a0
jmp 0x2d5c
movslq 0x15c(%rsp), %rcx
leaq 0x129b4(%rip), %rax     # 0x15150
leaq (%rax,%rcx,8), %rdx
leaq 0x1a0(%rsp), %rdi
leaq 0x15c(%rsp), %rsi
leaq 0x2d0(%rsp), %rcx
callq 0x6390
movl %eax, 0x58(%rsp)
jmp 0x27c3
movl 0x58(%rsp), %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, 0xde(%rsp)
cmpl $0x0, 0x164(%rsp)
jle 0x296b
movsd 0x12824(%rip), %xmm0    # 0x15010
movsd %xmm0, 0xd0(%rsp)
movsd 0x12813(%rip), %xmm0    # 0x15010
movsd %xmm0, 0xc8(%rsp)
testb $0x1, 0xde(%rsp)
je 0x284a
movslq 0x15c(%rsp), %rcx
leaq 0x12951(%rip), %rax     # 0x15170
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0xd0(%rsp)
movslq 0x15c(%rsp), %rcx
leaq 0x12914(%rip), %rax     # 0x15150
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0xc8(%rsp)
movsd 0x127be(%rip), %xmm0    # 0x15010
movsd %xmm0, 0xc0(%rsp)
movsd 0x127ad(%rip), %xmm0    # 0x15010
movsd %xmm0, 0xb8(%rsp)
testb $0x1, 0xdf(%rsp)
je 0x28b0
movslq 0x15c(%rsp), %rcx
leaq 0x128eb(%rip), %rax     # 0x15170
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0xc0(%rsp)
movslq 0x15c(%rsp), %rcx
leaq 0x128ae(%rip), %rax     # 0x15150
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0xb8(%rsp)
movsd 0xd0(%rsp), %xmm0
divsd 0xc0(%rsp), %xmm0
mulsd 0xb8(%rsp), %xmm0
divsd 0xc8(%rsp), %xmm0
movsd %xmm0, 0xb0(%rsp)
movsd 0x1272b(%rip), %xmm0    # 0x15010
addsd 0x168(%rsp), %xmm0
movsd %xmm0, 0x168(%rsp)
movsd 0xb0(%rsp), %xmm0
movsd 0x12708(%rip), %xmm1    # 0x15010
ucomisd %xmm1, %xmm0
jae 0x2938
leaq 0x2d0(%rsp), %rdi
callq 0x6510
movsd %xmm0, 0x50(%rsp)
jmp 0x2923
movsd 0x50(%rsp), %xmm1
movsd 0xb0(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x2954
movsd 0x126d0(%rip), %xmm0    # 0x15010
addsd 0x170(%rsp), %xmm0
movsd %xmm0, 0x170(%rsp)
jmp 0x2969
leaq 0x1a0(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0x6540
jmp 0x296b
leaq 0xe0(%rsp), %rdi
callq 0x65a0
movl 0x160(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x160(%rsp)
jmp 0x2643
cmpl $0x12c, 0x164(%rsp) # imm = 0x12C
jle 0x29fc
movl 0x164(%rsp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
cmpl $0x3, %edx
jne 0x29fc
movsd 0x178(%rsp), %xmm0
movsd 0x12650(%rip), %xmm1    # 0x15010
addsd %xmm1, %xmm0
movsd %xmm0, 0x178(%rsp)
leaq 0x1a0(%rsp), %rdi
callq 0x65e0
movl %eax, 0x4c(%rsp)
jmp 0x29e0
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 0x29fe
movl 0x164(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x164(%rsp)
jmp 0x2627
movsd 0x168(%rsp), %xmm1
movsd 0x170(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x170(%rsp)
movq 0x1b5b6(%rip), %rdi     # 0x1dff0
leaq 0x129a8(%rip), %rsi     # 0x153e9
callq 0x2180
movq %rax, 0x40(%rsp)
jmp 0x2a4d
movq 0x40(%rsp), %rdi
movsd 0x170(%rsp), %xmm0
callq 0x2290
movq %rax, 0x38(%rsp)
jmp 0x2a67
movq 0x38(%rsp), %rdi
movq 0x1b555(%rip), %rsi     # 0x1dfc8
callq 0x21a0
jmp 0x2a7a
movl $0x0, 0xac(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xa0(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x98(%rsp)
leaq 0x188(%rsp), %rax
movq %rax, 0x90(%rsp)
movq 0x90(%rsp), %rdi
callq 0x65f0
movq %rax, 0x88(%rsp)
movq 0x90(%rsp), %rdi
callq 0x6620
movq %rax, 0x80(%rsp)
leaq 0x88(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x6650
testb $0x1, %al
jne 0x2af5
jmp 0x2c2a
leaq 0x88(%rsp), %rdi
callq 0x6690
movl (%rax), %eax
movl %eax, 0x7c(%rsp)
cvtsi2sdl 0x7c(%rsp), %xmm0
movsd 0x178(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x28(%rsp)
movslq 0xac(%rsp), %rsi
movl %esi, %eax
incl %eax
movl %eax, 0xac(%rsp)
leaq 0x2b8(%rsp), %rdi
callq 0x66a0
movsd 0x28(%rsp), %xmm0
movsd (%rax), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp)
movsd 0x70(%rsp), %xmm0
movq 0x1b48e(%rip), %rdi     # 0x1dff0
callq 0x2290
movq %rax, 0x30(%rsp)
jmp 0x2b6e
movq 0x30(%rsp), %rdi
leaq 0x1287c(%rip), %rsi     # 0x153f6
callq 0x2180
movq %rax, 0x20(%rsp)
jmp 0x2b86
movq 0x20(%rsp), %rdi
cvtsi2sdl 0x7c(%rsp), %xmm0
movsd 0x178(%rsp), %xmm1
divsd %xmm1, %xmm0
callq 0x2290
movq %rax, 0x18(%rsp)
jmp 0x2baa
movq 0x18(%rsp), %rdi
movq 0x1b412(%rip), %rsi     # 0x1dfc8
callq 0x21a0
jmp 0x2bbd
movsd 0x70(%rsp), %xmm0
movaps 0x124b6(%rip), %xmm1    # 0x15080
pand %xmm1, %xmm0
addsd 0xa0(%rsp), %xmm0
movsd %xmm0, 0xa0(%rsp)
movsd 0x70(%rsp), %xmm0
movaps 0x12493(%rip), %xmm1    # 0x15080
pand %xmm1, %xmm0
ucomisd 0x98(%rsp), %xmm0
jbe 0x2c16
movsd 0x70(%rsp), %xmm0
movaps 0x12477(%rip), %xmm1    # 0x15080
pand %xmm1, %xmm0
movsd %xmm0, 0x98(%rsp)
jmp 0x2c18
leaq 0x88(%rsp), %rdi
callq 0x66c0
jmp 0x2ad7
movsd 0xa0(%rsp), %xmm0
movsd 0x123dd(%rip), %xmm1    # 0x15018
divsd %xmm1, %xmm0
movsd %xmm0, 0xa0(%rsp)
movq 0x1b3a1(%rip), %rdi     # 0x1dff0
leaq 0x127a2(%rip), %rsi     # 0x153f8
callq 0x2180
movq %rax, 0x10(%rsp)
jmp 0x2c62
movq 0x10(%rsp), %rdi
movsd 0xa0(%rsp), %xmm0
callq 0x2290
jmp 0x2c77
movsd 0xa0(%rsp), %xmm0
movsd 0x12398(%rip), %xmm1    # 0x15020
ucomisd %xmm1, %xmm0
jbe 0x2ca5
movq 0x1b35b(%rip), %rdi     # 0x1dff0
leaq 0x1276c(%rip), %rsi     # 0x15408
callq 0x2180
jmp 0x2ca3
jmp 0x2ca5
movq 0x1b344(%rip), %rdi     # 0x1dff0
movq 0x1b315(%rip), %rsi     # 0x1dfc8
callq 0x21a0
movq %rax, 0x8(%rsp)
jmp 0x2cbf
movq 0x8(%rsp), %rdi
leaq 0x1274e(%rip), %rsi     # 0x15419
callq 0x2180
movq %rax, (%rsp)
jmp 0x2cd6
movq (%rsp), %rdi
movsd 0x98(%rsp), %xmm0
callq 0x2290
jmp 0x2cea
movsd 0x98(%rsp), %xmm0
movsd 0x12325(%rip), %xmm1    # 0x15020
ucomisd %xmm1, %xmm0
jbe 0x2d18
movq 0x1b2e8(%rip), %rdi     # 0x1dff0
leaq 0x126f9(%rip), %rsi     # 0x15408
callq 0x2180
jmp 0x2d16
jmp 0x2d18
movq 0x1b2d1(%rip), %rdi     # 0x1dff0
movq 0x1b2a2(%rip), %rsi     # 0x1dfc8
callq 0x21a0
jmp 0x2d2d
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