// File: xbai0624[P]dnn/src/Neuron.cpp
// Function: Neuron::UpdateZFC(int)
void Neuron::UpdateZFC(int sample_index)
{
    // for fully connected layer, matrix reform are also done in here
    Layer* __previousLayer = __layer->GetPrevLayer();
    std::vector<Images>& _t = __previousLayer -> GetImagesActiveA(); // this line with '&' is 5 times faster than the following line without '&'

    //cout<<"batch size: "<<_t.size()<<endl;
    //cout<<"kernel number: "<<_t[0].GetNumberOfKernels()<<endl;
    //cout<<" image dimension: "<<_t[0].OutputImageFromKernel[0].Dimension()<<endl;
    if(_t.size() < 1 || _t.size() < (size_t)sample_index) 
    {
        std::cout<<"Error: previous layer has not 'A' image."<<std::endl;
        exit(0);
    }
    //Images &images = _t[sample_index]; // get images for current sample


    double z_for_current_neuron = 0;
    // get images for current sample
    Images images;
    if(__previousLayer->GetType() != LayerType::fullyConnected/* && __previousLayer->GetType() != LayerType::input*/ )
    {
        // need vectorization 2D->1D
        // input layer vectorization is already done in DataInterface class
        images = _t[sample_index].Vectorization(); // get images for current sample
    }
    else
    {
        // previous layer is fc, no need to do anything
        images = _t[sample_index];
    }

    if(images.OutputImageFromKernel.size() != 1) 
    {
        std::cout<<"Eroor: layer type not match, expecting FC layer, FC layer should only have 1 kernel."<<std::endl;
        exit(0);
    }

    Matrix &image = images.OutputImageFromKernel[0]; // FC layer has only one "kernel" (equivalent kernel)
    //cout<<"neuron id: "<<__neuron_id<<", image A debug:"<<endl;
    //cout<<image<<endl;


    //cout<<__func__<<" CHECKING HERE!!!! weight matrix dimension: "<<(*__w).Dimension()<<endl;
    //cout<<(*__w)<<endl;
    Matrix res = (*__w) * image;
    //cout<<"res matrix: "<<endl;
    //cout<<res<<endl;
    auto dim = res.Dimension();
    if(dim.first != 1 || dim.second != 1) 
    {
        std::cout<<"Error: wrong dimension, expecting 1D matrix."<<std::endl;
    }
    z_for_current_neuron = res[0][0];

    z_for_current_neuron = z_for_current_neuron + (*__b)[0][0];

    __z[sample_index] = z_for_current_neuron;
    //cout<<__func__<<" finished."<<endl;
}

