// File: redpony[P]cpyp/./cpyp/crp.h
// Function: cpyp::crp<int, std::hash<int>>::log_likelihood(double const&, double const&) const
double log_likelihood(const double& discount, const double& strength) const {
    double lp = 0.0;
    if (has_discount_prior() && discount) {
      lp = Md::log_beta_density(
          discount, discount_prior_strength_, discount_prior_beta_);
    }
    if (has_strength_prior()) {
      lp += Md::log_gamma_density(
          strength + discount, strength_prior_shape_, strength_prior_rate_);
    }
    assert(lp <= 0.0);
    if (num_customers_) {  // if restaurant is not empty
      if (discount > 0.0) {  // two parameter case: discount > 0
        const double r = lgamma(1.0 - discount);
        if (strength)
          lp += lgamma(strength) - lgamma(strength / discount);
        lp += - lgamma(strength + num_customers_)
             + num_tables_ * log(discount) +
             lgamma(strength / discount + num_tables_);
        // above line implies
        // 1) when adding a customer to a restaurant containing N customers:
        //    lp -= log(strength + N) [because \Gamma(s+N+1) = (s+N)\Gamma(s+N)
        // 2) when removing a customer from a restaurant containing N customers:
        //    lp += log(strength + N - 1)
        //    [because \Gamma(s+N) = (s+N-1)\Gamma(s+N-1)]
        // 3) when adding a table to a restaurant containing T tables:
        //    lp += log(discount) + log(s / d + T)
        // 4) when removing a table from a restuarant containint T tables:
        //    lp -= log(discount) + log(s / d + T - 1)

        assert(std::isfinite(lp));
        for (auto& dish_loc : dish_locs_)
          for (auto& bin : dish_loc.second.h[0])
            lp += (lgamma(bin.first - discount) - r) * bin.second;
         // above implies
         // 1) when adding to a table seating N > 1 customers
         //    lp += log(N - discount)
         // 2) when adding a new table
         //    do nothing
         // 3) when removing a customer from a table with N > 1 customers
         //    lp -= log(N - discount - 1)
         // 4) when closing a table
         //    do nothing
      } else if (!discount) {  // discount == 0.0 (ie, Dirichlet Process)
        lp += lgamma(strength) + num_tables_ * log(strength) -
            lgamma(strength + num_customers_);
        assert(std::isfinite(lp));
        for (auto& dish_loc : dish_locs_)
          for (auto& bin : dish_loc.second.h[0])
            lp += lgamma(bin.first) * bin.second;
      } else {  // should never happen, we check this elsewhere
        assert(!"discount less than 0 detected!");
      }
    }
    assert(std::isfinite(lp));
    return lp;
  }

