// File: adamiaonr[P]rid-analytics/src/prob.cpp
// Function: Prob::calc_lm_prob(unsigned char, Prob::fp_data*, std::map<int, std::vector<unsigned char, std::allocator<unsigned char>>, std::less<int>, std::allocator<std::pair<int const, std::vector<unsigned char, std::allocator<unsigned char>>>>>*, bool)
int Prob::calc_lm_prob(
    uint8_t i, 
    Prob::fp_data * iface_fp_data,
    std::map<int, std::vector<uint8_t> > * tree_bitmasks,
    bool iface_complement) {

    // either 'i' or '~i (complement)' largest match probs
    std::vector<std::vector<std::vector<__float080> > > * lmp;
    if (!iface_complement) lmp = &(this->lm_cond_prob);
    else lmp = &(this->lm_complement_cond_prob);

    // aux. arrays used in fp rate calculation:
    //  - P(|FP| =/= f) = (1.0 - P(|FP| = f)) : prob of not having an fp match of size f
    std::vector<__float080> log_prob_fp_neq(n, 0.0);
    //  - P(|FP| <= f) : prob of fp match smaller than or equal to f
    std::vector<__float080> log_prob_fp_smeq(n + 1, 0.0);

    // if there are no entries for this iface, a match is impossible
    // as such, match size f = 0 has prob 1.0 of happening
    if (iface_fp_data->is_blocked) { 
        for (int t = (int) this->n; t >= 0; t--) (*lmp)[i][t][0] = 1.0;
        return 0; 
    }

    if (iface_fp_data->num_entries < 1.0) {
        for (int t = (int) this->n; t >= 0; t--) (*lmp)[i][t][0] = 1.0;
        return 0;
    }

    // calc the ratio of trees which can origin FP trees locally at the router
    // std::cout << "Prob::calc_lm_prob(iface) : [INFO] lt ratio iface  " << (iface_complement ? "~" : "") << (int) i << " :" << std::endl;
    // std::vector<__float080> lt_ratios(n, 0.0);
    // local_tree_ratios(iface_fp_data, tree_bitmasks, lt_ratios);
    std::vector<__float080> lt_ratios = std::vector<__float080>(n, 1.0);

    // std::cout << "Prob::calc_lm_prob(iface) : [INFO] iface " << (iface_complement ? "~" : "") << ((int) i) << " stats :"
    //     << "\n\t [n, m, k] : " << this->n << ", " << this->m << ", " << this->k << ")";
        // << "\n\t [# entries] : " << iface_fp_data->num_entries << " (" << (iface_fp_data->num_entries * lt_ratio) << ")";
    //     << "\t\n [lmp size] : " << (*lmp).size()
    //     << "\t\n [f_distr] : ";
    // for(uint8_t f = 0; f < this->n; f++) 
    //     std::cout << "[" << (int) f << "] = " << iface_fp_data->f_distr[f] << ", ";
    // std::cout << std::endl;

    // fill P(|FP| =/= f) = (1.0 - P(|FP| = f)), for all f
    calc_log_prob_fp_neq(iface_fp_data, log_prob_fp_neq, lt_ratios);
    // calc P(|FP| <= f), for all f
    for (int f = (int) (this->n - 1); f >= 0; f--)
        log_prob_fp_smeq[f] = log_prob_fp_smeq[f + 1] + log_prob_fp_neq[f];

    for (int t = (int) this->n; t >= 0; t--) {
        for (int f = (int) this->n; f >= 0; f--) {
            _calc_lm_prob(
                f, t, 
                iface_fp_data, 
                &log_prob_fp_neq, &log_prob_fp_smeq,
                &((*lmp)[i][t]));
        }
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1e0, %rsp            # imm = 0x1E0
movb %r8b, %al
movq %rdi, -0x10(%rbp)
movb %sil, -0x11(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
andb $0x1, %al
movb %al, -0x29(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x168(%rbp)
testb $0x1, -0x29(%rbp)
jne 0x5a731
movq -0x168(%rbp), %rax
movq %rax, -0x38(%rbp)
jmp 0x5a740
movq -0x168(%rbp), %rax
addq $0x18, %rax
movq %rax, -0x38(%rbp)
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
flds 0x8ea9(%rip)            # 0x635fc
fucomi %st(1), %st
setbe %al
fldz
fld %st(0)
fcmovbe %st(2), %st
fstp %st(2)
fxch %st(2)
fsubp %st, %st(1)
fnstcw -0x13e(%rbp)
movzwl -0x13e(%rbp), %ecx
orl $0xc00, %ecx            # imm = 0xC00
movw %cx, -0x140(%rbp)
fldcw -0x140(%rbp)
fistpll -0x118(%rbp)
fldcw -0x13e(%rbp)
movzbl %al, %eax
movl %eax, %ecx
shlq $0x3f, %rcx
movq -0x118(%rbp), %rax
xorq %rcx, %rax
movq %rax, -0x178(%rbp)
fstpt -0x60(%rbp)
leaq -0x61(%rbp), %rdi
movq %rdi, -0x170(%rbp)
callq 0x34a40
movq -0x178(%rbp), %rsi
movq -0x170(%rbp), %rcx
leaq -0x50(%rbp), %rdi
leaq -0x60(%rbp), %rdx
callq 0x34a60
jmp 0x5a7da
leaq -0x61(%rbp), %rdi
callq 0x34b70
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
fld1
faddp %st, %st(1)
flds 0x8e02(%rip)            # 0x635fc
fxch %st(1)
fucomi %st(1), %st
fldz
fld %st(0)
fcmovnb %st(3), %st
fstp %st(3)
fxch %st(1)
fsubp %st, %st(2)
setae %al
fnstcw -0x142(%rbp)
movzwl -0x142(%rbp), %ecx
orl $0xc00, %ecx            # imm = 0xC00
movw %cx, -0x144(%rbp)
fldcw -0x144(%rbp)
fxch %st(1)
fistpll -0x120(%rbp)
fldcw -0x142(%rbp)
movzbl %al, %eax
movl %eax, %ecx
shlq $0x3f, %rcx
movq -0x120(%rbp), %rax
xorq %rcx, %rax
movq %rax, -0x188(%rbp)
fstpt -0xa0(%rbp)
leaq -0xa1(%rbp), %rdi
movq %rdi, -0x180(%rbp)
callq 0x34a40
movq -0x188(%rbp), %rsi
movq -0x180(%rbp), %rcx
leaq -0x90(%rbp), %rdi
leaq -0xa0(%rbp), %rdx
callq 0x34a60
jmp 0x5a891
leaq -0xa1(%rbp), %rdi
callq 0x34b70
movq -0x20(%rbp), %rax
testb $0x1, 0xb8(%rax)
je 0x5a987
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
fnstcw -0x146(%rbp)
movzwl -0x146(%rbp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, -0x148(%rbp)
fldcw -0x148(%rbp)
fistpl -0x13c(%rbp)
fldcw -0x146(%rbp)
movl -0x13c(%rbp), %eax
movl %eax, -0xa8(%rbp)
cmpl $0x0, -0xa8(%rbp)
jl 0x5a971
movq -0x38(%rbp), %rdi
movzbl -0x11(%rbp), %eax
movl %eax, %esi
callq 0x5d910
movq %rax, %rdi
movslq -0xa8(%rbp), %rsi
callq 0x358a0
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x34c70
fld1
fstpt (%rax)
movl -0xa8(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0xa8(%rbp)
jmp 0x5a8f2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x61(%rbp), %rdi
callq 0x34b70
jmp 0x5ade4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0xa1(%rbp), %rdi
callq 0x34b70
jmp 0x5addb
movl $0x0, -0x4(%rbp)
movl $0x1, -0xac(%rbp)
jmp 0x5adae
movq -0x20(%rbp), %rax
fldt 0x10(%rax)
fld1
fucompi %st(1), %st
fstp %st(0)
jbe 0x5aa3e
jmp 0x5a99c
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
fnstcw -0x14a(%rbp)
movzwl -0x14a(%rbp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, -0x14c(%rbp)
fldcw -0x14c(%rbp)
fistpl -0x138(%rbp)
fldcw -0x14a(%rbp)
movl -0x138(%rbp), %eax
movl %eax, -0xb0(%rbp)
cmpl $0x0, -0xb0(%rbp)
jl 0x5aa28
movq -0x38(%rbp), %rdi
movzbl -0x11(%rbp), %eax
movl %eax, %esi
callq 0x5d910
movq %rax, %rdi
movslq -0xb0(%rbp), %rsi
callq 0x358a0
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x34c70
fld1
fstpt (%rax)
movl -0xb0(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0xb0(%rbp)
jmp 0x5a9e0
movl $0x0, -0x4(%rbp)
movl $0x1, -0xac(%rbp)
jmp 0x5adae
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
flds 0x8bab(%rip)            # 0x635fc
fucomi %st(1), %st
setbe %al
fldz
fcmovbe %st(1), %st
fstp %st(1)
fsubrp %st, %st(1)
fnstcw -0x14e(%rbp)
movzwl -0x14e(%rbp), %ecx
orl $0xc00, %ecx            # imm = 0xC00
movw %cx, -0x150(%rbp)
fldcw -0x150(%rbp)
fistpll -0x128(%rbp)
fldcw -0x14e(%rbp)
movzbl %al, %eax
movl %eax, %ecx
shlq $0x3f, %rcx
movq -0x128(%rbp), %rax
xorq %rcx, %rax
movq %rax, -0x198(%rbp)
fld1
fstpt -0xe0(%rbp)
leaq -0xe1(%rbp), %rdi
movq %rdi, -0x190(%rbp)
callq 0x34a40
movq -0x198(%rbp), %rsi
movq -0x190(%rbp), %rcx
leaq -0xc8(%rbp), %rdi
leaq -0xe0(%rbp), %rdx
callq 0x34a60
jmp 0x5aae2
leaq -0xe1(%rbp), %rdi
callq 0x34b70
movq -0x20(%rbp), %rax
movq %rax, -0x1a0(%rbp)
leaq -0x100(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x36d30
jmp 0x5ab0e
movq -0x1a0(%rbp), %rsi
movq -0x168(%rbp), %rdi
leaq -0x50(%rbp), %rdx
leaq -0x100(%rbp), %rcx
callq 0x59b60
jmp 0x5ab2e
leaq -0x100(%rbp), %rdi
callq 0x34b10
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
fld1
fchs
faddp %st, %st(1)
fnstcw -0x152(%rbp)
movzwl -0x152(%rbp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, -0x154(%rbp)
fldcw -0x154(%rbp)
fistpl -0x12c(%rbp)
fldcw -0x152(%rbp)
movl -0x12c(%rbp), %eax
movl %eax, -0x104(%rbp)
cmpl $0x0, -0x104(%rbp)
jl 0x5ac4e
movl -0x104(%rbp), %eax
incl %eax
movslq %eax, %rsi
leaq -0x90(%rbp), %rdi
movq %rdi, -0x1b8(%rbp)
callq 0x34c70
fldt (%rax)
fstpt -0x1c4(%rbp)
movslq -0x104(%rbp), %rsi
leaq -0x50(%rbp), %rdi
callq 0x34c70
fldt -0x1c4(%rbp)
movq -0x1b8(%rbp), %rdi
fldt (%rax)
faddp %st, %st(1)
fstpt -0x1ac(%rbp)
movslq -0x104(%rbp), %rsi
callq 0x34c70
fldt -0x1ac(%rbp)
fstpt (%rax)
movl -0x104(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x104(%rbp)
jmp 0x5ab84
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0xe1(%rbp), %rdi
callq 0x34b70
jmp 0x5adcf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x5ada0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x100(%rbp), %rdi
callq 0x34b10
jmp 0x5ada0
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
fnstcw -0x156(%rbp)
movzwl -0x156(%rbp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, -0x158(%rbp)
fldcw -0x158(%rbp)
fistpl -0x130(%rbp)
fldcw -0x156(%rbp)
movl -0x130(%rbp), %eax
movl %eax, -0x108(%rbp)
cmpl $0x0, -0x108(%rbp)
jl 0x5ad81
movq -0x168(%rbp), %rax
fldt 0x90(%rax)
fnstcw -0x15a(%rbp)
movzwl -0x15a(%rbp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, -0x15c(%rbp)
fldcw -0x15c(%rbp)
fistpl -0x134(%rbp)
fldcw -0x15a(%rbp)
movl -0x134(%rbp), %eax
movl %eax, -0x10c(%rbp)
cmpl $0x0, -0x10c(%rbp)
jl 0x5ad6b
movl -0x10c(%rbp), %eax
movl %eax, -0x1d8(%rbp)
movl -0x108(%rbp), %eax
movl %eax, -0x1d4(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x1d0(%rbp)
movq -0x38(%rbp), %rdi
movzbl -0x11(%rbp), %eax
movl %eax, %esi
callq 0x5d910
movq %rax, %rdi
movslq -0x108(%rbp), %rsi
callq 0x358a0
movl -0x1d8(%rbp), %edi
movl -0x1d4(%rbp), %esi
movq -0x1d0(%rbp), %rdx
movq %rax, %r9
leaq -0x50(%rbp), %rcx
leaq -0x90(%rbp), %r8
callq 0x5a050
jmp 0x5ad55
jmp 0x5ad57
movl -0x10c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x10c(%rbp)
jmp 0x5ace3
jmp 0x5ad6d
movl -0x108(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x108(%rbp)
jmp 0x5ac92
movl $0x0, -0x4(%rbp)
movl $0x1, -0xac(%rbp)
leaq -0xc8(%rbp), %rdi
callq 0x34b10
jmp 0x5adae
leaq -0xc8(%rbp), %rdi
callq 0x34b10
jmp 0x5adcf
leaq -0x90(%rbp), %rdi
callq 0x34b10
leaq -0x50(%rbp), %rdi
callq 0x34b10
movl -0x4(%rbp), %eax
addq $0x1e0, %rsp            # imm = 0x1E0
popq %rbp
retq
leaq -0x90(%rbp), %rdi
callq 0x34b10
leaq -0x50(%rbp), %rdi
callq 0x34b10
movq -0x70(%rbp), %rdi
callq 0x5920
nopl (%rax)