// Assembly:
subq $0xf8, %rsp
movq %rdi, 0xf0(%rsp)
movl %esi, 0xec(%rsp)
movq 0xf0(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x78(%rax), %rdi
movq (%rdi), %rax
callq *0x2c8(%rax)
movq %rax, 0xe0(%rsp)
movq 0xe0(%rsp), %rdi
movq (%rdi), %rax
callq *0xc8(%rax)
movq %rax, 0xd8(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x1ff40
cmpq $0x1, %rax
jb 0x481be
movq 0xd8(%rsp), %rdi
callq 0x1ff40
movslq 0xec(%rsp), %rcx
cmpq %rcx, %rax
jae 0x481e7
movq 0x22e13(%rip), %rdi     # 0x6afd8
leaq 0xd8b2(%rip), %rsi      # 0x55a7e
callq 0x4230
movq %rax, %rdi
movq 0x22dd5(%rip), %rsi     # 0x6afb0
callq 0x4260
xorl %edi, %edi
callq 0x4290
movq $0x0, 0xd0(%rsp)
leaq 0xb8(%rsp), %rdi
callq 0x1fda0
movq 0xe0(%rsp), %rdi
movq (%rdi), %rax
movq 0x250(%rax), %rax
callq *%rax
movl %eax, 0x54(%rsp)
jmp 0x4821a
movl 0x54(%rsp), %eax
cmpl $0x0, %eax
je 0x48287
movq 0xd8(%rsp), %rdi
movslq 0xec(%rsp), %rsi
callq 0x1fd40
movq %rax, %rsi
leaq 0x90(%rsp), %rdi
callq 0x217c0
jmp 0x4824a
leaq 0xb8(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x4a540
leaq 0x90(%rsp), %rdi
callq 0x1fde0
jmp 0x482b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb0(%rsp)
movl %eax, 0xac(%rsp)
jmp 0x4848c
movq 0xd8(%rsp), %rdi
movslq 0xec(%rsp), %rsi
callq 0x1fd40
movq %rax, %rsi
leaq 0xb8(%rsp), %rdi
callq 0x1fdb0
jmp 0x482ae
jmp 0x482b0
leaq 0xb8(%rsp), %rdi
callq 0x1f9c0
cmpq $0x1, %rax
je 0x482f7
movq 0x22d0e(%rip), %rdi     # 0x6afd8
leaq 0xd7d6(%rip), %rsi      # 0x55aa7
callq 0x4230
movq %rax, 0x48(%rsp)
jmp 0x482dd
movq 0x48(%rsp), %rdi
movq 0x22cc7(%rip), %rsi     # 0x6afb0
callq 0x4260
jmp 0x482f0
xorl %edi, %edi
callq 0x4290
xorl %eax, %eax
movl %eax, %esi
leaq 0xb8(%rsp), %rdi
callq 0x1f9e0
movq %rax, %rcx
movq 0x58(%rsp), %rax
movq %rcx, 0x88(%rsp)
movq 0x8(%rax), %rsi
movq 0x88(%rsp), %rdx
leaq 0x70(%rsp), %rdi
callq 0x3bbb0
jmp 0x48330
leaq 0x70(%rsp), %rdi
callq 0x3bae0
movq %rdx, 0x38(%rsp)
movq %rax, 0x40(%rsp)
jmp 0x48346
movq 0x38(%rsp), %rax
movq 0x40(%rsp), %rcx
movq %rcx, 0x60(%rsp)
movq %rax, 0x68(%rsp)
cmpq $0x1, 0x60(%rsp)
jne 0x4836a
cmpq $0x1, 0x68(%rsp)
je 0x483bc
movq 0x22c67(%rip), %rdi     # 0x6afd8
leaq 0xd784(%rip), %rsi      # 0x55afc
callq 0x4230
movq %rax, 0x30(%rsp)
jmp 0x48384
movq 0x30(%rsp), %rdi
movq 0x22c20(%rip), %rsi     # 0x6afb0
callq 0x4260
jmp 0x48397
jmp 0x483bc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb0(%rsp)
movl %eax, 0xac(%rsp)
leaq 0x70(%rsp), %rdi
callq 0x3bb80
jmp 0x4848c
xorl %eax, %eax
movl %eax, %esi
leaq 0x70(%rsp), %rdi
callq 0x3be50
movq %rax, 0x28(%rsp)
jmp 0x483d1
movq 0x28(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
movq %rsi, 0x10(%rsp)
callq 0x1fd60
movq 0x10(%rsp), %rsi
movq %rax, %rcx
movq 0x58(%rsp), %rax
movsd (%rcx), %xmm0
movsd %xmm0, 0xd0(%rsp)
movsd 0xd0(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movq 0x10(%rax), %rdi
callq 0x3be50
movq %rax, 0x20(%rsp)
jmp 0x4841d
movq 0x20(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1fd60
movsd 0x18(%rsp), %xmm0
movq 0x58(%rsp), %rdi
addsd (%rax), %xmm0
movsd %xmm0, 0xd0(%rsp)
movsd 0xd0(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
addq $0x48, %rdi
movslq 0xec(%rsp), %rsi
callq 0x1fd60
movsd 0x8(%rsp), %xmm0
movsd %xmm0, (%rax)
leaq 0x70(%rsp), %rdi
callq 0x3bb80
leaq 0xb8(%rsp), %rdi
callq 0x1fde0
addq $0xf8, %rsp
retq
leaq 0xb8(%rsp), %rdi
callq 0x1fde0
movq 0xb0(%rsp), %rdi
callq 0x43f0
nopw %cs:(%rax,%rax)