// File: /workspace/github_cpp_makefile_star2_O2/xbai0624[P]dnn/src/ConstructLayer.cpp
// Function: ConstructLayer::BatchNormalization_RestoreDelta_ForSample_1DLayer(int)
void ConstructLayer::BatchNormalization_RestoreDelta_ForSample_1DLayer(int sample_id)
{
    // refer to: https://arxiv.org/pdf/1502.03167v3.pdf and the notes in overleaf by Xinzhan Bai
    // parallelization is implemented in upper level 

    // part 1
    Matrix & original_delta = __imageDelta[sample_id].OutputImageFromKernel[0];
    Matrix partial_C_over_partial_hat_x = original_delta ^ __gamma_BN[0];

    double epsilon = 1e-8;
    Matrix & var = __imageVariance_BN[0].OutputImageFromKernel[0];
    Matrix Var_inverse_square_root = var + epsilon;
    Var_inverse_square_root(inverse_square_root);

    Matrix part1 = partial_C_over_partial_hat_x ^ Var_inverse_square_root;

    // part 2
    Matrix & original_z = __imageZ[sample_id].OutputImageFromKernel[0];
    Matrix & mu_B = __imageAverage_BN[0].OutputImageFromKernel[0];
    size_t batch_size = __p_data_interface->GetBatchSize();
    Matrix part2 = original_z - mu_B;
    part2 = part2 * (2./(double)batch_size);

    Matrix &partial_C_over_partial_sigma_square = __v_partial_C_over_partial_sigma_square[0];
    part2 = part2^partial_C_over_partial_sigma_square;

    // part 3
    Matrix  & partial_C_over_partial_mu_B = __v_partial_C_over_partial_mu[0];
    Matrix part3 = partial_C_over_partial_mu_B / ((double)batch_size);

    // result --- only active, no need to calculate full
    Matrix tmp = part1 + part2;
    tmp = tmp + part3;
    __imageDelta_BN[sample_id].OutputImageFromKernel.push_back(tmp);;
}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
subq $0xc0, %rsp
movq %rdi, %r14
movslq %esi, %rax
movq 0x180(%rdi), %rcx
imulq $0x18, %rax, %rbx
movq (%rcx,%rbx), %rsi
movq 0x308(%rdi), %rdx
leaq 0x98(%rsp), %rdi
callq 0x17f64
movq 0x2a8(%r14), %rax
movq (%rax), %rsi
leaq 0x50(%rsp), %rdi
movsd 0x17d2e(%rip), %xmm0    # 0x21528
callq 0x180cc
leaq -0xfc(%rip), %rsi       # 0x970a
leaq 0x50(%rsp), %rdi
callq 0x188a2
leaq 0x80(%rsp), %rdi
leaq 0x98(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0x17f64
movq 0x150(%r14), %rax
movq 0x278(%r14), %rcx
movq (%rax,%rbx), %rsi
movq (%rcx), %rdx
movq 0x400(%r14), %rax
movslq (%rax), %r15
leaq 0x20(%rsp), %rdi
callq 0x17eb0
movq %r15, %xmm0
punpckldq 0x177c0(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x177c8(%rip), %xmm0    # 0x21030
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x17c9c(%rip), %xmm0    # 0x21518
movapd %xmm1, 0xb0(%rsp)
divsd %xmm1, %xmm0
leaq 0x8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x182dc
leaq 0x20(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x125b4
leaq 0x8(%rsp), %rdi
callq 0x17a9a
movq 0x338(%r14), %rdx
leaq 0x8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x17f64
leaq 0x20(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x125b4
leaq 0x8(%rsp), %rdi
callq 0x17a9a
movq 0x350(%r14), %rsi
leaq 0x8(%rsp), %rdi
movapd 0xb0(%rsp), %xmm0
callq 0x18348
leaq 0x38(%rsp), %rdi
leaq 0x80(%rsp), %rsi
leaq 0x20(%rsp), %rdx
callq 0x17cc4
leaq 0x68(%rsp), %rdi
leaq 0x38(%rsp), %rsi
leaq 0x8(%rsp), %rdx
callq 0x17cc4
leaq 0x38(%rsp), %rdi
leaq 0x68(%rsp), %rsi
callq 0x125b4
leaq 0x68(%rsp), %rdi
callq 0x17a9a
addq 0x2d8(%r14), %rbx
leaq 0x38(%rsp), %rsi
movq %rbx, %rdi
callq 0x1139c
leaq 0x38(%rsp), %rdi
callq 0x17a9a
leaq 0x8(%rsp), %rdi
callq 0x17a9a
leaq 0x20(%rsp), %rdi
callq 0x17a9a
leaq 0x80(%rsp), %rdi
callq 0x17a9a
leaq 0x50(%rsp), %rdi
callq 0x17a9a
leaq 0x98(%rsp), %rdi
callq 0x17a9a
addq $0xc0, %rsp
popq %rbx
popq %r14
popq %r15
retq
jmp 0x99b2
movq %rax, %rbx
leaq 0x68(%rsp), %rdi
callq 0x17a9a
jmp 0x99b5
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x17a9a
jmp 0x99cc
jmp 0x99c9
jmp 0x99d8
jmp 0x99c9
jmp 0x99d8
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x17a9a
jmp 0x99db
movq %rax, %rbx
leaq 0x20(%rsp), %rdi
callq 0x17a9a
leaq 0x80(%rsp), %rdi
callq 0x17a9a
leaq 0x50(%rsp), %rdi
callq 0x17a9a
leaq 0x98(%rsp), %rdi
callq 0x17a9a
movq %rbx, %rdi
callq 0x43b0
movq %rax, %rbx
jmp 0x99e5
jmp 0x9a18
movq %rax, %rbx
jmp 0x99f2
movq %rax, %rbx
jmp 0x99fc