// Assembly:
subq $0x138, %rsp            # imm = 0x138
movq %rdi, 0x130(%rsp)
movq %rsi, 0x128(%rsp)
movq %rdx, 0x120(%rsp)
movq 0x130(%rsp), %rdi
movq %rdi, 0x40(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x118(%rsp)
callq 0xa780
testb $0x1, %al
jne 0xa123
jmp 0xa162
movq 0x128(%rsp), %rax
movsd (%rax), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0xa13c
jp 0xa13c
jmp 0xa162
movq 0x40(%rsp), %rdx
movq 0x128(%rsp), %rdi
movq %rdx, %rsi
addq $0x50, %rsi
addq $0x58, %rdx
callq 0xa7a0
movsd %xmm0, 0x118(%rsp)
movq 0x40(%rsp), %rdi
callq 0xa930
testb $0x1, %al
jne 0xa172
jmp 0xa1c2
movq 0x40(%rsp), %rdx
movq 0x120(%rsp), %rax
movsd (%rax), %xmm0
movq 0x128(%rsp), %rax
addsd (%rax), %xmm0
movsd %xmm0, 0x110(%rsp)
movq %rdx, %rsi
addq $0x60, %rsi
addq $0x68, %rdx
leaq 0x110(%rsp), %rdi
callq 0xa950
addsd 0x118(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x118(%rsp), %xmm0
jb 0xa1d2
jmp 0xa1f1
leaq 0xb3d1(%rip), %rdi      # 0x155aa
leaq 0xb3d4(%rip), %rsi      # 0x155b4
movl $0x134, %edx            # imm = 0x134
leaq 0xb3d5(%rip), %rcx      # 0x155c1
callq 0x20e0
movq 0x40(%rsp), %rax
cmpl $0x0, 0x4(%rax)
je 0xa734
movq 0x128(%rsp), %rax
movsd (%rax), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0xa4fd
movq 0x128(%rsp), %rax
movsd 0xade7(%rip), %xmm0     # 0x15010
subsd (%rax), %xmm0
callq 0x2110
movsd %xmm0, 0x108(%rsp)
movq 0x120(%rsp), %rax
movsd (%rax), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0xa254
jp 0xa254
jmp 0xa2a7
movq 0x120(%rsp), %rax
movsd (%rax), %xmm0
callq 0x2110
movsd %xmm0, 0x38(%rsp)
movq 0x120(%rsp), %rax
movsd (%rax), %xmm0
movq 0x128(%rsp), %rax
divsd (%rax), %xmm0
callq 0x2110
movaps %xmm0, %xmm1
movsd 0x38(%rsp), %xmm0
subsd %xmm1, %xmm0
addsd 0x118(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
movq 0x40(%rsp), %rax
movq 0x120(%rsp), %rcx
movsd (%rcx), %xmm0
movl 0x4(%rax), %eax
cvtsi2sd %rax, %xmm1
addsd %xmm1, %xmm0
callq 0x2110
movq 0x40(%rsp), %rax
movsd %xmm0, 0x20(%rsp)
movl (%rax), %eax
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x28(%rsp)
movq 0x128(%rsp), %rax
movsd (%rax), %xmm0
callq 0x2130
movsd 0x20(%rsp), %xmm1
movq 0x40(%rsp), %rax
movaps %xmm0, %xmm2
movsd 0x28(%rsp), %xmm0
mulsd %xmm2, %xmm0
subsd %xmm1, %xmm0
movsd %xmm0, 0x30(%rsp)
movq 0x120(%rsp), %rcx
movsd (%rcx), %xmm0
movq 0x128(%rsp), %rcx
movsd (%rcx), %xmm1
divsd %xmm1, %xmm0
movl (%rax), %eax
cvtsi2sd %rax, %xmm1
addsd %xmm1, %xmm0
callq 0x2110
movaps %xmm0, %xmm1
movsd 0x30(%rsp), %xmm0
addsd %xmm1, %xmm0
addsd 0x118(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
movsd 0x118(%rsp), %xmm0
callq 0xaac0
testb $0x1, %al
jne 0xa373
jmp 0xa375
jmp 0xa394
leaq 0xb2b9(%rip), %rdi      # 0x15635
leaq 0xb231(%rip), %rsi      # 0x155b4
movl $0x148, %edx            # imm = 0x148
leaq 0xb232(%rip), %rcx      # 0x155c1
callq 0x20e0
movq 0x40(%rsp), %rax
addq $0x8, %rax
movq %rax, 0x100(%rsp)
movq 0x100(%rsp), %rdi
callq 0xab00
movq %rax, 0xf8(%rsp)
movq 0x100(%rsp), %rdi
callq 0xab30
movq %rax, 0xf0(%rsp)
leaq 0xf8(%rsp), %rdi
leaq 0xf0(%rsp), %rsi
callq 0xab60
testb $0x1, %al
jne 0xa3ed
jmp 0xa4f8
leaq 0xf8(%rsp), %rdi
callq 0xab80
movq %rax, 0xe8(%rsp)
movq 0xe8(%rsp), %rax
addq $0x8, %rax
addq $0x8, %rax
movq %rax, 0xe0(%rsp)
movq 0xe0(%rsp), %rsi
leaq 0xc8(%rsp), %rdi
callq 0xaba0
movq 0xe0(%rsp), %rsi
leaq 0xb0(%rsp), %rdi
callq 0xabd0
leaq 0xc8(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0xac00
testb $0x1, %al
jne 0xa462
jmp 0xa4e4
leaq 0xc8(%rsp), %rdi
callq 0xac30
movq %rax, 0xa8(%rsp)
movq 0xa8(%rsp), %rax
movl (%rax), %eax
cvtsi2sd %rax, %xmm0
movq 0x128(%rsp), %rax
movsd (%rax), %xmm1
subsd %xmm1, %xmm0
callq 0x2110
movsd 0x108(%rsp), %xmm1
subsd %xmm1, %xmm0
movq 0xa8(%rsp), %rax
movl 0x4(%rax), %eax
cvtsi2sd %rax, %xmm2
movsd 0x118(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x118(%rsp)
leaq 0xc8(%rsp), %rdi
callq 0xac80
jmp 0xa444
jmp 0xa4e6
leaq 0xf8(%rsp), %rdi
callq 0xacd0
jmp 0xa3cf
jmp 0xa732
movq 0x128(%rsp), %rax
movsd (%rax), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0xa711
jp 0xa711
movq 0x120(%rsp), %rax
movsd (%rax), %xmm0
callq 0x2110
movq 0x40(%rsp), %rax
movsd %xmm0, 0x8(%rsp)
movl (%rax), %eax
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x10(%rsp)
movq 0x120(%rsp), %rax
movsd (%rax), %xmm0
callq 0x2130
movsd 0x8(%rsp), %xmm1
movq 0x40(%rsp), %rax
movaps %xmm0, %xmm2
movsd 0x10(%rsp), %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x18(%rsp)
movq 0x120(%rsp), %rcx
movsd (%rcx), %xmm0
movl 0x4(%rax), %eax
cvtsi2sd %rax, %xmm1
addsd %xmm1, %xmm0
callq 0x2110
movaps %xmm0, %xmm1
movsd 0x18(%rsp), %xmm0
subsd %xmm1, %xmm0
addsd 0x118(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
movsd 0x118(%rsp), %xmm0
callq 0xaac0
testb $0x1, %al
jne 0xa5c8
jmp 0xa5ca
jmp 0xa5e9
leaq 0xb064(%rip), %rdi      # 0x15635
leaq 0xafdc(%rip), %rsi      # 0x155b4
movl $0x158, %edx            # imm = 0x158
leaq 0xafdd(%rip), %rcx      # 0x155c1
callq 0x20e0
movq 0x40(%rsp), %rax
addq $0x8, %rax
movq %rax, 0xa0(%rsp)
movq 0xa0(%rsp), %rdi
callq 0xab00
movq %rax, 0x98(%rsp)
movq 0xa0(%rsp), %rdi
callq 0xab30
movq %rax, 0x90(%rsp)
leaq 0x98(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0xab60
testb $0x1, %al
jne 0xa642
jmp 0xa70f
leaq 0x98(%rsp), %rdi
callq 0xab80
movq %rax, 0x88(%rsp)
movq 0x88(%rsp), %rax
addq $0x8, %rax
addq $0x8, %rax
movq %rax, 0x80(%rsp)
movq 0x80(%rsp), %rsi
leaq 0x68(%rsp), %rdi
callq 0xaba0
movq 0x80(%rsp), %rsi
leaq 0x50(%rsp), %rdi
callq 0xabd0
leaq 0x68(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0xac00
testb $0x1, %al
jne 0xa6a8
jmp 0xa6fb
leaq 0x68(%rsp), %rdi
callq 0xac30
movq %rax, 0x48(%rsp)
movq 0x48(%rsp), %rax
movl (%rax), %eax
cvtsi2sd %rax, %xmm0
callq 0x2110
movq 0x48(%rsp), %rax
movl 0x4(%rax), %eax
cvtsi2sd %rax, %xmm2
movsd 0x118(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x118(%rsp)
leaq 0x68(%rsp), %rdi
callq 0xac80
jmp 0xa693
jmp 0xa6fd
leaq 0x98(%rsp), %rdi
callq 0xacd0
jmp 0xa624
jmp 0xa730
leaq 0xaf2f(%rip), %rdi      # 0x15647
leaq 0xae95(%rip), %rsi      # 0x155b4
movl $0x15d, %edx            # imm = 0x15D
leaq 0xae96(%rip), %rcx      # 0x155c1
callq 0x20e0
jmp 0xa732
jmp 0xa734
movsd 0x118(%rsp), %xmm0
callq 0xaac0
testb $0x1, %al
jne 0xa748
jmp 0xa74a
jmp 0xa769
leaq 0xaee4(%rip), %rdi      # 0x15635
leaq 0xae5c(%rip), %rsi      # 0x155b4
movl $0x160, %edx            # imm = 0x160
leaq 0xae5d(%rip), %rcx      # 0x155c1
callq 0x20e0
movsd 0x118(%rsp), %xmm0
addq $0x138, %rsp            # imm = 0x138
retq
nopw (%rax,%rax)