// File: /workspace/github_cpp_makefile_star2_O2/hantaoyin[P]ffxiv-crafting-mcts/ffxiv-crafting-mcts.C
// Function: mlp::MLP::train(State const&, std::array<double, 29ul> const&, double, double, bool)
void train(const State& in, const std::array<double, TotalActionCount>& p, double score, double step_size, bool track_simulation) {
    {
      double total = 0.;
      for (size_t i = 0; i < TotalActionCount; ++i) {
        total += p[i];
      }
      ASSERT(fabs(total - 1.) < 1e-10) << in.DebugString() << ", total = " << total;
    }

    // cost function is MLE + weight decay.
    forward(in);

    Edge &eb = e.back();
    const size_t size = eb.size() - 1;
    ASSERT(p.size() == size) << p.size() << " != " << size;
    // For probabilities, use max likelihood loss function.
    for (size_t i = 0; i < size; ++i) {
      eb.D(i) = -p[i] / (1e-10 + eb(i));
    }
    // For score, we use mean square root as error function.
    // eb.D(size) = 2. * (eb(size) - score);

    // Or this loss function (which proves to be much better than the above since we want the
    // sigmoid to output a near-zero score initially):
    
    // l = (log(z/((1-e)*s+e)))^2
    // Where e is a very small positive number (to eliminate the singularity), z = sigmoid output, s = score.
    double s = (1 - 1e-5) * score + 1e-5;
    eb.D(size) = 2 * std::log(eb(size)/s) / eb(size);

    for (size_t i = v.size(); i > 0; --i) {
      v[i - 1]->backward_propagate(step_size);
    }

    if (track_simulation) {
      std::cout << "MLP training: " << in.DebugString() << " ==>\n";
      for (size_t i = 0; i < size; ++i) {
        std::cout << "MLP training: " << std::setfill(' ') << std::setw(20) << Action2Name(static_cast<Action>(i))
                  << std::setw(14) << std::scientific << std::setprecision(3) << p[i]
                  << std::setw(14) << std::scientific << std::setprecision(3) << eb(i)
                  << std::setw(14) << std::scientific << std::setprecision(3) << eb.D(i) << "\n";
      }
      std::cout << "MLP training: " << std::setw(20) << "<score>:"
                << std::setw(14) << std::scientific << std::setprecision(3) << score
                << std::setw(14) << std::scientific << std::setprecision(3) << eb(size)
                << std::setw(14) << std::scientific << std::setprecision(3) << eb.D(size) << "\n";
    }
  }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movl %ecx, 0x8(%rsp)
