// File: xbai0624[P]dnn/src/ConstructLayer.cpp
// Function: ConstructLayer::ComputeCostInOutputLayerForCurrentSample(int)
void ConstructLayer::ComputeCostInOutputLayerForCurrentSample(int sample_index)
{
    if(__type != LayerType::output)
    {
        std::cout<<"Error: ComputeCostInOutputLayerForCurrentSample() only works for output layer."
            <<std::endl;
        std::exit(0);
    }

    // --- 2) compute the cost function C(a_i, y_i)
    Images & sample_image = __imageA[sample_index]; // output layer drop out is not used for sure, so use __imageA is OK.
    assert(sample_image.GetNumberOfKernels() == 1); // output layer must be a fully connected layer, so one kernel
    // now get a_i
    Matrix & sample_A = sample_image.OutputImageFromKernel[0];
    assert(sample_A.Dimension().second == 1); // must be a collum matrix
    //cout<<sample_A<<endl;

    //assert(sample_number >= 1); // obsolete
    //Matrix sample_label = (__p_data_interface->GetCurrentBatchLabel())[sample_number-1];
    Matrix & sample_label = (__p_data_interface->GetCurrentBatchLabel())[sample_index];
    assert(sample_label.Dimension()  == sample_A.Dimension());

    double cost = 0.;
    if(__cost_func_type == CostFuncType::cross_entropy)
    {
        cost = cross_entropy(sample_A, sample_label);
    }
    else if(__cost_func_type == CostFuncType::log_likelihood)
    {
        cost = log_likelihood(sample_A, sample_label);
    }
    else if(__cost_func_type == CostFuncType::quadratic_sum)
    {
        cost = quadratic_sum(sample_A, sample_label);
    }
    else {
        std::cout<<"Error: cost function only supports cross_entropy, loglikelihood, quadratic_sum"
            <<std::endl;
        exit(0);
    }
    // push cost for current sample to memory
    //__outputLayerCost.push_back(cost);
    __outputLayerCost[sample_index]= cost;
    //cout<<"sample cost: "<<cost<<endl;
    //getchar();


    // --- 3) then calculate delta: delta = delta(a_i, y_i) for this sample
    // -------- please note: this function only calculate \delta for current sample, 
    // ----------- when doing back propagation for hidden layers, only delta with the same sample_index should be updated 
    // ----------- the overall delta for this batch should be an average of all deltas in this batch
    // ----------- this is due to the characteristic of Cost function, which is an averaged sum over all samples

    Matrix delta = Matrix(sample_A.Dimension());
    if(__cost_func_type == CostFuncType::cross_entropy)
    {
        delta = sample_A - sample_label; // softmax and sigmoid all have this form
    }
    else if(__cost_func_type == CostFuncType::log_likelihood)
    {
        delta = sample_A - sample_label;
    }
    else if(__cost_func_type == CostFuncType::quadratic_sum)
    {
        delta = sample_A - sample_label; // this is a place holder, not used
    }
    else {
        std::cout<<"Error: cost function only supports cross_entropy, loglikelihood, quadratic_sum"
            <<std::endl;
        exit(0);
    }
    // push cost for current sample to memory
    Images images_delta_from_current_sample;
    images_delta_from_current_sample.OutputImageFromKernel.push_back(delta); // only one kernel in fc layer
    __imageDelta[sample_index]=images_delta_from_current_sample;
    __imageDeltaFull[sample_index]=images_delta_from_current_sample; // in output layer, dropout is not used for sure
}

