// File: millanek[P]evo/./process_vcf_stats_utils.h
// Function: fisher_exact(int, int, int, int)
inline double fisher_exact(int a, int b, int c, int d) {
    
    std::vector<int> mTotals;
    int r1 = a + b; int r2 = c + d;
    int c1 = a + c; int c2 = b + d;
    mTotals.push_back(r1); mTotals.push_back(r2); mTotals.push_back(c1); mTotals.push_back(c2);
    int m = std::min(std::min(r1, r2), std::min(c1,c2)); // The smallest margin total
    // int min_index = (int)(std::min_element(mTotals.begin(), mTotals.end()) - mTotals.begin()); // Position of the ssmallest margin total
    
    std::vector<double> allPvals;
    if (m == c2) {
        for (int i = 0; i <= m; i++) {
            double thisP = fisher_exactTable(r1-i,i,r2-(m-i),m-i);
            allPvals.push_back(thisP);
        }
    } else if (m == c1) {
        for (int i = 0; i <= m; i++) {
            double thisP = fisher_exactTable(i,r1-i,m-i,r2-(m-i));
            allPvals.push_back(thisP);
        }
    } else if (m == r2) {
        for (int i = 0; i <= m; i++) {
            double thisP = fisher_exactTable(c1-(m-i),c2-i,m-i,i);
            allPvals.push_back(thisP);
        }
    } else if (m == r1){
        for (int i = 0; i <= m; i++) {
            double thisP = fisher_exactTable(m-i,i,c1-(m-i),c2-i);
            allPvals.push_back(thisP);
        }
    } else {
        std::cerr << "a: " << a << " b: " << b << std::endl;
        std::cerr << "c: " << c << " d: " << d << std::endl;
        std::cerr << "m: " << m << " c1: " << c1 << " c2: " << c2 << " r1: " << r1 << " r2: " << r2 << std::endl;
        assert(false);
    }
    
    double thisTablePval = fisher_exactTable(a,b,c,d);
    double p = 0;
    for (std::vector<double>::size_type i = 0; i != allPvals.size(); i++) {
        if (allPvals[i] <= thisTablePval) {
            p += allPvals[i];
        }
    }
    /*if (m == r2) {
        std::cerr << "a: " << a << " b: " << b << std::endl;
        std::cerr << "c: " << c << " d: " << d << std::endl;
        std::cerr << "p: " << p << std::endl;
    } */
    
//    std::cerr << "this pval:" << thisTablePval << std::endl;
//    print_vector_stream(allPvals, std::cerr);
    return p;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1a0, %rsp            # imm = 0x1A0
movl %edi, -0x4(%rbp)
movl %esi, -0x8(%rbp)
movl %edx, -0xc(%rbp)
movl %ecx, -0x10(%rbp)
leaq -0x28(%rbp), %rdi
movq %rdi, -0xc0(%rbp)
callq 0x46270
movq -0xc0(%rbp), %rdi
movl -0x4(%rbp), %eax
movl -0x8(%rbp), %ecx
addl %ecx, %eax
movl %eax, -0x2c(%rbp)
movl -0xc(%rbp), %eax
movl -0x10(%rbp), %ecx
addl %ecx, %eax
movl %eax, -0x30(%rbp)
movl -0x4(%rbp), %eax
movl -0xc(%rbp), %ecx
addl %ecx, %eax
movl %eax, -0x34(%rbp)
movl -0x8(%rbp), %eax
movl -0x10(%rbp), %ecx
addl %ecx, %eax
movl %eax, -0x38(%rbp)
leaq -0x2c(%rbp), %rsi
callq 0x6b600
jmp 0xe3c35
leaq -0x28(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x6b600
jmp 0xe3c44
leaq -0x28(%rbp), %rdi
leaq -0x34(%rbp), %rsi
callq 0x6b600
jmp 0xe3c53
leaq -0x28(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x6b600
jmp 0xe3c62
leaq -0x2c(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0xe6240
movq %rax, -0xc8(%rbp)
jmp 0xe3c78
leaq -0x34(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0xe6240
movq %rax, -0xd0(%rbp)
jmp 0xe3c8e
movq -0xd0(%rbp), %rsi
movq -0xc8(%rbp), %rdi
callq 0xe6240
movq %rax, -0xd8(%rbp)
jmp 0xe3caa
movq -0xd8(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x48(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x48410
movl -0x48(%rbp), %eax
cmpl -0x38(%rbp), %eax
jne 0xe3d54
movl $0x0, -0x64(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x48(%rbp), %eax
jg 0xe3d4f
movl -0x2c(%rbp), %edi
movl -0x64(%rbp), %esi
subl %esi, %edi
movl -0x30(%rbp), %edx
movl -0x48(%rbp), %ecx
subl %esi, %ecx
subl %ecx, %edx
callq 0xe6280
movsd %xmm0, -0xe0(%rbp)
jmp 0xe3cfb
movsd -0xe0(%rbp), %xmm0
movsd %xmm0, -0x70(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0xb77b0
jmp 0xe3d17
jmp 0xe3d19
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0xe3cd2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0xe41e1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x3ecb0
jmp 0xe41e1
jmp 0xe40e8
movl -0x48(%rbp), %eax
cmpl -0x34(%rbp), %eax
jne 0xe3dba
movl $0x0, -0x74(%rbp)
movl -0x74(%rbp), %eax
cmpl -0x48(%rbp), %eax
jg 0xe3db5
movl -0x74(%rbp), %edi
movl -0x2c(%rbp), %esi
subl %edi, %esi
movl -0x48(%rbp), %edx
subl %edi, %edx
movl -0x30(%rbp), %ecx
subl %edx, %ecx
callq 0xe6280
movsd %xmm0, -0xe8(%rbp)
jmp 0xe3d8c
movsd -0xe8(%rbp), %xmm0
movsd %xmm0, -0x80(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0xb77b0
jmp 0xe3da8
jmp 0xe3daa
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0xe3d63
jmp 0xe40e6
movl -0x48(%rbp), %eax
cmpl -0x30(%rbp), %eax
jne 0xe3e35
movl $0x0, -0x84(%rbp)
movl -0x84(%rbp), %eax
cmpl -0x48(%rbp), %eax
jg 0xe3e30
movl -0x34(%rbp), %edi
movl -0x48(%rbp), %edx
movl -0x84(%rbp), %ecx
subl %ecx, %edx
subl %edx, %edi
movl -0x38(%rbp), %esi
subl %ecx, %esi
callq 0xe6280
movsd %xmm0, -0xf0(%rbp)
jmp 0xe3dfb
movsd -0xf0(%rbp), %xmm0
movsd %xmm0, -0x90(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0xb77b0
jmp 0xe3e1d
jmp 0xe3e1f
movl -0x84(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x84(%rbp)
jmp 0xe3dcc
jmp 0xe40e4
movl -0x48(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jne 0xe3eb0
movl $0x0, -0x94(%rbp)
movl -0x94(%rbp), %eax
cmpl -0x48(%rbp), %eax
jg 0xe3eab
movl -0x48(%rbp), %edi
movl -0x94(%rbp), %esi
subl %esi, %edi
movl -0x34(%rbp), %edx
subl %edi, %edx
movl -0x38(%rbp), %ecx
subl %esi, %ecx
callq 0xe6280
movsd %xmm0, -0xf8(%rbp)
jmp 0xe3e76
movsd -0xf8(%rbp), %xmm0
movsd %xmm0, -0xa0(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0xb77b0
jmp 0xe3e98
jmp 0xe3e9a
movl -0x94(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x94(%rbp)
jmp 0xe3e47
jmp 0xe40e2
movq 0xb5139(%rip), %rdi     # 0x198ff0
leaq 0x641c0(%rip), %rsi     # 0x14807e
callq 0xa5c0
movq %rax, -0x100(%rbp)
jmp 0xe3ecc
movq -0x100(%rbp), %rdi
movl -0x4(%rbp), %esi
callq 0xab20
movq %rax, -0x108(%rbp)
jmp 0xe3ee4
movq -0x108(%rbp), %rdi
leaq 0x64190(%rip), %rsi     # 0x148082
callq 0xa5c0
movq %rax, -0x110(%rbp)
jmp 0xe3f00
movq -0x110(%rbp), %rdi
movl -0x8(%rbp), %esi
callq 0xab20
movq %rax, -0x118(%rbp)
jmp 0xe3f18
movq -0x118(%rbp), %rdi
movq 0xb5062(%rip), %rsi     # 0x198f88
callq 0xa610
jmp 0xe3f2d
movq 0xb50bc(%rip), %rdi     # 0x198ff0
leaq 0x59c8d(%rip), %rsi     # 0x13dbc8
callq 0xa5c0
movq %rax, -0x120(%rbp)
jmp 0xe3f49
movq -0x120(%rbp), %rdi
movl -0xc(%rbp), %esi
callq 0xab20
movq %rax, -0x128(%rbp)
jmp 0xe3f61
movq -0x128(%rbp), %rdi
leaq 0x64118(%rip), %rsi     # 0x148087
callq 0xa5c0
movq %rax, -0x130(%rbp)
jmp 0xe3f7d
movq -0x130(%rbp), %rdi
movl -0x10(%rbp), %esi
callq 0xab20
movq %rax, -0x138(%rbp)
jmp 0xe3f95
movq -0x138(%rbp), %rdi
movq 0xb4fe5(%rip), %rsi     # 0x198f88
callq 0xa610
jmp 0xe3faa
movq 0xb503f(%rip), %rdi     # 0x198ff0
leaq 0x5f940(%rip), %rsi     # 0x1438f8
callq 0xa5c0
movq %rax, -0x140(%rbp)
jmp 0xe3fc6
movq -0x140(%rbp), %rdi
movl -0x48(%rbp), %esi
callq 0xab20
movq %rax, -0x148(%rbp)
jmp 0xe3fde
movq -0x148(%rbp), %rdi
leaq 0x640a0(%rip), %rsi     # 0x14808c
callq 0xa5c0
movq %rax, -0x150(%rbp)
jmp 0xe3ffa
movq -0x150(%rbp), %rdi
movl -0x34(%rbp), %esi
callq 0xab20
movq %rax, -0x158(%rbp)
jmp 0xe4012
movq -0x158(%rbp), %rdi
leaq 0x64072(%rip), %rsi     # 0x148092
callq 0xa5c0
movq %rax, -0x160(%rbp)
jmp 0xe402e
movq -0x160(%rbp), %rdi
movl -0x38(%rbp), %esi
callq 0xab20
movq %rax, -0x168(%rbp)
jmp 0xe4046
movq -0x168(%rbp), %rdi
leaq 0x64044(%rip), %rsi     # 0x148098
callq 0xa5c0
movq %rax, -0x170(%rbp)
jmp 0xe4062
movq -0x170(%rbp), %rdi
movl -0x2c(%rbp), %esi
callq 0xab20
movq %rax, -0x178(%rbp)
jmp 0xe407a
movq -0x178(%rbp), %rdi
leaq 0x64016(%rip), %rsi     # 0x14809e
callq 0xa5c0
movq %rax, -0x180(%rbp)
jmp 0xe4096
movq -0x180(%rbp), %rdi
movl -0x30(%rbp), %esi
callq 0xab20
movq %rax, -0x188(%rbp)
jmp 0xe40ae
movq -0x188(%rbp), %rdi
movq 0xb4ecc(%rip), %rsi     # 0x198f88
callq 0xa610
jmp 0xe40c3
leaq 0x555f3(%rip), %rdi     # 0x1396bd
leaq 0x5738c(%rip), %rsi     # 0x13b45d
movl $0xd7, %edx
leaq 0x63fc7(%rip), %rcx     # 0x1480a4
callq 0xa390
jmp 0xe40e4
jmp 0xe40e6
jmp 0xe40e8
movl -0x4(%rbp), %edi
movl -0x8(%rbp), %esi
movl -0xc(%rbp), %edx
movl -0x10(%rbp), %ecx
callq 0xe6280
movsd %xmm0, -0x190(%rbp)
jmp 0xe4103
movsd -0x190(%rbp), %xmm0
movsd %xmm0, -0xa8(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0xb0(%rbp)
movq $0x0, -0xb8(%rbp)
movq -0xb8(%rbp), %rax
movq %rax, -0x198(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x3ebf0
movq %rax, %rcx
movq -0x198(%rbp), %rax
cmpq %rcx, %rax
je 0xe41ae
movq -0xb8(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x3ec30
movsd (%rax), %xmm1
movsd -0xa8(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jb 0xe4195
movq -0xb8(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x3ec30
movsd (%rax), %xmm0
addsd -0xb0(%rbp), %xmm0
movsd %xmm0, -0xb0(%rbp)
jmp 0xe4197
movq -0xb8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb8(%rbp)
jmp 0xe4129
movsd -0xb0(%rbp), %xmm0
movsd %xmm0, -0x1a0(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x3ecb0
leaq -0x28(%rbp), %rdi
callq 0x48290
movsd -0x1a0(%rbp), %xmm0
addq $0x1a0, %rsp            # imm = 0x1A0
popq %rbp
retq
leaq -0x28(%rbp), %rdi
callq 0x48290
movq -0x40(%rbp), %rdi
callq 0xab50
nopw %cs:(%rax,%rax)
nopl (%rax)