// File: /workspace/github_cpp_makefile_star2_O3/adamiaonr[P]rid-analytics/src/prob.cpp
// Function: Prob::calc_iface_prob(unsigned char, std::vector<std::vector<Prob::fp_data*, std::allocator<Prob::fp_data*>>, std::allocator<std::vector<Prob::fp_data*, std::allocator<Prob::fp_data*>>>>*, std::vector<long double, std::allocator<long double>>*, std::vector<long double, std::allocator<long double>>&)
int Prob::calc_iface_prob(
    uint8_t i, 
    std::vector<std::vector<Prob::fp_data *> > * iface_fp_data,
    std::vector<__float080> * in_fptree_prob,
    std::vector<__float080> & iface_prob) {

    //  - P(L_i | T_i = 0, A) and P(L_~i | T_~i = 0, A)
    std::vector<std::vector<__float080> > event_a(2, std::vector<__float080> ((this->n + 1), 0.0));
    calc_lm_prob(i, 0, (*iface_fp_data)[0][i], &event_a[0]);
    calc_lm_prob(i, 0, (*iface_fp_data)[1][i], &event_a[1]);

    // 1) calc P(L_i = l) and P(L_{~i} = l), for all l
    for (int f = this->n; f >= 0; f--) {

        // P(L_i, T_i = 0) is a special case, influenced by 2 mutually exclusive 
        // events, say A and B:
        //
        //  - A : a request comes into the router while *not* associated w/ 
        //        a tree of any size t. 
        //        in this case, none of the ifaces can be associated w/ 
        //        a fp tree of any size, yielding:
        //          - P(T_i = 0) = 1.0
        //          - P(T_i > 0) = 0.0
        //
        //        this can happen iff a TP match and no FP matches happened 
        //        in the previous router.
        //        
        //  - B : say the req. comes into the router associated w/ a tree of some size t (t > 0).
        //        in this this case iface i can either be associated or not 
        //        associated w/ a fp tree of size t > 0, yielding:
        //          - P(T_i = 0) = 1.0 - SUM {for all t > 0} [ srt[i][t] * P(T_in = t) ]
        //          - P(T_i > 0) = srt[i][t] * P(T_in = t)
        //         
        // finally, P(L_i, T_i = 0) = 
        //      P(T_in = 0) * (P(L_i | T_i = 0, A) * P(T_i = 0, A))         // event A
        //      + (1 - P(T_in = 0)) * (P(L_i | T_i = 0, B) * T_i = 0, B)    // event B

        // - P(L_i, T_i = 0)
        __float080 __joint_prob = 
            ((*in_fptree_prob)[0] * event_a[0][f] * (((*iface_fp_data)[0][i]->is_blocked && (f > 0)) ? 0.0 : 1.0))
            + ((1.0 - (*in_fptree_prob)[0]) * (this->lm_cond_prob[i][0][f] * this->fptree_prob[0][i][0]));
        lm_marg_prob[i][f] += __joint_prob;

        // if (__joint_prob > 0.0 || __joint_prob < 0.0) {

        //     std::cout << "\t[0] = " << (*in_fptree_prob)[0] << std::endl;
        //     std::cout << "\t[1] = " << event_a[0][f] << std::endl;
        //     std::cout << "\t[2] = " << (((*iface_fp_data)[0][i]->is_blocked && (f > 0)) ? 0.0 : 1.0) << std::endl;
        //     std::cout << "\t[3] = " << (1.0 - (*in_fptree_prob)[0]) << std::endl;
        //     std::cout << "\t[4] = " << (this->lm_cond_prob[i][0][f]) << std::endl;
        //     std::cout << "\t[5] = " << (this->fptree_prob[0][i][0]) << std::endl;
        // }

        // - P(L_~i, T_~i = 0)
        __joint_prob = 
            ((*in_fptree_prob)[0] * event_a[1][f])
            + ((1.0 - (*in_fptree_prob)[0]) * (this->lm_complement_cond_prob[i][0][f] * this->fptree_prob[1][i][0]));
        lm_complement_marg_prob[i][f] += __joint_prob;

        for (uint8_t t = 1; t < (this->n + 1); t++) {

            // - P(L_i = l, T_i = t)
            __float080 joint_prob = (1.0 - (*in_fptree_prob)[0]) * (this->lm_cond_prob[i][t][f] * this->fptree_prob[0][i][t]);
            // add joint P(L_i = l, T_i = t) to marginal P(L_i = l)
            lm_marg_prob[i][f] += joint_prob;

            // print if P(L_i = l, T_i = t) > 0.0
            // if (joint_prob > 0.0 || joint_prob < 0.0) {
            //     std::cout << "\t[" << (int) t << "] +" 
            //         << (joint_prob) << " (" << this->lm_cond_prob[i][t][f] << " x " << this->fptree_prob[0][i][t] << ")"
            //         << " to P(L_" << (int) i << " = " << (int) f << ") = " << lm_marg_prob[i][f] << std::endl;
            // }

            // - P(L_{~i} = l, T_{~i} = t)
            joint_prob = 
                    (1.0 - (*in_fptree_prob)[0])
                    * this->lm_complement_cond_prob[i][t][f]    // P(L_{~i} = l | T_{~i} = t)
                    * this->fptree_prob[1][i][t];               // P(T_{~i} = t)
            // add the joint P(L_{~i} = l, T_{~i} = t) to marginal P(L_{~i} = l)
            lm_complement_marg_prob[i][f] += joint_prob;
            // print if P(L_{~i} = l, T_{~i} = t) > 0.0
            // if (joint_prob > 0.0 || joint_prob < 0.0) {
            //     std::cout << "\t[" << (int) t << "] +" 
            //         << (joint_prob) << " (" << this->lm_complement_cond_prob[i][t][f] << " x " << this->fptree_prob[1][i][t] << ")"
            //         << " to P(L_{~" << (int) i << "} = " << f << ") = " << lm_complement_marg_prob[i][f] << std::endl;
            // }
        }
    }

    // std::cout << "Prob::calc_iface_prob() : P(L_" << (int) i << " = l) :" << std::endl; 
    // for (int f = 0; f < this->n + 1; f++)
    //     std::cout << "\tP(L_" << (int) i << " = " << (int) f << ") = " << lm_marg_prob[i][f] << std::endl;

    // std::cout << "Prob::calc_iface_prob() : P(L_{~" << (int) i << "} = l) :" << std::endl; 
    // for (int f = 0; f < this->n + 1; f++)
    //     std::cout << "\tP(L_{~" << (int) i << "} = " << (int) f << ") = " << lm_complement_marg_prob[i][f] << std::endl;


    // 2) calc P(L_i >= L_{~i})
    for (int f = this->n; f >= 0; f--) {

        __float080 prob[4] = {0.0, 0.0, 0.0, 0.0};

        for (uint8_t k = 0; k < f; k++) {

            // a) L_i > [ L_{~i} AND L_0]
            // [ i ][~i ][ 0 ]
            //   2    0    0
            //   2    0    1
            //   2    1    0
            //   2    1    1
            //   1    0    0
            __float080 _p = (lm_marg_prob[i][f] * lm_complement_marg_prob[i][k]);

            if (i > 0) {

                for (uint8_t j = 0; j < f; j++) {
                    // std::cout << "\t (a) [" << (int) f << "][" << (int) k << "][" << (int) j << "]" << std::endl;
                    prob[0] += _p * lm_marg_prob[0][j];
                }

                // b) L_i == L_0 > L_{~i}
                // [ i ][~i ][ 0 ]
                //   2    0    2
                //   2    1    2
                //   1    0    1
                // std::cout << "\t (b) [" << (int) f << "][" << (int) k << "][" << (int) f << "]" << std::endl;
                prob[1] += (_p * lm_marg_prob[0][f]);

            } else {
                prob[0] += _p;
            }
        }

        // std::cout << "Prob::calc_iface_prob() : L_" << (int) i << " > [ L~{" << (int) i << "} AND L_0 ] [" << f << "] = " << prob[0] << std::endl;
        // std::cout << "Prob::calc_iface_prob() : L_" << (int) i << " [ > L~{" << (int) i << "} ] AND  [ = L_0 ] [" << f << "] = " << prob[1] << std::endl;

        __float080 __p = (lm_marg_prob[i][f] * lm_complement_marg_prob[i][f]);

        if (i > 0) {

            for (uint8_t k = 0; k < f; k++) {
                // c) L_i == L_{~i} > L_0
                // [ i ][~i ][ 0 ]
                //   2    2    0
                //   2    2    1
                //   1    1    0
                // std::cout << "\t (c) [" << (int) f << "][" << (int) f << "][" << (int) k << "]" << std::endl;
                prob[2] += (__p * lm_marg_prob[0][k]);
            }

            // d) L_i == L_{~i} == L_0
            // [ i ][~i ][ 0 ]
            //   2    2    2
            //   1    1    1
            //   0    0    0
            // std::cout << "\t (d) [" << (int) f << "][" << (int) f << "][" << (int) f << "]" << std::endl;
            prob[3] = (__p  * lm_marg_prob[0][f]);

        } else {
            prob[3] = __p;
        }

        // std::cout << "Prob::calc_iface_prob() : L_" << (int) i << " = L~{" << (int) i << "} > L_0 [" << f << "] = " << prob[2] << std::endl;
        // std::cout << "Prob::calc_iface_prob() : L_" << (int) i << " = L~{" << (int) i << "} = L_0)[" << f << "] = " << prob[3] << std::endl;

        iface_prob[0] += (prob[0]);                                 // P(L_i >  L_{~i}) : SINGLE MATCH ONLY
        iface_prob[1] += (prob[0] + prob[2]);                       // P(L_i >= L_{~i}) : MULTIPLE MATCH (NO LOCAL MATCHES)
        iface_prob[2] += (prob[0] + prob[1] + prob[2] + prob[3]);   // P(L_i >= L_{~i}) : MULTIPLE MATCH (W/ LOCAL MATCHES)

        // for (int k = 0; k < 3; k++)
        //     std::cout << "Prob::calc_iface_prob() : iface_prob[" << (int) k << "] = " << iface_prob[k] << std::endl;

        if ((iface_prob[2] < iface_prob[0]) && (i > 0))
            std::cout << "Prob::calc_iface_prob() : [ERROR] P(L_i > L_{~i}) > P(L_i > L_{~i}/0)" << std::endl;            
    }

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movq %rdi, %rbx
fldt 0x90(%rdi)
fld1
faddp %st, %st(1)
flds 0x5512(%rip)            # 0x305e0
xorl %eax, %eax
fxch %st(1)
fucomi %st(1), %st
fldz
fld %st(0)
fcmovnb %st(3), %st
fstp %st(3)
movq %r8, 0x40(%rsp)
movq %rcx, %r15
fxch %st(1)
fsubp %st, %st(2)
setae %al
fnstcw 0x14(%rsp)
movzwl 0x14(%rsp), %ecx
orl $0xc00, %ecx            # imm = 0xC00
movw %cx, 0x1a(%rsp)
fldcw 0x1a(%rsp)
movq %rdx, %r12
movl %esi, %ebp
fxch %st(1)
fistpll 0x68(%rsp)
fldcw 0x14(%rsp)
shlq $0x3f, %rax
xorq 0x68(%rsp), %rax
fstpt 0xa0(%rsp)
leaq 0x70(%rsp), %rdi
leaq 0xa0(%rsp), %rdx
leaq 0x1f(%rsp), %rcx
movq %rax, %rsi
callq 0x1d906
leaq 0x88(%rsp), %rdi
leaq 0x70(%rsp), %rdx
leaq 0x1e(%rsp), %rcx
movl $0x2, %esi
callq 0x1dca0
movq 0x70(%rsp), %rdi
testq %rdi, %rdi
je 0x2b172
movq 0x80(%rsp), %rsi
subq %rdi, %rsi
callq 0x43a0
movq (%r12), %rax
movzbl %bpl, %r14d
movq (%rax), %rax
movq (%rax,%r14,8), %rcx
movq 0x88(%rsp), %r8
movq %rbx, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x29e3c
movq (%r12), %rax
movq 0x18(%rax), %rax
movq (%rax,%r14,8), %rcx
movq 0x88(%rsp), %r8
addq $0x18, %r8
movq %rbx, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x29e3c
fldt 0x90(%rbx)
fnstcw 0x12(%rsp)
movzwl 0x12(%rsp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, 0x18(%rsp)
fldcw 0x18(%rsp)
fistpl 0x24(%rsp)
fldcw 0x12(%rsp)
movl 0x24(%rsp), %ecx
testl %ecx, %ecx
js 0x2b592
movq (%r15), %rax
movq 0x88(%rsp), %rdx
movq (%rdx), %rsi
movq %rsi, 0x60(%rsp)
movq 0x18(%rdx), %rdx
movq %rdx, 0x58(%rsp)
movq (%r12), %rdx
movq (%rdx), %rdx
movq %r14, 0x38(%rsp)
leal (,%r14,8), %esi
movq (%rdx,%rsi), %rdx
movb 0xb8(%rdx), %dl
movb %dl, 0xf(%rsp)
leaq (%rsi,%rsi,2), %rdx
movq (%rbx), %rsi
movq 0x18(%rbx), %r8
movq (%rsi,%rdx), %rdi
movq (%rdi), %rsi
movq %rsi, 0x50(%rsp)
movq 0x60(%rbx), %rsi
movq (%rsi), %r9
movq 0x18(%rsi), %rsi
movq (%r9,%rdx), %r9
movq 0x30(%rbx), %r10
movq (%r10,%rdx), %r10
movq %r10, 0x30(%rsp)
movq (%r8,%rdx), %r11
movq (%r11), %r8
movq %r8, 0x48(%rsp)
movq (%rsi,%rdx), %r15
movq 0x48(%rbx), %rsi
movq (%rsi,%rdx), %rdx
movq %rdx, 0x28(%rsp)
movl %ecx, %ecx
movq %rcx, %rdx
fldz
fstp %st(0)
fldt (%rax)
movq %rcx, %r13
shlq $0x4, %r13
cmpb $0x0, 0xf(%rsp)
fldz
fld1
fld %st(0)
fcmovne %st(2), %st
fstp %st(2)
movq 0x60(%rsp), %rsi
fldt (%rsi,%r13)
fmul %st(3), %st
addq $-0x1, %rdx
fld %st(1)
fcmovb %st(3), %st
fstp %st(3)
fxch %st(3)
fsubr %st(1), %st
movq 0x50(%rsp), %rsi
fldt (%rsi,%r13)
fldt (%r9)
fmulp %st, %st(1)
fmulp %st, %st(1)
fxch %st(3)
fmulp %st, %st(2)
fxch %st(1)
faddp %st, %st(2)
movq 0x30(%rsp), %rsi
fldt (%rsi,%r13)
faddp %st, %st(2)
fxch %st(1)
fstpt (%rsi,%r13)
fldt (%rax)
movq 0x58(%rsp), %rsi
fldt (%rsi,%r13)
fld %st(2)
fsub %st(2), %st
movq 0x48(%rsp), %rsi
fldt (%rsi,%r13)
fldt (%r15)
fmulp %st, %st(1)
fmulp %st, %st(1)
fxch %st(2)
fmulp %st, %st(1)
faddp %st, %st(1)
movq 0x28(%rsp), %rsi
fldt (%rsi,%r13)
faddp %st, %st(1)
fstpt (%rsi,%r13)
fldt 0x90(%rbx)
fld %st(0)
fadd %st(2), %st
fucompi %st(2), %st
fstp %st(1)
jbe 0x2b3ae
fstp %st(0)
movq 0x30(%rsp), %rsi
addq %r13, %rsi
movq 0x28(%rsp), %r8
addq %r13, %r8
movb $0x1, %r14b
fldz
fstp %st(0)
fldt (%rax)
fld1
fsub %st, %st(1)
movzbl %r14b, %r14d
leal (,%r14,8), %r10d
leaq (%r10,%r10,2), %r10
movq (%rdi,%r10), %r12
fldt (%r12,%r13)
movl %r14d, %r12d
shll $0x4, %r12d
fldt (%r9,%r12)
fmulp %st, %st(1)
fmulp %st, %st(2)
fldt (%rsi)
faddp %st, %st(2)
fxch %st(1)
fstpt (%rsi)
fldt (%rax)
fsubr %st(1), %st
movq (%r11,%r10), %r10
fldt (%r10,%r13)
fmulp %st, %st(1)
fldt (%r15,%r12)
fmulp %st, %st(1)
fldt (%r8)
faddp %st, %st(1)
fstpt (%r8)
incb %r14b
movzbl %r14b, %r10d
movw %r10w, 0x1c(%rsp)
filds 0x1c(%rsp)
fldt 0x90(%rbx)
fadd %st, %st(2)
fxch %st(2)
fucompi %st(1), %st
fstp %st(0)
ja 0x2b33a
testq %rcx, %rcx
movq %rdx, %rcx
jg 0x2b27f
fnstcw 0x10(%rsp)
movzwl 0x10(%rsp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, 0x16(%rsp)
fldcw 0x16(%rsp)
fistpl 0x20(%rsp)
fldcw 0x10(%rsp)
movl 0x20(%rsp), %eax
testl %eax, %eax
movq 0x38(%rsp), %rcx
js 0x2b592
movl %eax, %r14d
leaq (%rcx,%rcx,2), %r12
movq 0x13bc0(%rip), %r15     # 0x3efb8
movq %r14, %r13
movq 0x30(%rbx), %rax
movq (%rax,%r12,8), %rdx
movq %r14, %rcx
shlq $0x4, %rcx
subq $0x1, %r14
jae 0x2b43a
fldt (%rdx)
movq 0x48(%rbx), %rdx
movq (%rdx,%r12,8), %rdx
fldt (%rdx,%rcx)
fmulp %st, %st(1)
fldz
testb %bpl, %bpl
je 0x2b4e3
fstp %st(0)
movq (%rax), %rax
fldz
fld %st(0)
fld %st(1)
jmp 0x2b4d5
fldt (%rdx,%rcx)
movq 0x48(%rbx), %rdx
movq (%rdx,%r12,8), %rdx
fldz
xorl %esi, %esi
fld %st(0)
movzbl %sil, %edi
shll $0x4, %edi
fldt (%rdx,%rdi)
fmul %st(3), %st
testb %bpl, %bpl
je 0x2b48a
movq (%rax), %rdi
xorl %r8d, %r8d
movzbl %r8b, %r8d
movl %r8d, %r9d
shll $0x4, %r9d
fldt (%rdi,%r9)
fmul %st(1), %st
faddp %st, %st(2)
incb %r8b
movzbl %r8b, %r9d
cmpq %r9, %r13
ja 0x2b462
fldt (%rdi,%rcx)
fmulp %st, %st(1)
faddp %st, %st(2)
jmp 0x2b48c
faddp %st, %st(1)
incb %sil
movzbl %sil, %edi
cmpq %rdi, %r13
ja 0x2b44b
fldt (%rdx,%rcx)
fmulp %st, %st(3)
fldz
testb %bpl, %bpl
je 0x2b4e7
fstp %st(0)
movq (%rax), %rax
fldz
testq %r13, %r13
je 0x2b4cf
fstp %st(0)
fldz
xorl %ecx, %ecx
movzbl %cl, %ecx
movl %ecx, %edx
shll $0x4, %edx
fldt (%rax,%rdx)
fmul %st(4), %st
faddp %st, %st(1)
incb %cl
movzbl %cl, %edx
cmpq %rdx, %r13
ja 0x2b4b6
fxch %st(1)
fxch %st(2)
fxch %st(1)
movq %r13, %rcx
shlq $0x4, %rcx
fldt (%rax,%rcx)
fmulp %st, %st(4)
jmp 0x2b4ed
fld %st(0)
fld %st(1)
fxch %st(1)
fxch %st(2)
fxch %st(1)
movq 0x40(%rsp), %rax
movq (%rax), %rax
fldt (%rax)
fadd %st(3), %st
fld %st(0)
fstpt (%rax)
fld %st(3)
fadd %st(2), %st
fldt 0x10(%rax)
faddp %st, %st(1)
fstpt 0x10(%rax)
fxch %st(3)
faddp %st, %st(2)
faddp %st, %st(1)
faddp %st, %st(2)
fldt 0x20(%rax)
faddp %st, %st(2)
fld %st(1)
fstpt 0x20(%rax)
testb %bpl, %bpl
je 0x2b585
fucompi %st(1), %st
fstp %st(0)
fldz
fldz
jbe 0x2b585
fstp %st(1)
fstp %st(0)
movl $0x45, %edx
movq %r15, %rdi
leaq 0x5ee3(%rip), %rsi      # 0x31420
callq 0x4400
fldz
fldz
fstp %st(1)
fstp %st(0)
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4370
fldz
fldz
fstp %st(1)
fstp %st(0)
movsbl %al, %esi
movq %r15, %rdi
callq 0x4040
fldz
fldz
fstp %st(1)
fstp %st(0)
movq %rax, %rdi
callq 0x42a0
fldz
fldz
fstp %st(1)
fstp %st(0)
testq %r13, %r13
jg 0x2b3f8
leaq 0x88(%rsp), %rdi
callq 0x1dd38
xorl %eax, %eax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
movq 0x70(%rsp), %rdi
testq %rdi, %rdi
je 0x2b5ed
movq 0x80(%rsp), %rsi
subq %rdi, %rsi
callq 0x43a0
jmp 0x2b5ed
movq %rax, %rbx
jmp 0x2b5ed
jmp 0x2b5dd
fstp %st(1)
fstp %st(0)
movq %rax, %rbx
leaq 0x88(%rsp), %rdi
callq 0x1dd38
movq %rbx, %rdi
callq 0x4700
nop