// File: 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:
subq $0x168, %rsp            # imm = 0x168
movq %rdi, 0x160(%rsp)
movl %esi, 0x15c(%rsp)
movq 0x160(%rsp), %rdi
movq %rdi, 0x20(%rsp)
addq $0x180, %rdi            # imm = 0x180
movslq 0x15c(%rsp), %rsi
callq 0x1fd40
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
movq %rsi, 0x28(%rsp)
callq 0x1f9e0
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq %rax, 0x150(%rsp)
movq 0x150(%rsp), %rax
movq %rax, 0x18(%rsp)
addq $0x308, %rdi            # imm = 0x308
callq 0x1f9e0
movq 0x18(%rsp), %rsi
movq %rax, %rdx
leaq 0x138(%rsp), %rdi
callq 0x3c680
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
movabsq $0x3e45798ee2308c3a, %rax # imm = 0x3E45798EE2308C3A
movq %rax, 0x130(%rsp)
addq $0x2a8, %rdi            # imm = 0x2A8
callq 0x1fd40
movq 0x28(%rsp), %rsi
movq %rax, %rdi
callq 0x1f9e0
movq %rax, 0x128(%rsp)
movq 0x128(%rsp), %rsi
movsd 0x130(%rsp), %xmm0
leaq 0x110(%rsp), %rdi
callq 0x3ca80
jmp 0xf175
leaq -0x1ec(%rip), %rsi      # 0xef90
leaq 0x110(%rsp), %rdi
callq 0x3dc20
jmp 0xf18b
leaq 0xe8(%rsp), %rdi
leaq 0x138(%rsp), %rsi
leaq 0x110(%rsp), %rdx
callq 0x3c680
jmp 0xf1aa
movq 0x20(%rsp), %rdi
addq $0x150, %rdi            # imm = 0x150
movslq 0x15c(%rsp), %rsi
callq 0x1fd40
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
movq %rsi, 0x8(%rsp)
callq 0x1f9e0
movq 0x8(%rsp), %rsi
movq 0x20(%rsp), %rdi
movq %rax, 0xe0(%rsp)
addq $0x278, %rdi            # imm = 0x278
callq 0x1fd40
movq 0x8(%rsp), %rsi
movq %rax, %rdi
callq 0x1f9e0
movq %rax, %rcx
movq 0x20(%rsp), %rax
movq %rcx, 0xd8(%rsp)
movq 0x400(%rax), %rdi
callq 0x1f310
movl %eax, 0x14(%rsp)
jmp 0xf221
movl 0x14(%rsp), %eax
cltq
movq %rax, 0xd0(%rsp)
movq 0xe0(%rsp), %rsi
movq 0xd8(%rsp), %rdx
leaq 0xb8(%rsp), %rdi
callq 0x3c480
jmp 0xf24e
movaps 0x42e0b(%rip), %xmm0    # 0x52060
movq 0xd0(%rsp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movapd 0x42e06(%rip), %xmm0    # 0x52070
subpd %xmm0, %xmm1
movaps %xmm1, %xmm0
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
addsd %xmm0, %xmm1
movsd 0x42d97(%rip), %xmm0    # 0x52018
divsd %xmm1, %xmm0
leaq 0xa0(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x3cfd0
jmp 0xf29c
leaq 0xb8(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x1fa20
jmp 0xf2b3
leaq 0xa0(%rsp), %rdi
callq 0x3bb80
movq 0x20(%rsp), %rdi
addq $0x338, %rdi            # imm = 0x338
xorl %eax, %eax
movl %eax, %esi
callq 0x1f9e0
movq %rax, 0x98(%rsp)
movq 0x98(%rsp), %rdx
leaq 0x80(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x3c680
jmp 0xf2fc
leaq 0xb8(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x1fa20
jmp 0xf313
leaq 0x80(%rsp), %rdi
callq 0x3bb80
movq 0x20(%rsp), %rdi
addq $0x350, %rdi            # imm = 0x350
xorl %eax, %eax
movl %eax, %esi
callq 0x1f9e0
movq %rax, 0x78(%rsp)
movq 0x78(%rsp), %rsi
movaps 0x42d1a(%rip), %xmm1    # 0x52060
movq 0xd0(%rsp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x42d15(%rip), %xmm1    # 0x52070
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
leaq 0x60(%rsp), %rdi
callq 0x3d140
jmp 0xf376
leaq 0x48(%rsp), %rdi
leaq 0xe8(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
callq 0x3bf90
jmp 0xf392
leaq 0x30(%rsp), %rdi
leaq 0x48(%rsp), %rsi
leaq 0x60(%rsp), %rdx
callq 0x3bf90
jmp 0xf3a8
leaq 0x48(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x1fa20
jmp 0xf3b9
leaq 0x30(%rsp), %rdi
callq 0x3bb80
movq 0x20(%rsp), %rdi
addq $0x2d8, %rdi            # imm = 0x2D8
movslq 0x15c(%rsp), %rsi
callq 0x1fd40
movq %rax, %rdi
leaq 0x48(%rsp), %rsi
callq 0x1fa50
jmp 0xf3eb
leaq 0x48(%rsp), %rdi
callq 0x3bb80
leaq 0x60(%rsp), %rdi
callq 0x3bb80
leaq 0xb8(%rsp), %rdi
callq 0x3bb80
leaq 0xe8(%rsp), %rdi
callq 0x3bb80
leaq 0x110(%rsp), %rdi
callq 0x3bb80
leaq 0x138(%rsp), %rdi
callq 0x3bb80
addq $0x168, %rsp            # imm = 0x168
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0xf56d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0xf560
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0xf553
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0xf546
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
leaq 0xa0(%rsp), %rdi
callq 0x3bb80
jmp 0xf546
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x3bb80
jmp 0xf546
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0xf53c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0xf532
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
leaq 0x30(%rsp), %rdi
callq 0x3bb80
leaq 0x48(%rsp), %rdi
callq 0x3bb80
leaq 0x60(%rsp), %rdi
callq 0x3bb80
leaq 0xb8(%rsp), %rdi
callq 0x3bb80
leaq 0xe8(%rsp), %rdi
callq 0x3bb80
leaq 0x110(%rsp), %rdi
callq 0x3bb80
leaq 0x138(%rsp), %rdi
callq 0x3bb80
movq 0x108(%rsp), %rdi
callq 0x43f0
nopw (%rax,%rax)