// File: /workspace/github_cpp_makefile_star2_O1/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, %r12d
movsd %xmm1, 0x8(%rsp)
movsd %xmm0, 0x10(%rsp)
movq %rdx, %rbx
movq %rsi, %r13
movq %rdi, %r14
callq 0x49a8
movq 0x20(%r14), %rcx
movq -0x30(%rcx), %rax
movq %rcx, (%rsp)
movq -0x28(%rcx), %rbp
subq %rax, %rbp
sarq $0x3, %rbp
movq %rbp, %r15
decq %r15
je 0x6ced
movq (%rsp), %rcx
movq -0x18(%rcx), %rcx
xorl %edx, %edx
movapd 0x14ae(%rip), %xmm0     # 0x8170
movsd 0x1416(%rip), %xmm1     # 0x80e0
movsd (%rbx,%rdx,8), %xmm2
xorpd %xmm0, %xmm2
movsd (%rax,%rdx,8), %xmm3
addsd %xmm1, %xmm3
divsd %xmm3, %xmm2
movsd %xmm2, (%rcx,%rdx,8)
incq %rdx
cmpq %rdx, %r15
jne 0x6cca
movsd 0x13f3(%rip), %xmm1     # 0x80e8
mulsd 0x10(%rsp), %xmm1
addsd 0x1325(%rip), %xmm1     # 0x8028
movsd -0x8(%rax,%rbp,8), %xmm0
divsd %xmm1, %xmm0
callq 0x2120
addsd %xmm0, %xmm0
movq (%rsp), %rcx
movq -0x30(%rcx), %rax
movq -0x18(%rcx), %rcx
divsd -0x8(%rax,%rbp,8), %xmm0
movq %rbp, 0x18(%rsp)
movsd %xmm0, -0x8(%rcx,%rbp,8)
movq 0x8(%r14), %rbp
subq (%r14), %rbp
je 0x6d59
sarq $0x3, %rbp
movq (%r14), %rax
movq -0x8(%rax,%rbp,8), %rdi
movq (%rdi), %rax
movsd 0x8(%rsp), %xmm0
callq *0x8(%rax)
decq %rbp
jne 0x6d40
testb %r12b, %r12b
je 0x7087
movq 0x526f(%rip), %r14      # 0xbfd8
leaq 0x1901(%rip), %rsi      # 0x8671
movl $0xe, %edx
movq %r14, %rdi
callq 0x21b0
leaq 0x28(%rsp), %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x5c6e
movq (%r12), %rsi
movq 0x8(%r12), %rdx
movq %r14, %rdi
callq 0x21b0
leaq 0x18db(%rip), %rsi      # 0x8680
movl $0x5, %edx
movq %rax, %rdi
callq 0x21b0
movq %rbx, 0x8(%rsp)
leaq 0x38(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x6dd2
movq 0x38(%rsp), %rsi
incq %rsi
callq 0x21a0
testq %r15, %r15
je 0x6f76
xorl %r12d, %r12d
movq %r15, 0x20(%rsp)
movl $0xe, %ebp
movl $0xfffffefb, %ebx       # imm = 0xFFFFFEFB
movl $0x100, %r15d           # imm = 0x100
movl $0xe, %edx
movq %r14, %rdi
leaq 0x186f(%rip), %rsi      # 0x8671
callq 0x21b0
movq (%r14), %rax
movq -0x18(%rax), %rax
leaq (%r14,%rax), %r13
cmpb $0x0, 0xe1(%r14,%rax)
jne 0x6e39
movq %r13, %rdi
movl $0x20, %esi
callq 0x2170
movb %al, 0xe0(%r13)
movb $0x1, 0xe1(%r13)
movb $0x20, 0xe0(%r13)
movq (%r14), %rax
movq -0x18(%rax), %rcx
movq $0x14, 0x10(%r14,%rcx)
movzbl %r12b, %ecx
shll $0x4, %ecx
leaq 0x4c59(%rip), %rdx      # 0xbab8
movq (%rcx,%rdx), %r13
testq %r13, %r13
je 0x6e80
movq %r13, %rdi
callq 0x2070
movq %r14, %rdi
movq %r13, %rsi
movq %rax, %rdx
callq 0x21b0
jmp 0x6e95
movq -0x18(%rax), %rax
leaq (%r14,%rax), %rdi
movl 0x20(%r14,%rax), %esi
orl $0x1, %esi
callq 0x2260
movq (%r14), %rax
movq -0x18(%rax), %rcx
movq %rbp, 0x10(%r14,%rcx)
movq -0x18(%rax), %rcx
movl 0x18(%r14,%rcx), %edx
andl %ebx, %edx
orl %r15d, %edx
movl %edx, 0x18(%r14,%rcx)
movq -0x18(%rax), %rax
movl $0x3, %ecx
movq %rcx, 0x8(%r14,%rax)
movl $0x3, %r13d
movq 0x8(%rsp), %rax
movsd (%rax,%r12,8), %xmm0
movq %r14, %rdi
callq 0x2220
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %rbp, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %ebx, %esi
orl %r15d, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %r13, 0x8(%rax,%rcx)
movq (%rsp), %r13
movq -0x30(%r13), %rcx
movsd (%rcx,%r12,8), %xmm0
movq %rax, %rdi
callq 0x2220
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %rbp, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %ebx, %esi
orl %r15d, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movl $0x3, %edx
movq %rdx, 0x8(%rax,%rcx)
movq -0x18(%r13), %rcx
movsd (%rcx,%r12,8), %xmm0
movq %rax, %rdi
callq 0x2220
movl $0x1, %edx
movq %rax, %rdi
leaq 0x15a0(%rip), %rsi      # 0x8503
callq 0x21b0
incq %r12
cmpq %r12, 0x20(%rsp)
jne 0x6df3
leaq 0x16f4(%rip), %rsi      # 0x8671
movl $0xe, %ebx
movl $0xe, %edx
movq %r14, %rdi
callq 0x21b0
movq (%r14), %rax
movq -0x18(%rax), %rax
movq $0x14, 0x10(%r14,%rax)
leaq 0x16e0(%rip), %rsi      # 0x8686
movl $0x8, %edx
movq %r14, %rdi
callq 0x21b0
movq (%r14), %rax
movq -0x18(%rax), %rcx
movq %rbx, 0x10(%r14,%rcx)
movq -0x18(%rax), %rcx
movl $0xfffffefb, %ebp       # imm = 0xFFFFFEFB
movl 0x18(%r14,%rcx), %edx
andl %ebp, %edx
movl $0x100, %r15d           # imm = 0x100
orl %r15d, %edx
movl %edx, 0x18(%r14,%rcx)
movq -0x18(%rax), %rax
movl $0x3, %r12d
movq %r12, 0x8(%r14,%rax)
movq %r14, %rdi
movsd 0x10(%rsp), %xmm0
callq 0x2220
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %rbx, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
movl 0x18(%rax,%rdx), %esi
andl %ebp, %esi
orl %r15d, %esi
movl %esi, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %r12, 0x8(%rax,%rcx)
movq (%rsp), %r14
movq -0x30(%r14), %rcx
movq 0x18(%rsp), %r13
movsd -0x8(%rcx,%r13,8), %xmm0
movq %rax, %rdi
callq 0x2220
movq (%rax), %rcx
movq -0x18(%rcx), %rdx
movq %rbx, 0x10(%rax,%rdx)
movq -0x18(%rcx), %rdx
andl 0x18(%rax,%rdx), %ebp
orl %r15d, %ebp
movl %ebp, 0x18(%rax,%rdx)
movq -0x18(%rcx), %rcx
movq %r12, 0x8(%rax,%rcx)
movq -0x18(%r14), %rcx
movsd -0x8(%rcx,%r13,8), %xmm0
movq %rax, %rdi
callq 0x2220
leaq 0x1489(%rip), %rsi      # 0x8503
movl $0x1, %edx
movq %rax, %rdi
callq 0x21b0
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x38(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x70b4
movq 0x38(%rsp), %rsi
incq %rsi
callq 0x21a0
movq %rbx, %rdi
callq 0x2290