// File: /workspace/github_cpp_makefile_star2_O2/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 0x5fd6(%rip)            # 0x2a7a0
xorl %eax, %eax
fxch %st(1)
fucomi %st(1), %st
fldz
fld %st(0)
fcmovnb %st(3), %st
fstp %st(3)
movq %r8, 0x20(%rsp)
movq %rcx, 0x60(%rsp)
fxch %st(1)
fsubp %st, %st(2)
setae %al
fnstcw 0x4(%rsp)
movzwl 0x4(%rsp), %ecx
orl $0xc00, %ecx            # imm = 0xC00
movw %cx, 0xa(%rsp)
fldcw 0xa(%rsp)
movq %rdx, %r14
movl %esi, %ebp
fxch %st(1)
fistpll 0x68(%rsp)
fldcw 0x4(%rsp)
shlq $0x3f, %rax
xorq 0x68(%rsp), %rax
fstpt 0xa0(%rsp)
leaq 0x88(%rsp), %rdi
leaq 0xa0(%rsp), %rdx
leaq 0xf(%rsp), %rcx
movq %rax, %rsi
callq 0x18df8
leaq 0x70(%rsp), %rdi
pushq $0x2
popq %rsi
leaq 0x88(%rsp), %rdx
leaq 0xe(%rsp), %rcx
callq 0x1918c
leaq 0x88(%rsp), %rdi
callq 0x195d0
movq (%r14), %rax
movzbl %bpl, %r15d
movq (%rax), %rax
movq (%rax,%r15,8), %rcx
movq 0x70(%rsp), %r8
movq %rbx, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x237e8
movq (%r14), %rax
movq 0x18(%rax), %rax
movq (%rax,%r15,8), %rcx
movq 0x70(%rsp), %r8
addq $0x18, %r8
movq %rbx, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x237e8
fldt 0x90(%rbx)
fnstcw 0x2(%rsp)
movzwl 0x2(%rsp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, 0x8(%rsp)
fldcw 0x8(%rsp)
fistl 0x14(%rsp)
fldcw 0x2(%rsp)
movl 0x14(%rsp), %eax
movq 0x70(%rsp), %rcx
movq %rcx, 0x50(%rsp)
imulq $0x18, %r15, %rcx
movq (%rbx), %rdx
addq %rcx, %rdx
movq %rdx, 0x48(%rsp)
movq 0x60(%rbx), %rdx
movq %rdx, 0x40(%rsp)
movq 0x30(%rbx), %rdx
addq %rcx, %rdx
movq %rdx, 0x38(%rsp)
movq 0x18(%rbx), %rdx
addq %rcx, %rdx
movq %rdx, 0x30(%rsp)
movq 0x48(%rbx), %rdx
movq %rcx, 0x18(%rsp)
addq %rcx, %rdx
movq %rdx, 0x28(%rsp)
movq %r14, 0x58(%rsp)
testl %eax, %eax
js 0x24a7a
fstp %st(0)
movq 0x60(%rsp), %rcx
movq (%rcx), %r10
fldt (%r10)
movl %eax, %r11d
movq 0x50(%rsp), %rdi
movq (%rdi), %rdx
shlq $0x4, %r11
fldt (%rdx,%r11)
movq (%r14), %rdx
movq (%rdx), %rdx
movq %r15, %rsi
movq (%rdx,%r15,8), %rdx
cmpb $0x0, 0xb8(%rdx)
fmul %st(1), %st
fldz
fld1
fld %st(0)
fcmovne %st(2), %st
fstp %st(2)
addl $-0x1, %eax
fld %st(0)
fcmovb %st(2), %st
fstp %st(2)
fsub %st, %st(3)
movq 0x48(%rsp), %rcx
movq (%rcx), %r15
movq (%r15), %rdx
fldt (%rdx,%r11)
movq 0x40(%rsp), %r8
movq (%r8), %rdx
movq 0x18(%rsp), %rcx
movq (%rdx,%rcx), %r12
fldt (%r12)
fmulp %st, %st(1)
fmulp %st, %st(4)
fxch %st(2)
fmulp %st, %st(1)
faddp %st, %st(2)
movq 0x38(%rsp), %rdx
movq (%rdx), %rdx
leaq (%rdx,%r11), %r14
fldt (%rdx,%r11)
faddp %st, %st(2)
fxch %st(1)
fstpt (%rdx,%r11)
fldt (%r10)
movq 0x18(%rdi), %rdx
fldt (%rdx,%r11)
fxch %st(2)
fsub %st(1), %st
movq 0x30(%rsp), %rdx
movq (%rdx), %rdx
movq (%rdx), %rdi
fldt (%rdi,%r11)
movq 0x18(%r8), %rdi
movq (%rdi,%rcx), %rdi
fldt (%rdi)
fmulp %st, %st(1)
fmulp %st, %st(1)
fxch %st(1)
fmulp %st, %st(2)
faddp %st, %st(1)
movq 0x28(%rsp), %rcx
movq (%rcx), %r9
leaq (%r9,%r11), %r8
fldt (%r9,%r11)
faddp %st, %st(1)
fstpt (%r9,%r11)
movb $0x1, %r9b
movzbl %r9b, %r9d
movw %r9w, 0xc(%rsp)
filds 0xc(%rsp)
fldt 0x90(%rbx)
fld1
fadd %st(1), %st
fucompi %st(2), %st
fstp %st(1)
jbe 0x24a6d
fstp %st(0)
fldt (%r10)
fld1
fsub %st, %st(1)
imulq $0x18, %r9, %r13
movq (%r15,%r13), %rcx
fldt (%rcx,%r11)
movl %r9d, %ecx
shll $0x4, %ecx
fldt (%r12,%rcx)
fmulp %st, %st(1)
fmulp %st, %st(2)
fldt (%r14)
faddp %st, %st(2)
fxch %st(1)
fstpt (%r14)
fldt (%r10)
fsubrp %st, %st(1)
movq (%rdx,%r13), %r13
fldt (%r13,%r11)
fmulp %st, %st(1)
fldt (%rdi,%rcx)
fmulp %st, %st(1)
fldt (%r8)
faddp %st, %st(1)
fstpt (%r8)
incb %r9b
jmp 0x24a00
movq 0x58(%rsp), %r14
movq %rsi, %r15
jmp 0x2491c
fnstcw (%rsp)
movzwl (%rsp), %eax
orl $0xc00, %eax            # imm = 0xC00
movw %ax, 0x6(%rsp)
fldcw 0x6(%rsp)
fistpl 0x10(%rsp)
fldcw (%rsp)
movl 0x10(%rsp), %r14d
movq 0x1650e(%rip), %r15     # 0x3afb0
leaq 0x6ad7(%rip), %r12      # 0x2b580
testl %r14d, %r14d
js 0x24bbc
movl %r14d, %esi
movq %rsi, %rax
shlq $0x4, %rax
movq 0x30(%rbx), %rdx
movq 0x48(%rbx), %rdi
movq 0x18(%rsp), %r9
movq (%rdx,%r9), %r8
movq %rsi, %rcx
shlq $0x4, %rcx
fldt (%r8,%rcx)
movq (%rdi,%r9), %rdi
fldz
xorl %r8d, %r8d
fld %st(0)
cmpq %rsi, %r8
je 0x24b24
movq %r8, %r9
shlq $0x4, %r9
fldt (%rdi,%r9)
fmul %st(3), %st
testb %bpl, %bpl
je 0x24b1d
movq (%rdx), %r9
xorl %r10d, %r10d
cmpq %r10, %rax
je 0x24b13
fldt (%r9,%r10)
fmul %st(1), %st
faddp %st, %st(3)
addq $0x10, %r10
jmp 0x24b00
fldt (%r9,%rcx)
fmulp %st, %st(1)
faddp %st, %st(1)
jmp 0x24b1f
faddp %st, %st(2)
incq %r8
jmp 0x24ae3
fldt (%rdi,%rcx)
fmulp %st, %st(3)
fldz
testb %bpl, %bpl
je 0x24b50
fstp %st(0)
movq (%rdx), %rdx
fldz
xorl %esi, %esi
cmpq %rsi, %rax
je 0x24b4b
fldt (%rdx,%rsi)
fmul %st(4), %st
faddp %st, %st(1)
addq $0x10, %rsi
jmp 0x24b39
fldt (%rdx,%rcx)
fmulp %st, %st(4)
movq 0x20(%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 0x24bb0
fucompi %st(1), %st
fstp %st(0)
fldz
fldz
jbe 0x24bb0
fstp %st(1)
fstp %st(0)
movq %r15, %rdi
movq %r12, %rsi
callq 0x43a0
fldz
fldz
fstp %st(1)
fstp %st(0)
movq %rax, %rdi
callq 0x41e0
fldz
fldz
fstp %st(1)
fstp %st(0)
decl %r14d
jmp 0x24aa9
leaq 0x70(%rsp), %rdi
callq 0x191e2
xorl %eax, %eax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x88(%rsp), %rdi
callq 0x195d0
jmp 0x24c04
movq %rax, %rbx
jmp 0x24c04
jmp 0x24bf7
fstp %st(1)
fstp %st(0)
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x191e2
movq %rbx, %rdi
callq 0x4700