// Assembly:
subq $0x118, %rsp            # imm = 0x118
movq %rdi, 0x110(%rsp)
movl %esi, 0x10c(%rsp)
movq 0x110(%rsp), %rax
movq %rax, 0x18(%rsp)
cmpl $0x4, 0xc(%rax)
je 0xfe32
movq 0x5b1c8(%rip), %rdi     # 0x6afd8
leaq 0x427de(%rip), %rsi     # 0x525f5
callq 0x4230
movq %rax, %rdi
movq 0x5b18a(%rip), %rsi     # 0x6afb0
callq 0x4260
xorl %edi, %edi
callq 0x4290
movq 0x18(%rsp), %rdi
addq $0x138, %rdi            # imm = 0x138
movslq 0x10c(%rsp), %rsi
callq 0x1fd40
movq %rax, 0x100(%rsp)
movq 0x100(%rsp), %rdi
callq 0x1fd80
cmpq $0x1, %rax
jne 0xfe68
jmp 0xfe87
leaq 0x427d5(%rip), %rdi     # 0x52644
leaq 0x4235c(%rip), %rsi     # 0x521d2
movl $0x591, %edx            # imm = 0x591
leaq 0x427e9(%rip), %rcx     # 0x5266b
callq 0x4170
movq 0x100(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1f9e0
movq %rax, 0xf8(%rsp)
movq 0xf8(%rsp), %rdi
callq 0x3bae0
movq %rax, 0xe8(%rsp)
movq %rdx, 0xf0(%rsp)
cmpq $0x1, 0xf0(%rsp)
jne 0xfeca
jmp 0xfee9
leaq 0x427e5(%rip), %rdi     # 0x526b6
leaq 0x422fa(%rip), %rsi     # 0x521d2
movl $0x594, %edx            # imm = 0x594
leaq 0x42787(%rip), %rcx     # 0x5266b
callq 0x4170
movq 0x18(%rsp), %rax
movq 0x400(%rax), %rdi
callq 0x1fd90
movq %rax, %rdi
movslq 0x10c(%rsp), %rsi
callq 0x1f9e0
movq %rax, 0xe0(%rsp)
movq 0xe0(%rsp), %rdi
callq 0x3bae0
movq %rax, 0xd0(%rsp)
movq %rdx, 0xd8(%rsp)
movq 0xf8(%rsp), %rdi
callq 0x3bae0
movq %rax, 0xc0(%rsp)
movq %rdx, 0xc8(%rsp)
movq 0xd0(%rsp), %rdi
movq 0xd8(%rsp), %rsi
movq 0xc0(%rsp), %rdx
movq 0xc8(%rsp), %rcx
callq 0x3b180
testb $0x1, %al
jne 0xff77
jmp 0xff79
jmp 0xff98
leaq 0x42757(%rip), %rdi     # 0x526d7
leaq 0x4224b(%rip), %rsi     # 0x521d2
movl $0x59a, %edx            # imm = 0x59A
leaq 0x426d8(%rip), %rcx     # 0x5266b
callq 0x4170
movq 0x18(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0xb8(%rsp)
cmpl $0x0, 0x3e8(%rax)
jne 0xffd5
movq 0xf8(%rsp), %rdi
movq 0xe0(%rsp), %rsi
callq 0x10310
movsd %xmm0, 0xb8(%rsp)
jmp 0x1005e
movq 0x18(%rsp), %rax
cmpl $0x1, 0x3e8(%rax)
jne 0x10003
movq 0xf8(%rsp), %rdi
movq 0xe0(%rsp), %rsi
callq 0x104d0
movsd %xmm0, 0xb8(%rsp)
jmp 0x1005c
movq 0x18(%rsp), %rax
cmpl $0x2, 0x3e8(%rax)
jne 0x10031
movq 0xf8(%rsp), %rdi
movq 0xe0(%rsp), %rsi
callq 0x104e0
movsd %xmm0, 0xb8(%rsp)
jmp 0x1005a
movq 0x5afa0(%rip), %rdi     # 0x6afd8
leaq 0x426c9(%rip), %rsi     # 0x52708
callq 0x4230
movq %rax, %rdi
movq 0x5af62(%rip), %rsi     # 0x6afb0
callq 0x4260
xorl %edi, %edi
callq 0x4290
jmp 0x1005c
jmp 0x1005e
movq 0x18(%rsp), %rdi
movsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
addq $0x1f8, %rdi            # imm = 0x1F8
movslq 0x10c(%rsp), %rsi
callq 0x1fd60
movsd 0x10(%rsp), %xmm0
movsd %xmm0, (%rax)
movq 0xf8(%rsp), %rdi
callq 0x3bae0
movq %rax, 0x90(%rsp)
movq %rdx, 0x98(%rsp)
movq 0x90(%rsp), %rsi
movq 0x98(%rsp), %rdx
leaq 0xa0(%rsp), %rdi
callq 0x3b4a0
movq 0x18(%rsp), %rax
cmpl $0x0, 0x3e8(%rax)
jne 0x10147
movq 0xf8(%rsp), %rsi
movq 0xe0(%rsp), %rdx
leaq 0x78(%rsp), %rdi
callq 0x3c480
jmp 0x100f4
leaq 0xa0(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0x1fa20
jmp 0x10108
leaq 0x78(%rsp), %rdi
callq 0x3bb80
jmp 0x10250
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x70(%rsp)
movl %eax, 0x6c(%rsp)
jmp 0x102f7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x70(%rsp)
movl %eax, 0x6c(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x3bb80
jmp 0x102f7
movq 0x18(%rsp), %rax
cmpl $0x1, 0x3e8(%rax)
jne 0x101b1
movq 0xf8(%rsp), %rsi
movq 0xe0(%rsp), %rdx
leaq 0x50(%rsp), %rdi
callq 0x3c480
jmp 0x10171
leaq 0xa0(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x1fa20
jmp 0x10185
leaq 0x50(%rsp), %rdi
callq 0x3bb80
jmp 0x1024e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x70(%rsp)
movl %eax, 0x6c(%rsp)
leaq 0x50(%rsp), %rdi
callq 0x3bb80
jmp 0x102f7
movq 0x18(%rsp), %rax
cmpl $0x2, 0x3e8(%rax)
jne 0x10218
movq 0xf8(%rsp), %rsi
movq 0xe0(%rsp), %rdx
leaq 0x38(%rsp), %rdi
callq 0x3c480
jmp 0x101db
leaq 0xa0(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x1fa20
jmp 0x101ef
leaq 0x38(%rsp), %rdi
callq 0x3bb80
jmp 0x1024c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x70(%rsp)
movl %eax, 0x6c(%rsp)
leaq 0x38(%rsp), %rdi
callq 0x3bb80
jmp 0x102f7
movq 0x5adb9(%rip), %rdi     # 0x6afd8
leaq 0x424e2(%rip), %rsi     # 0x52708
callq 0x4230
movq %rax, 0x8(%rsp)
jmp 0x10232
movq 0x8(%rsp), %rdi
movq 0x5ad72(%rip), %rsi     # 0x6afb0
callq 0x4260
jmp 0x10245
xorl %edi, %edi
callq 0x4290
jmp 0x1024e
jmp 0x10250
leaq 0x20(%rsp), %rdi
callq 0x1fda0
jmp 0x1025c
leaq 0x20(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x1fa50
jmp 0x10270
movq 0x18(%rsp), %rdi
addq $0x180, %rdi            # imm = 0x180
movslq 0x10c(%rsp), %rsi
callq 0x1fd40
movq %rax, %rdi
leaq 0x20(%rsp), %rsi
callq 0x1fdb0
jmp 0x10298
movq 0x18(%rsp), %rdi
addq $0x1e0, %rdi            # imm = 0x1E0
movslq 0x10c(%rsp), %rsi
callq 0x1fd40
movq %rax, %rdi
leaq 0x20(%rsp), %rsi
callq 0x1fdb0
jmp 0x102c0
leaq 0x20(%rsp), %rdi
callq 0x1fde0
leaq 0xa0(%rsp), %rdi
callq 0x3bb80
addq $0x118, %rsp            # imm = 0x118
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x70(%rsp)
movl %eax, 0x6c(%rsp)
leaq 0x20(%rsp), %rdi
callq 0x1fde0
leaq 0xa0(%rsp), %rdi
callq 0x3bb80
movq 0x70(%rsp), %rdi
callq 0x43f0
nop