// File: 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:
subq $0x1c8, %rsp            # imm = 0x1C8
movb %cl, %al
movq %rdi, 0x1c0(%rsp)
movq %rsi, 0x1b8(%rsp)
movq %rdx, 0x1b0(%rsp)
movsd %xmm0, 0x1a8(%rsp)
movsd %xmm1, 0x1a0(%rsp)
andb $0x1, %al
movb %al, 0x19f(%rsp)
movq 0x1c0(%rsp), %rax
movq %rax, 0xe0(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x190(%rsp)
movq $0x0, 0x188(%rsp)
cmpq $0x1d, 0x188(%rsp)
jae 0x12450
movq 0x1b0(%rsp), %rdi
movq 0x188(%rsp), %rsi
callq 0xae20
movsd (%rax), %xmm0
addsd 0x190(%rsp), %xmm0
movsd %xmm0, 0x190(%rsp)
movq 0x188(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x188(%rsp)
jmp 0x12404
movq 0xe0(%rsp), %rdi
movq 0x1b8(%rsp), %rsi
callq 0xabd0
movq 0xe0(%rsp), %rdi
addq $0x18, %rdi
callq 0xb5c0
movq %rax, 0x180(%rsp)
movq 0x180(%rsp), %rdi
callq 0x8350
subq $0x1, %rax
movq %rax, 0x178(%rsp)
movq $0x0, 0x170(%rsp)
movq 0x170(%rsp), %rax
cmpq 0x178(%rsp), %rax
jae 0x12564
movq 0x1b0(%rsp), %rdi
movq 0x170(%rsp), %rsi
callq 0xae20
movsd (%rax), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movsd %xmm0, 0xd0(%rsp)
movq 0x180(%rsp), %rdi
movq 0x170(%rsp), %rsi
callq 0x8b00
movsd 0xd0(%rsp), %xmm0
movsd 0xbd8(%rip), %xmm1      # 0x130f0
addsd (%rax), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0xd8(%rsp)
movq 0x180(%rsp), %rdi
movq 0x170(%rsp), %rsi
callq 0x8b30
movsd 0xd8(%rsp), %xmm0
movsd %xmm0, (%rax)
movq 0x170(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x170(%rsp)
jmp 0x124a3
movsd 0x1a8(%rsp), %xmm0
movsd 0xb73(%rip), %xmm1      # 0x130e8
mulsd %xmm1, %xmm0
movsd 0xa9f(%rip), %xmm1      # 0x13020
addsd %xmm1, %xmm0
movsd %xmm0, 0x168(%rsp)
movq 0x180(%rsp), %rdi
movq 0x178(%rsp), %rsi
callq 0x8b00
movsd (%rax), %xmm0
divsd 0x168(%rsp), %xmm0
callq 0x2110
movaps %xmm0, %xmm1
movsd 0xb20(%rip), %xmm0      # 0x130e0
mulsd %xmm1, %xmm0
movsd %xmm0, 0xc0(%rsp)
movq 0x180(%rsp), %rdi
movq 0x178(%rsp), %rsi
callq 0x8b00
movsd 0xc0(%rsp), %xmm0
divsd (%rax), %xmm0
movsd %xmm0, 0xc8(%rsp)
movq 0x180(%rsp), %rdi
movq 0x178(%rsp), %rsi
callq 0x8b30
movsd 0xc8(%rsp), %xmm0
movq 0xe0(%rsp), %rdi
movsd %xmm0, (%rax)
callq 0x7940
movq %rax, 0x160(%rsp)
cmpq $0x0, 0x160(%rsp)
jbe 0x12683
movq 0xe0(%rsp), %rdi
movq 0x160(%rsp), %rsi
subq $0x1, %rsi
callq 0xb590
movq %rax, %rdi
callq 0xb5b0
movq %rax, %rdi
movsd 0x1a0(%rsp), %xmm0
movq (%rdi), %rax
callq *0x8(%rax)
movq 0x160(%rsp), %rax
addq $-0x1, %rax
movq %rax, 0x160(%rsp)
jmp 0x1262f
testb $0x1, 0x19f(%rsp)
je 0x12b7a
movq 0x9940(%rip), %rdi      # 0x1bfd8
leaq 0xf8c(%rip), %rsi       # 0x1362b
callq 0x2180
movq %rax, 0xa8(%rsp)
movq 0x1b8(%rsp), %rsi
leaq 0x140(%rsp), %rdi
movq %rdi, 0xb0(%rsp)
callq 0xf010
movq 0xa8(%rsp), %rdi
movq 0xb0(%rsp), %rsi
callq 0x2140
movq %rax, 0xb8(%rsp)
jmp 0x126e8
movq 0xb8(%rsp), %rdi
leaq 0xf43(%rip), %rsi       # 0x1363a
callq 0x2180
jmp 0x126fe
leaq 0x140(%rsp), %rdi
callq 0x20b0
movq $0x0, 0x128(%rsp)
movq 0x128(%rsp), %rax
cmpq 0x178(%rsp), %rax
jae 0x129ac
movq 0x98a4(%rip), %rdi      # 0x1bfd8
leaq 0xef0(%rip), %rsi       # 0x1362b
callq 0x2180
movq %rax, 0x48(%rsp)
movl $0x20, %edi
callq 0xfdb0
movq 0x48(%rsp), %rdi
movb %al, 0x127(%rsp)
movzbl 0x127(%rsp), %esi
callq 0x2240
movq %rax, 0x50(%rsp)
movl $0x14, %edi
callq 0xfd90
movq 0x50(%rsp), %rdi
movl %eax, 0x120(%rsp)
movl 0x120(%rsp), %esi
callq 0x21c0
movq %rax, 0x58(%rsp)
movq 0x128(%rsp), %rax
movzbl %al, %edi
callq 0x2530
movq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x2180
movq %rax, 0x60(%rsp)
movl $0xe, %edi
callq 0xfd90
movq 0x60(%rsp), %rdi
movl %eax, 0x11c(%rsp)
movl 0x11c(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq -0x4552(%rip), %rsi     # 0xe290
callq 0x2050
movq %rax, 0x68(%rsp)
movl $0x3, %edi
callq 0xe2b0
movq 0x68(%rsp), %rdi
movl %eax, 0x118(%rsp)
movl 0x118(%rsp), %esi
callq 0x2250
movq %rax, 0x70(%rsp)
movq 0x1b0(%rsp), %rdi
movq 0x128(%rsp), %rsi
callq 0xae20
movq 0x70(%rsp), %rdi
movsd (%rax), %xmm0
callq 0x22f0
movq %rax, 0x78(%rsp)
movl $0xe, %edi
callq 0xfd90
movq 0x78(%rsp), %rdi
movl %eax, 0x114(%rsp)
movl 0x114(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq -0x45d7(%rip), %rsi     # 0xe290
callq 0x2050
movq %rax, 0x80(%rsp)
movl $0x3, %edi
callq 0xe2b0
movq 0x80(%rsp), %rdi
movl %eax, 0x110(%rsp)
movl 0x110(%rsp), %esi
callq 0x2250
movq %rax, 0x88(%rsp)
movq 0x180(%rsp), %rdi
movq 0x128(%rsp), %rsi
callq 0x8b00
movq 0x88(%rsp), %rdi
movsd (%rax), %xmm0
callq 0x22f0
movq %rax, 0x90(%rsp)
movl $0xe, %edi
callq 0xfd90
movq 0x90(%rsp), %rdi
movl %eax, 0x10c(%rsp)
movl 0x10c(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq -0x466e(%rip), %rsi     # 0xe290
callq 0x2050
movq %rax, 0x98(%rsp)
movl $0x3, %edi
callq 0xe2b0
movq 0x98(%rsp), %rdi
movl %eax, 0x108(%rsp)
movl 0x108(%rsp), %esi
callq 0x2250
movq %rax, 0xa0(%rsp)
movq 0x180(%rsp), %rdi
movq 0x128(%rsp), %rsi
callq 0x8b30
movq 0xa0(%rsp), %rdi
movsd (%rax), %xmm0
callq 0x22f0
movq %rax, %rdi
leaq 0xb55(%rip), %rsi       # 0x134bd
callq 0x2180
movq 0x128(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x128(%rsp)
jmp 0x12717
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x138(%rsp)
movl %eax, 0x134(%rsp)
leaq 0x140(%rsp), %rdi
callq 0x20b0
jmp 0x12b82
movq 0x9625(%rip), %rdi      # 0x1bfd8
leaq 0xc71(%rip), %rsi       # 0x1362b
callq 0x2180
movq %rax, (%rsp)
movl $0x14, %edi
callq 0xfd90
movq (%rsp), %rdi
movl %eax, 0x104(%rsp)
movl 0x104(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq 0xc52(%rip), %rsi       # 0x13640
callq 0x2180
movq %rax, 0x8(%rsp)
movl $0xe, %edi
callq 0xfd90
movq 0x8(%rsp), %rdi
movl %eax, 0x100(%rsp)
movl 0x100(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq -0x4794(%rip), %rsi     # 0xe290
callq 0x2050
movq %rax, 0x10(%rsp)
movl $0x3, %edi
callq 0xe2b0
movq 0x10(%rsp), %rdi
movl %eax, 0xfc(%rsp)
movl 0xfc(%rsp), %esi
callq 0x2250
movq %rax, %rdi
movsd 0x1a8(%rsp), %xmm0
callq 0x22f0
movq %rax, 0x18(%rsp)
movl $0xe, %edi
callq 0xfd90
movq 0x18(%rsp), %rdi
movl %eax, 0xf8(%rsp)
movl 0xf8(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq -0x4802(%rip), %rsi     # 0xe290
callq 0x2050
movq %rax, 0x20(%rsp)
movl $0x3, %edi
callq 0xe2b0
movq 0x20(%rsp), %rdi
movl %eax, 0xf4(%rsp)
movl 0xf4(%rsp), %esi
callq 0x2250
movq %rax, 0x28(%rsp)
movq 0x180(%rsp), %rdi
movq 0x178(%rsp), %rsi
callq 0x8b00
movq 0x28(%rsp), %rdi
movsd (%rax), %xmm0
callq 0x22f0
movq %rax, 0x30(%rsp)
movl $0xe, %edi
callq 0xfd90
movq 0x30(%rsp), %rdi
movl %eax, 0xf0(%rsp)
movl 0xf0(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
leaq -0x4887(%rip), %rsi     # 0xe290
callq 0x2050
movq %rax, 0x38(%rsp)
movl $0x3, %edi
callq 0xe2b0
movq 0x38(%rsp), %rdi
movl %eax, 0xec(%rsp)
movl 0xec(%rsp), %esi
callq 0x2250
movq %rax, 0x40(%rsp)
movq 0x180(%rsp), %rdi
movq 0x178(%rsp), %rsi
callq 0x8b30
movq 0x40(%rsp), %rdi
movsd (%rax), %xmm0
callq 0x22f0
movq %rax, %rdi
leaq 0x948(%rip), %rsi       # 0x134bd
callq 0x2180
addq $0x1c8, %rsp            # imm = 0x1C8
retq
movq 0x138(%rsp), %rdi
callq 0x22c0
nop