// File: /workspace/github_cpp_makefile_star2_O2/xbai0624[P]dnn/src/ConstructLayer.cpp
// Function: ConstructLayer::UpdateWeightsAndBiasGradientsFC()
void ConstructLayer::UpdateWeightsAndBiasGradientsFC()
{
    //cout<<__func__<<" started."<<endl;
    // after finishing one batch, update weights and bias, for FC layer
    // get output from previous layer for current training sample
    std::vector<Images> a_images;
    if(/*__prevLayer->GetType() != LayerType::input && */__prevLayer->GetType() != LayerType::fullyConnected) // input layer has no W&B
    {
        // if previous layer is not an input/fullyConnected layer, then Vectorization operation is needed
        //      this is for cnn->fc or pooling->fc
        auto & _tmp = __prevLayer->GetImagesFullA(); // 'a' images from previous layer
        for(auto &i: _tmp)
            a_images.push_back(i.Vectorization());
    }
    else
    {
        // if previous layer is input/fc, no other operation is needed
        a_images = __prevLayer->GetImagesFullA(); // 'a' images from previous layer
    }
    auto & d_images = this->GetImagesFullDelta(); // delta images from current layer
    // NOTE: 'a' and 'delta' include value correpsonds to disabled neurons
    //       it's just these values have been set to 0 when updating __imagesA, __imagesDelta
    //       see Functions UpdateImagesA() and UpdateImagesDelta()
    //       since dC/dw_ij = a^{l-1}_j * delta^l_k, so if a = 0 or delta = 0, then dC/dw = 0, namely no change on w for inactive neurons
    if(a_images.size() != d_images.size()) {
        std::cout<<__func__<<" Error: batch size not equal..."<<std::endl;
        exit(0);
    }
    if(a_images.back().OutputImageFromKernel.size() != 1 ) {
        std::cout<<__func__<<" Error: updating weights and bias gradients for FC, dimension not match."<<std::endl;
        std::cout<<"                  kernel size: "<<a_images.back().OutputImageFromKernel.size()<<std::endl;
        exit(0);
    }

    // so directly work on __weightMatrix, not __weightMatrixActive
    // check layer type
    if(__weightMatrix.size() != 1) {
        std::cout<<__func__<<" Error: more than 1 weight matrix exist in fully connected layer."<<std::endl;
        exit(0);
    }

    //cout<<"sample size: "<<d_images.size()<<endl;
    //for(auto &i: d_images)
    //{
    //    cout<<i.OutputImageFromKernel[0].Dimension()<<endl;
    //    cout<<i.OutputImageFromKernel[0]<<endl;
    //}
    // loop for samples
    for(size_t i=0;i<a_images.size();i++)
    {
        Matrix & a_matrix = a_images[i].OutputImageFromKernel[0]; // 'a' image from previous layer
        Matrix & d_matrix = d_images[i].OutputImageFromKernel[0]; // 'd' image from current layer
        //cout<<"Layer id: "<<GetID()<<endl;
        //cout<<"a matrix: "<<endl<<a_matrix<<endl;
        //cout<<"delta matrix: "<<endl<<d_matrix<<endl;

        auto d1 = (__weightMatrix[0]).Dimension(), d2 = a_matrix.Dimension(), d3 = d_matrix.Dimension();
        if(d1.first != d3.first || d1.second != d2.first)
        {
            std::cout<<__func__<<"Error: updating weights and bias gradients for FC, dimension not match."<<std::endl;
            std::cout<<"          current layer 'w' matrix dimension: "<<d1<<std::endl;
            std::cout<<"          previous layer 'a' matrix dimension: "<<d2<<std::endl;
            std::cout<<"          current layer 'delta' matrix dimension: "<<d3<<std::endl;
            exit(0);
        }

        //cout<<"sample_id: "<<i<<endl;
        Matrix a_T = a_matrix.Transpose();
        Matrix dw = d_matrix * a_T;

        //cout<<a_T.Dimension()<<endl;
        //cout<<"a :"<<endl<<a_T<<endl;
        //cout<<d_matrix.Dimension()<<endl;
        //cout<<"d :"<<endl<<d_matrix<<endl;
        //cout<<"dw: "<<endl<<dw<<endl;
        //cout<<"dw matrix."<<endl;
        //getchar();

        // push bias gradient for current training sample
        Images tmp_w_gradients;
        tmp_w_gradients.OutputImageFromKernel.push_back(dw);
        __wGradient.push_back(tmp_w_gradients); // push weight gradient for current training sample

        Images tmp_b_gradients;
        tmp_b_gradients.OutputImageFromKernel.push_back(d_matrix);
        __bGradient.push_back(tmp_b_gradients); // bias gradient equals delta
    }

    //cout<<"INFO: "<<__func__<<" finished."<<endl;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xe8, %rsp
movq %rdi, %r13
andq $0x0, 0x10(%rsp)
xorps %xmm0, %xmm0
movaps %xmm0, (%rsp)
movq 0x3f0(%rdi), %rdi
movq (%rdi), %rax
callq *0x250(%rax)
movq 0x3f0(%r13), %rdi
movq (%rdi), %rcx
movq 0xd0(%rcx), %rcx
testl %eax, %eax
je 0xe7b5
callq *%rcx
movq (%rax), %rbx
movq 0x8(%rax), %r12
leaq 0xb8(%rsp), %r14
movq %rsp, %r15
cmpq %r12, %rbx
je 0xe7c2
movq %r14, %rdi
movq %rbx, %rsi
callq 0x11b66
movq %r15, %rdi
movq %r14, %rsi
callq 0x15c54
movq %r14, %rdi
callq 0x110e4
addq $0x18, %rbx
jmp 0xe78c
callq *%rcx
movq %rsp, %rdi
movq %rax, %rsi
callq 0x11c04
movq (%r13), %rax
movq %r13, %rdi
callq *0x100(%rax)
movq %rax, %rdi
movq (%rsp), %rcx
movq 0x8(%rsp), %rax
movq %rax, %rdx
subq %rcx, %rdx
movq 0x8(%rdi), %rsi
subq (%rdi), %rsi
cmpq %rsi, %rdx
jne 0xea59
movq -0x10(%rax), %rdx
subq -0x18(%rax), %rdx
cmpq $0x18, %rdx
jne 0xea88
movq 0x68(%r13), %rdx
subq 0x60(%r13), %rdx
cmpq $0x18, %rdx
jne 0xeaef
leaq 0x90(%r13), %rdx
movq %rdx, 0x30(%rsp)
leaq 0xa8(%r13), %rdx
movq %rdx, 0x28(%rsp)
xorl %r8d, %r8d
leaq 0xb8(%rsp), %rbx
xorl %r9d, %r9d
movq %rdi, 0x20(%rsp)
movq %r13, 0x38(%rsp)
subq %rcx, %rax
cqto
pushq $0x18
popq %rsi
idivq %rsi
cmpq %rax, %r9
jae 0xe998
movq %r9, 0x40(%rsp)
movq %rbx, %r14
movq (%rcx,%r8), %r12
movq (%rdi), %rax
movq %r8, 0x48(%rsp)
movq (%rax,%r8), %r15
movq 0x60(%r13), %rdi
callq 0x17a6a
movq %rax, %rbp
movq %rdx, %r13
movq %rax, 0x70(%rsp)
movq %rdx, 0x78(%rsp)
movq %r12, %rdi
callq 0x17a6a
movq %rax, %rbx
movq %rax, 0x60(%rsp)
movq %rdx, 0x68(%rsp)
movq %r15, %rdi
callq 0x17a6a
movq %rax, 0x50(%rsp)
movq %rdx, 0x58(%rsp)
cmpq %rax, %rbp
jne 0xe9b2
cmpq %rbx, %r13
jne 0xe9b2
movq %r14, %rbx
movq %r14, %rdi
movq %r12, %rsi
callq 0x18e22
leaq 0xd0(%rsp), %r14
leaq 0xa0(%rsp), %r12
leaq 0x80(%rsp), %rbp
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x17aac
movq 0x38(%rsp), %r13
xorps %xmm0, %xmm0
movaps %xmm0, 0xa0(%rsp)
andq $0x0, 0xb0(%rsp)
movq %r12, %rdi
movq %r14, %rsi
callq 0x1139c
movq 0x30(%rsp), %rdi
movq %r12, %rsi
callq 0x11400
xorps %xmm0, %xmm0
movaps %xmm0, 0x80(%rsp)
andq $0x0, 0x90(%rsp)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1139c
movq 0x28(%rsp), %rdi
movq %rbp, %rsi
callq 0x11400
movq %rbp, %rdi
callq 0x110e4
movq %r12, %rdi
callq 0x110e4
movq %r14, %rdi
callq 0x17a9a
movq %rbx, %rdi
callq 0x17a9a
movq 0x40(%rsp), %r9
incq %r9
movq (%rsp), %rcx
movq 0x8(%rsp), %rax
movq 0x48(%rsp), %r8
addq $0x18, %r8
movq 0x20(%rsp), %rdi
jmp 0xe845
movq %rsp, %rdi
callq 0x11106
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x2461f(%rip), %rdi     # 0x32fd8
leaq 0x13f18(%rip), %rsi     # 0x228d8
callq 0x4240
leaq 0x13f4d(%rip), %rsi     # 0x22919
movq %rax, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq 0x245f5(%rip), %rdi     # 0x32fd8
leaq 0x13fd9(%rip), %rsi     # 0x229c3
callq 0x4240
leaq 0x70(%rsp), %rsi
movq %rax, %rdi
callq 0x17602
movq %rax, %rdi
callq 0x4130
movq 0x245cd(%rip), %rdi     # 0x32fd8
leaq 0x13fe0(%rip), %rsi     # 0x229f2
callq 0x4240
leaq 0x60(%rsp), %rsi
movq %rax, %rdi
callq 0x17602
movq %rax, %rdi
callq 0x4130
movq 0x245a5(%rip), %rdi     # 0x32fd8
leaq 0x13fe8(%rip), %rsi     # 0x22a22
callq 0x4240
leaq 0x50(%rsp), %rsi
movq %rax, %rdi
callq 0x17602
movq %rax, %rdi
callq 0x4130
jmp 0xeb19
movq 0x24578(%rip), %rdi     # 0x32fd8
leaq 0x13e71(%rip), %rsi     # 0x228d8
callq 0x4240
leaq 0x13e85(%rip), %rsi     # 0x228f8
movq %rax, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
jmp 0xeb19
movq 0x24549(%rip), %rdi     # 0x32fd8
leaq 0x13e42(%rip), %rsi     # 0x228d8
callq 0x4240
leaq 0x13e76(%rip), %rsi     # 0x22918
movq %rax, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq 0x2451f(%rip), %rdi     # 0x32fd8
leaq 0x13ea1(%rip), %rsi     # 0x22961
callq 0x4240
movq %rax, %rdi
movq 0x8(%rsp), %rcx
movq -0x10(%rcx), %rax
subq -0x18(%rcx), %rax
cqto
pushq $0x18
popq %rcx
idivq %rcx
movq %rax, %rsi
callq 0x41a0
movq %rax, %rdi
callq 0x4130
jmp 0xeb19
movq 0x244e2(%rip), %rdi     # 0x32fd8
leaq 0x13ddb(%rip), %rsi     # 0x228d8
callq 0x4240
leaq 0x13e78(%rip), %rsi     # 0x22981
movq %rax, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
xorl %edi, %edi
callq 0x4260
jmp 0xeb47
jmp 0xeb47
jmp 0xeb47
jmp 0xeb47
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x110e4
jmp 0xeb88
jmp 0xeb47
jmp 0xeb47
jmp 0xeb47
jmp 0xeb47
movq %rax, %rbx
jmp 0xeb7b
movq %rax, %rbx
jmp 0xeb88
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
callq 0x110e4
jmp 0xeb61
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0x110e4
leaq 0xd0(%rsp), %rdi
callq 0x17a9a
leaq 0xb8(%rsp), %rdi
callq 0x17a9a
movq %rsp, %rdi
callq 0x11106
movq %rbx, %rdi
callq 0x43b0