// File: /workspace/github_cpp_makefile_star2_O3/xbai0624[P]dnn/src/ConstructLayer.cpp
// Function: ConstructLayer::BatchNormalization_GetGradientOnParameters_1DLayer()
void ConstructLayer::BatchNormalization_GetGradientOnParameters_1DLayer() //TO-DO: need to parallelize
{
    // gradients of cost function on \sigma_B^2, \mu_B, \gamma, \beta
    double epsilon = 1e-8;
    size_t batch_size = __p_data_interface->GetBatchSize();

    // mu_B
    // both cnn and fc have one average and variance
    Matrix & mu_B = __imageAverage_BN[0].OutputImageFromKernel[0]; // 1D layer has one kernel
    // sigma_B^2
    Matrix & sigma_B = __imageVariance_BN[0].OutputImageFromKernel[0];

    Matrix Var_inverse_half_cubic = sigma_B + epsilon;
    Var_inverse_half_cubic(inverse_half_cubic);
    Var_inverse_half_cubic = Var_inverse_half_cubic * (-1./2.);

    Matrix Var_inverse_square_root = sigma_B + epsilon;
    Var_inverse_square_root(inverse_square_root);
    Var_inverse_square_root = Var_inverse_square_root * (-1.);

    // 1) \partial{C}/\partial{\sigma_B^2}
    Matrix partial_C_over_partial_sigma_B2(__imageZ[0].OutputImageFromKernel[0].Dimension(), 0.);
    for(size_t i=0;i<batch_size;i++)
    {
        Matrix partial_C_over_partial_hat_x = __imageDelta[i].OutputImageFromKernel[0] ^ __gamma_BN[0];

        Matrix tmp = __imageZ[i].OutputImageFromKernel[0] - mu_B;
        tmp = tmp ^ partial_C_over_partial_hat_x;

        partial_C_over_partial_sigma_B2 = partial_C_over_partial_sigma_B2 + tmp;
    }
    partial_C_over_partial_sigma_B2 = partial_C_over_partial_sigma_B2 ^ Var_inverse_half_cubic;

    // \partial{C}/\partial{\sigma_B^2}  result
    __v_partial_C_over_partial_sigma_square.push_back(partial_C_over_partial_sigma_B2);

    // 2) \partial{C}/\partial{mu_B}
    Matrix part1(__imageZ[0].OutputImageFromKernel[0].Dimension(), 0.);
    Matrix part2(__imageZ[0].OutputImageFromKernel[0].Dimension(), 0.);
    for(size_t i=0;i<batch_size;i++)
    {
        Matrix partial_C_over_partial_hat_x = __imageDelta[i].OutputImageFromKernel[0] ^ __gamma_BN[0];
        part1 = part1 + partial_C_over_partial_hat_x;

        part2 = part2 + __imageZ[i].OutputImageFromKernel[0];
        part2 = part2 - mu_B;
    }
    part1 = part1 ^ Var_inverse_square_root;

    part2 = part2 * (-2./(double)batch_size);
    part2 = part2 ^ partial_C_over_partial_sigma_B2;
    Matrix partial_C_over_partial_mu_B = part1 + part2;

    // \partial{C}/\partial{mu_B}   result
    __v_partial_C_over_partial_mu.push_back(partial_C_over_partial_mu_B);

    // 3) \partial{C}/\partial{\gamma} and \partial{C}/\partial{beta}
    Matrix partial_C_over_partial_gamma(__imageZ[0].OutputImageFromKernel[0].Dimension(), 0.);
    Matrix partial_C_over_partial_beta(__imageZ[0].OutputImageFromKernel[0].Dimension(), 0.);
    for(size_t i=0;i<batch_size;i++)
    {
        Matrix tmp = __imageDelta[i].OutputImageFromKernel[0] ^ __imageZ_BN[i].OutputImageFromKernel[0];
        partial_C_over_partial_gamma = partial_C_over_partial_gamma +  tmp;

        partial_C_over_partial_beta = partial_C_over_partial_beta + __imageDelta[i].OutputImageFromKernel[0];
    }

    // \partial{C}/\partial{\gamma} and \partial{C}/\partial{beta} result
    __v_partial_C_over_partial_gamma.push_back(partial_C_over_partial_gamma);
    __v_partial_C_over_partial_beta.push_back(partial_C_over_partial_beta);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq %rdi, %rbx
movq 0x400(%rdi), %rax
movslq (%rax), %rax
movq %rax, 0x10(%rsp)
movq 0x278(%rdi), %rax
movq 0x2a8(%rdi), %rcx
movq (%rax), %rax
movq %rax, 0x90(%rsp)
movq (%rcx), %r15
leaq 0xb8(%rsp), %r12
movsd 0x1e27f(%rip), %xmm0    # 0x27598
movq %r12, %rdi
movq %r15, %rsi
callq 0x1b3f2
leaq 0xf5f(%rip), %rsi       # 0xa28a
movq %r12, %rdi
callq 0x1bf18
leaq 0x78(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
movsd 0x1e258(%rip), %xmm0    # 0x275a0
callq 0x1b70c
leaq 0xb8(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0x14e2c
leaq 0x78(%rsp), %rdi
callq 0x1abf2
leaq 0x78(%rsp), %rdi
movsd 0x1e222(%rip), %xmm0    # 0x27598
movq %r15, %rsi
callq 0x1b3f2
leaq 0xf56(%rip), %rsi       # 0xa2db
leaq 0x78(%rsp), %rdi
callq 0x1bf18
leaq 0x48(%rsp), %rdi
leaq 0x78(%rsp), %rsi
movsd 0x1e207(%rip), %xmm0    # 0x275a8
callq 0x1b70c
leaq 0x78(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x14e2c
leaq 0x48(%rsp), %rdi
callq 0x1abf2
movq %rbx, 0x8(%rsp)
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1abb8
leaq 0x48(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a92c
cmpl $0x0, 0x10(%rsp)
je 0x94bd
xorl %r14d, %r14d
leaq 0x30(%rsp), %rdi
leaq 0x60(%rsp), %r15
leaq 0x18(%rsp), %r13
leaq 0x48(%rsp), %rbx
movq 0x10(%rsp), %rbp
movq %rbp, 0xb0(%rsp)
movq %rbx, %rbp
movq 0x8(%rsp), %rbx
movq 0x180(%rbx), %rax
movq 0x308(%rbx), %rdx
movq (%rax,%r14), %rsi
movq %rdi, %r12
callq 0x1b1ee
movq 0x150(%rbx), %rax
movq (%rax,%r14), %rsi
movq %r15, %rdi
movq 0x90(%rsp), %rdx
callq 0x1b0ec
movq %r13, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x1b1ee
movq %rbp, %rbx
movq %r15, %rdi
movq %r13, %rsi
callq 0x14e2c
movq %r13, %rdi
callq 0x1abf2
movq %r13, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x1ae34
movq %rbx, %rdi
movq %r13, %rsi
callq 0x14e2c
movq 0xb0(%rsp), %rbp
movq %r13, %rdi
callq 0x1abf2
movq %r15, %rdi
callq 0x1abf2
movq %r12, %rdi
callq 0x1abf2
movq %r12, %rdi
addq $0x18, %r14
decq %rbp
jne 0x940b
leaq 0x30(%rsp), %rdi
leaq 0x48(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
callq 0x1b1ee
leaq 0x48(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x14e2c
movq 0x8(%rsp), %rbx
leaq 0x30(%rsp), %rdi
callq 0x1abf2
leaq 0x338(%rbx), %rdi
leaq 0x48(%rsp), %rsi
callq 0x138a4
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1abb8
leaq 0x30(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a92c
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1abb8
leaq 0x60(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a92c
cmpl $0x0, 0x10(%rsp)
je 0x961c
xorl %r14d, %r14d
leaq 0x18(%rsp), %rbx
leaq 0x98(%rsp), %r12
movq 0x10(%rsp), %r13
movq 0x8(%rsp), %rcx
movq 0x180(%rcx), %rax
movq 0x308(%rcx), %rdx
movq (%rax,%r14), %rsi
movq %rbx, %rdi
callq 0x1b1ee
movq %r12, %rdi
leaq 0x30(%rsp), %r15
movq %r15, %rsi
movq %rbx, %rbp
movq %rbx, %rdx
callq 0x1ae34
movq %r15, %rdi
movq %r12, %rsi
callq 0x14e2c
movq %r12, %rdi
callq 0x1abf2
movq 0x8(%rsp), %rax
movq 0x150(%rax), %rax
movq (%rax,%r14), %rdx
movq %r12, %rdi
leaq 0x60(%rsp), %rbx
movq %rbx, %rsi
callq 0x1ae34
movq %rbx, %rdi
movq %r12, %rsi
callq 0x14e2c
movq %r12, %rdi
callq 0x1abf2
movq %r12, %rdi
movq %rbx, %rsi
movq 0x90(%rsp), %rdx
callq 0x1b0ec
movq %rbx, %rdi
movq %r12, %rsi
callq 0x14e2c
movq %r12, %rdi
callq 0x1abf2
movq %rbp, %rdi
callq 0x1abf2
movq %rbp, %rbx
addq $0x18, %r14
decq %r13
jne 0x9563
leaq 0x18(%rsp), %rdi
leaq 0x30(%rsp), %rsi
leaq 0x78(%rsp), %rdx
callq 0x1b1ee
leaq 0x30(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x14e2c
movq 0x8(%rsp), %rbx
leaq 0x18(%rsp), %rdi
callq 0x1abf2
movsd 0x10(%rsp), %xmm0
unpcklps 0x1d9e5(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1d9ed(%rip), %xmm0    # 0x27050
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1df39(%rip), %xmm0    # 0x275b0
divsd %xmm1, %xmm0
leaq 0x18(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x1b70c
leaq 0x60(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x14e2c
leaq 0x18(%rsp), %rdi
callq 0x1abf2
leaq 0x18(%rsp), %rdi
leaq 0x60(%rsp), %rsi
leaq 0x48(%rsp), %rdx
callq 0x1b1ee
leaq 0x60(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x14e2c
leaq 0x18(%rsp), %rdi
callq 0x1abf2
leaq 0x18(%rsp), %rdi
leaq 0x30(%rsp), %rsi
leaq 0x60(%rsp), %rdx
callq 0x1ae34
leaq 0x350(%rbx), %rdi
leaq 0x18(%rsp), %rsi
callq 0x138a4
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1abb8
leaq 0x98(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a92c
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1abb8
leaq 0xd0(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a92c
cmpl $0x0, 0x10(%rsp)
je 0x97f1
xorl %ebp, %ebp
leaq 0x100(%rsp), %r14
leaq 0xe8(%rsp), %r15
leaq 0x98(%rsp), %r12
leaq 0xd0(%rsp), %r13
movq 0x8(%rsp), %rcx
movq 0x180(%rcx), %rax
movq 0x218(%rcx), %rcx
movq (%rax,%rbp), %rsi
movq (%rcx,%rbp), %rdx
movq %r14, %rdi
callq 0x1b1ee
movq %r15, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x1ae34
movq %r12, %rdi
movq %r15, %rsi
callq 0x14e2c
movq %r15, %rdi
callq 0x1abf2
movq 0x8(%rsp), %rax
movq 0x180(%rax), %rax
movq (%rax,%rbp), %rdx
movq %r15, %rdi
movq %r13, %rsi
callq 0x1ae34
movq %r13, %rdi
movq %r15, %rsi
callq 0x14e2c
movq %r15, %rdi
callq 0x1abf2
movq %r14, %rdi
callq 0x1abf2
addq $0x18, %rbp
decq 0x10(%rsp)
jne 0x9768
movq 0x8(%rsp), %rbx
leaq 0x368(%rbx), %rdi
leaq 0x98(%rsp), %rsi
callq 0x138a4
addq $0x380, %rbx            # imm = 0x380
leaq 0xd0(%rsp), %rsi
movq %rbx, %rdi
callq 0x138a4
leaq 0xd0(%rsp), %rdi
callq 0x1abf2
leaq 0x98(%rsp), %rdi
callq 0x1abf2
leaq 0x18(%rsp), %rdi
callq 0x1abf2
leaq 0x60(%rsp), %rdi
callq 0x1abf2
leaq 0x30(%rsp), %rdi
callq 0x1abf2
leaq 0x48(%rsp), %rdi
callq 0x1abf2
leaq 0x78(%rsp), %rdi
callq 0x1abf2
leaq 0xb8(%rsp), %rdi
callq 0x1abf2
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x9951
jmp 0x994c
jmp 0x9951
jmp 0x994c
jmp 0x9951
jmp 0x994c
jmp 0x9951
jmp 0x994c
jmp 0x993e
jmp 0x9943
jmp 0x993e
jmp 0x993e
jmp 0x98de
jmp 0x98de
jmp 0x98cc
jmp 0x98de
jmp 0x98cc
movq %rax, %rbx
jmp 0x9986
jmp 0x98e6
jmp 0x992c
jmp 0x9951
jmp 0x9943
jmp 0x993e
movq %rax, %rbx
jmp 0x997c
movq %rax, %rbx
jmp 0x9911
jmp 0x98ef
jmp 0x98f4
movq %rax, %rbx
jmp 0x9904
movq %rax, %rbx
leaq 0xe8(%rsp), %rdi
callq 0x1abf2
leaq 0x100(%rsp), %rdi
callq 0x1abf2
leaq 0xd0(%rsp), %rdi
callq 0x1abf2
jmp 0x992f
jmp 0x994c
jmp 0x9951
jmp 0x992c
jmp 0x9951
jmp 0x992c
jmp 0x9951
movq %rax, %rbx
leaq 0x98(%rsp), %rdi
callq 0x1abf2
jmp 0x9954
movq %rax, %rbx
jmp 0x9972
movq %rax, %rbx
jmp 0x9968
jmp 0x994c
jmp 0x9951
movq %rax, %rbx
jmp 0x995e
movq %rax, %rbx
leaq 0x18(%rsp), %rdi
callq 0x1abf2
leaq 0x60(%rsp), %rdi
callq 0x1abf2
leaq 0x30(%rsp), %rdi
callq 0x1abf2
leaq 0x48(%rsp), %rdi
callq 0x1abf2
leaq 0x78(%rsp), %rdi
callq 0x1abf2
leaq 0xb8(%rsp), %rdi
callq 0x1abf2
movq %rbx, %rdi
callq 0x43e0
nop