// File: /workspace/github_cpp_makefile_star2_O1/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 0x1e21f(%rip), %xmm0    # 0x27598
movq %r12, %rdi
movq %r15, %rsi
callq 0x1b4b6
leaq 0xf5f(%rip), %rsi       # 0xa2ea
movq %r12, %rdi
callq 0x1bfe6
leaq 0x78(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
movsd 0x1e1f8(%rip), %xmm0    # 0x275a0
callq 0x1b7d0
leaq 0xb8(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0x14f80
leaq 0x78(%rsp), %rdi
callq 0x1acb6
leaq 0x78(%rsp), %rdi
movsd 0x1e1c2(%rip), %xmm0    # 0x27598
movq %r15, %rsi
callq 0x1b4b6
leaq 0xf56(%rip), %rsi       # 0xa33b
leaq 0x78(%rsp), %rdi
callq 0x1bfe6
leaq 0x48(%rsp), %rdi
leaq 0x78(%rsp), %rsi
movsd 0x1e1a7(%rip), %xmm0    # 0x275a8
callq 0x1b7d0
leaq 0x78(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x14f80
leaq 0x48(%rsp), %rdi
callq 0x1acb6
movq %rbx, 0x8(%rsp)
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1ac7c
leaq 0x48(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a9ec
cmpl $0x0, 0x10(%rsp)
je 0x951d
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 0x1b2b2
movq 0x150(%rbx), %rax
movq (%rax,%r14), %rsi
movq %r15, %rdi
movq 0x90(%rsp), %rdx
callq 0x1b1b0
movq %r13, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x1b2b2
movq %rbp, %rbx
movq %r15, %rdi
movq %r13, %rsi
callq 0x14f80
movq %r13, %rdi
callq 0x1acb6
movq %r13, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x1aef8
movq %rbx, %rdi
movq %r13, %rsi
callq 0x14f80
movq 0xb0(%rsp), %rbp
movq %r13, %rdi
callq 0x1acb6
movq %r15, %rdi
callq 0x1acb6
movq %r12, %rdi
callq 0x1acb6
movq %r12, %rdi
addq $0x18, %r14
decq %rbp
jne 0x946b
leaq 0x30(%rsp), %rdi
leaq 0x48(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
callq 0x1b2b2
leaq 0x48(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x14f80
movq 0x8(%rsp), %rbx
leaq 0x30(%rsp), %rdi
callq 0x1acb6
leaq 0x338(%rbx), %rdi
leaq 0x48(%rsp), %rsi
callq 0x13a14
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1ac7c
leaq 0x30(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a9ec
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1ac7c
leaq 0x60(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a9ec
cmpl $0x0, 0x10(%rsp)
je 0x967c
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 0x1b2b2
movq %r12, %rdi
leaq 0x30(%rsp), %r15
movq %r15, %rsi
movq %rbx, %rbp
movq %rbx, %rdx
callq 0x1aef8
movq %r15, %rdi
movq %r12, %rsi
callq 0x14f80
movq %r12, %rdi
callq 0x1acb6
movq 0x8(%rsp), %rax
movq 0x150(%rax), %rax
movq (%rax,%r14), %rdx
movq %r12, %rdi
leaq 0x60(%rsp), %rbx
movq %rbx, %rsi
callq 0x1aef8
movq %rbx, %rdi
movq %r12, %rsi
callq 0x14f80
movq %r12, %rdi
callq 0x1acb6
movq %r12, %rdi
movq %rbx, %rsi
movq 0x90(%rsp), %rdx
callq 0x1b1b0
movq %rbx, %rdi
movq %r12, %rsi
callq 0x14f80
movq %r12, %rdi
callq 0x1acb6
movq %rbp, %rdi
callq 0x1acb6
movq %rbp, %rbx
addq $0x18, %r14
decq %r13
jne 0x95c3
leaq 0x18(%rsp), %rdi
leaq 0x30(%rsp), %rsi
leaq 0x78(%rsp), %rdx
callq 0x1b2b2
leaq 0x30(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x14f80
movq 0x8(%rsp), %rbx
leaq 0x18(%rsp), %rdi
callq 0x1acb6
movsd 0x10(%rsp), %xmm0
unpcklps 0x1d985(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1d98d(%rip), %xmm0    # 0x27050
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1ded9(%rip), %xmm0    # 0x275b0
divsd %xmm1, %xmm0
leaq 0x18(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x1b7d0
leaq 0x60(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x14f80
leaq 0x18(%rsp), %rdi
callq 0x1acb6
leaq 0x18(%rsp), %rdi
leaq 0x60(%rsp), %rsi
leaq 0x48(%rsp), %rdx
callq 0x1b2b2
leaq 0x60(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x14f80
leaq 0x18(%rsp), %rdi
callq 0x1acb6
leaq 0x18(%rsp), %rdi
leaq 0x30(%rsp), %rsi
leaq 0x60(%rsp), %rdx
callq 0x1aef8
leaq 0x350(%rbx), %rdi
leaq 0x18(%rsp), %rsi
callq 0x13a14
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1ac7c
leaq 0x98(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a9ec
movq 0x150(%rbx), %rax
movq (%rax), %rdi
callq 0x1ac7c
leaq 0xd0(%rsp), %rdi
xorpd %xmm0, %xmm0
movq %rax, %rsi
callq 0x1a9ec
cmpl $0x0, 0x10(%rsp)
je 0x9851
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 0x1b2b2
movq %r15, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x1aef8
movq %r12, %rdi
movq %r15, %rsi
callq 0x14f80
movq %r15, %rdi
callq 0x1acb6
movq 0x8(%rsp), %rax
movq 0x180(%rax), %rax
movq (%rax,%rbp), %rdx
movq %r15, %rdi
movq %r13, %rsi
callq 0x1aef8
movq %r13, %rdi
movq %r15, %rsi
callq 0x14f80
movq %r15, %rdi
callq 0x1acb6
movq %r14, %rdi
callq 0x1acb6
addq $0x18, %rbp
decq 0x10(%rsp)
jne 0x97c8
movq 0x8(%rsp), %rbx
leaq 0x368(%rbx), %rdi
leaq 0x98(%rsp), %rsi
callq 0x13a14
addq $0x380, %rbx            # imm = 0x380
leaq 0xd0(%rsp), %rsi
movq %rbx, %rdi
callq 0x13a14
leaq 0xd0(%rsp), %rdi
callq 0x1acb6
leaq 0x98(%rsp), %rdi
callq 0x1acb6
leaq 0x18(%rsp), %rdi
callq 0x1acb6
leaq 0x60(%rsp), %rdi
callq 0x1acb6
leaq 0x30(%rsp), %rdi
callq 0x1acb6
leaq 0x48(%rsp), %rdi
callq 0x1acb6
leaq 0x78(%rsp), %rdi
callq 0x1acb6
leaq 0xb8(%rsp), %rdi
callq 0x1acb6
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x99b1
jmp 0x99ac
jmp 0x99b1
jmp 0x99ac
jmp 0x99b1
jmp 0x99ac
jmp 0x99b1
jmp 0x99ac
jmp 0x999e
jmp 0x99a3
jmp 0x999e
jmp 0x999e
jmp 0x993e
jmp 0x993e
jmp 0x992c
jmp 0x993e
jmp 0x992c
movq %rax, %rbx
jmp 0x99e6
jmp 0x9946
jmp 0x998c
jmp 0x99b1
jmp 0x99a3
jmp 0x999e
movq %rax, %rbx
jmp 0x99dc
movq %rax, %rbx
jmp 0x9971
jmp 0x994f
jmp 0x9954
movq %rax, %rbx
jmp 0x9964
movq %rax, %rbx
leaq 0xe8(%rsp), %rdi
callq 0x1acb6
leaq 0x100(%rsp), %rdi
callq 0x1acb6
leaq 0xd0(%rsp), %rdi
callq 0x1acb6
jmp 0x998f
jmp 0x99ac
jmp 0x99b1
jmp 0x998c
jmp 0x99b1
jmp 0x998c
jmp 0x99b1
movq %rax, %rbx
leaq 0x98(%rsp), %rdi
callq 0x1acb6
jmp 0x99b4
movq %rax, %rbx
jmp 0x99d2
movq %rax, %rbx
jmp 0x99c8
jmp 0x99ac
jmp 0x99b1
movq %rax, %rbx
jmp 0x99be
movq %rax, %rbx
leaq 0x18(%rsp), %rdi
callq 0x1acb6
leaq 0x60(%rsp), %rdi
callq 0x1acb6
leaq 0x30(%rsp), %rdi
callq 0x1acb6
leaq 0x48(%rsp), %rdi
callq 0x1acb6
leaq 0x78(%rsp), %rdi
callq 0x1acb6
leaq 0xb8(%rsp), %rdi
callq 0x1acb6
movq %rbx, %rdi
callq 0x43e0
nop