// File: /workspace/github_cpp_makefile_star2_O3/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
leaq (%rax,%rax,2), %rbx
movq (%rcx,%rbx,8), %rsi
movq 0x308(%rdi), %rdx
leaq 0x98(%rsp), %rdi
callq 0x1b1ee
movq 0x2a8(%r14), %rax
movq (%rax), %rsi
leaq 0x50(%rsp), %rdi
movsd 0x1d1ce(%rip), %xmm0    # 0x27598
callq 0x1b3f2
leaq -0xfb(%rip), %rsi       # 0xa2db
leaq 0x50(%rsp), %rdi
callq 0x1bf18
leaq 0x80(%rsp), %rdi
leaq 0x98(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0x1b1ee
movq 0x150(%r14), %rax
movq 0x278(%r14), %rcx
movq (%rax,%rbx,8), %rsi
movq (%rcx), %rdx
movq 0x400(%r14), %rax
movslq (%rax), %r15
leaq 0x20(%rsp), %rdi
callq 0x1b0ec
movq %r15, %xmm0
punpckldq 0x1cc10(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1cc18(%rip), %xmm0    # 0x27050
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1d13c(%rip), %xmm0    # 0x27588
movapd %xmm1, 0xb0(%rsp)
divsd %xmm1, %xmm0
leaq 0x8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x1b70c
leaq 0x20(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x14e2c
leaq 0x8(%rsp), %rdi
callq 0x1abf2
movq 0x338(%r14), %rdx
leaq 0x8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x1b1ee
leaq 0x20(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x14e2c
leaq 0x8(%rsp), %rdi
callq 0x1abf2
movq 0x350(%r14), %rsi
leaq 0x8(%rsp), %rdi
movapd 0xb0(%rsp), %xmm0
callq 0x1b7c8
leaq 0x38(%rsp), %rdi
leaq 0x80(%rsp), %rsi
leaq 0x20(%rsp), %rdx
callq 0x1ae34
leaq 0x68(%rsp), %rdi
leaq 0x38(%rsp), %rsi
leaq 0x8(%rsp), %rdx
callq 0x1ae34
leaq 0x38(%rsp), %rdi
leaq 0x68(%rsp), %rsi
callq 0x14e2c
leaq 0x68(%rsp), %rdi
callq 0x1abf2
shlq $0x3, %rbx
addq 0x2d8(%r14), %rbx
leaq 0x38(%rsp), %rsi
movq %rbx, %rdi
callq 0x138a4
leaq 0x38(%rsp), %rdi
callq 0x1abf2
leaq 0x8(%rsp), %rdi
callq 0x1abf2
leaq 0x20(%rsp), %rdi
callq 0x1abf2
leaq 0x80(%rsp), %rdi
callq 0x1abf2
leaq 0x50(%rsp), %rdi
callq 0x1abf2
leaq 0x98(%rsp), %rdi
callq 0x1abf2
addq $0xc0, %rsp
popq %rbx
popq %r14
popq %r15
retq
jmp 0xa586
movq %rax, %rbx
leaq 0x68(%rsp), %rdi
callq 0x1abf2
jmp 0xa589
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x1abf2
jmp 0xa5a0
jmp 0xa59d
jmp 0xa5ac
jmp 0xa59d
jmp 0xa5ac
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x1abf2
jmp 0xa5af
movq %rax, %rbx
leaq 0x20(%rsp), %rdi
callq 0x1abf2
leaq 0x80(%rsp), %rdi
callq 0x1abf2
leaq 0x50(%rsp), %rdi
callq 0x1abf2
leaq 0x98(%rsp), %rdi
callq 0x1abf2
movq %rbx, %rdi
callq 0x43e0
movq %rax, %rbx
jmp 0xa5b9
jmp 0xa5ec
movq %rax, %rbx
jmp 0xa5c6
movq %rax, %rbx
jmp 0xa5d0