movsd %xmm1, (%rsp)
movsd %xmm0, 0x10(%rsp)
movq %rdx, %rbx
movq %rsi, %r14
movq %rdi, %r15
callq 0x453e
movq 0x20(%r15), %r13
movq -0x30(%r13), %rax
movq -0x28(%r13), %r12
subq %rax, %r12
sarq $0x3, %r12
leaq -0x1(%r12), %rbp
xorl %ecx, %ecx
movapd 0xb65(%rip), %xmm0      # 0x7160
movsd 0xaed(%rip), %xmm1      # 0x70f0
cmpq %rcx, %rbp
je 0x662c
movsd (%rbx,%rcx,8), %xmm2
xorpd %xmm0, %xmm2
movsd (%rax,%rcx,8), %xmm3
addsd %xmm1, %xmm3
divsd %xmm3, %xmm2
movq -0x18(%r13), %rdx
movsd %xmm2, (%rdx,%rcx,8)
incq %rcx
jmp 0x6603
movsd 0xac4(%rip), %xmm1      # 0x70f8
mulsd 0x10(%rsp), %xmm1
addsd 0x9ee(%rip), %xmm1      # 0x7030
movsd -0x8(%rax,%r12,8), %xmm0
divsd %xmm1, %xmm0
callq 0x2110
addsd %xmm0, %xmm0
movq -0x30(%r13), %rax
movq -0x18(%r13), %rcx
divsd -0x8(%rax,%r12,8), %xmm0
movq %r12, 0x18(%rsp)
movsd %xmm0, -0x8(%rcx,%r12,8)
movq 0x8(%r15), %r12
subq (%r15), %r12
sarq $0x3, %r12
subq $0x1, %r12
jb 0x6696
movq (%r15), %rax
movq (%rax,%r12,8), %rdi
movq (%rdi), %rax
movsd (%rsp), %xmm0
callq *0x8(%rax)
jmp 0x667c
cmpb $0x0, 0x8(%rsp)
je 0x6912
movq %rbx, 0x8(%rsp)
movq 0x492b(%rip), %rdi      # 0xafd8
leaq 0xf83(%rip), %rsi       # 0x7637
callq 0x2170
movq %rax, %r15
leaq 0x28(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0x579e
movq %r15, %rdi
movq %r12, %rsi
callq 0x2140
leaq 0xf68(%rip), %rsi       # 0x7646
movq %rax, %rdi
callq 0x2170
movq %r13, (%rsp)
leaq 0x28(%rsp), %rdi
callq 0x2070
xorl %r12d, %r12d
movq %rbp, 0x20(%rsp)
pushq $0xe
popq %r14
movl $0xfffffefb, %r15d      # imm = 0xFFFFFEFB
pushq $0x3
popq %rbx
movq (%rsp), %r13
movq 0x48c4(%rip), %rdi      # 0xafd8
leaq 0xf1c(%rip), %rsi       # 0x7637
callq 0x2170
cmpq %r12, %rbp
je 0x6828
movq %rax, %rdi
pushq $0x20
popq %rsi
callq 0x21f0
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
movq $0x14, 0x10(%rax,%rcx)
movzbl %r12b, %ecx
shll $0x4, %ecx
leaq 0x439e(%rip), %rdx      # 0xaaf0
movq (%rcx,%rdx), %rsi
movq %rax, %rdi
callq 0x2170
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %r14, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %r15d, %esi
movl $0x100, %ebp            # imm = 0x100
orl %ebp, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %rbx, 0x8(%rax,%rcx)
movq 0x8(%rsp), %rcx
movsd (%rcx,%r12,8), %xmm0
movq %rax, %rdi
callq 0x2210
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %r14, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %r15d, %esi
orl %ebp, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %rbx, 0x8(%rax,%rcx)
movq -0x30(%r13), %rcx
movsd (%rcx,%r12,8), %xmm0
movq %rax, %rdi
callq 0x2210
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %r14, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %r15d, %esi
orl %ebp, %esi
movq 0x20(%rsp), %rbp
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %rbx, 0x8(%rax,%rcx)
movq -0x18(%r13), %rcx
movsd (%rcx,%r12,8), %xmm0
movq %rax, %rdi
callq 0x2210
movq %rax, %rdi
leaq 0xcae(%rip), %rsi       # 0x74c9
callq 0x2170
incq %r12
jmp 0x670d
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
movq $0x14, 0x10(%rax,%rcx)
leaq 0xe0d(%rip), %rsi       # 0x764c
movq %rax, %rdi
callq 0x2170
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
pushq $0xe
popq %r12
movq %r12, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl $0xfffffefb, %ebx       # imm = 0xFFFFFEFB
movl 0x18(%rax,%rdx), %esi
andl %ebx, %esi
movl $0x100, %ebp            # imm = 0x100
orl %ebp, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
pushq $0x3
popq %r15
movq %r15, 0x8(%rax,%rcx)
movq %rax, %rdi
movsd 0x10(%rsp), %xmm0
callq 0x2210
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %r12, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %ebx, %esi
orl %ebp, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %r15, 0x8(%rax,%rcx)
movq (%rsp), %r13
movq -0x30(%r13), %rcx
movq 0x18(%rsp), %r14
movsd -0x8(%rcx,%r14,8), %xmm0
movq %rax, %rdi
callq 0x2210
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %r12, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
andl 0x18(%rax,%rdx), %ebx
orl %ebp, %ebx
movl %ebx, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %r15, 0x8(%rax,%rcx)
movq -0x18(%r13), %rcx
movsd -0x8(%rcx,%r14,8), %xmm0
movq %rax, %rdi
callq 0x2210
leaq 0xbbf(%rip), %rsi       # 0x74c9
movq %rax, %rdi
callq 0x2170
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x2070
movq %rbx, %rdi
callq 0x2270