// File: ghulette[P]neural-net-openmp/neuralnet.cpp
// Function: NeuralNet::train(double*, double*, double)
void NeuralNet::train(double *input, double *desired_output, double eta) {
  run(input);
  double *iv = input;
  double *hv = hidden_values;
  double *ov = output_values;
  double *dv = desired_output;
  
  // Calculate weight deltas for the output layer
  #pragma omp parallel for
  for(int i=0; i < num_outputs; i++) {
    output_weight_deltas[i] = (dv[i] - ov[i]) * ov[i] * (1.0 - ov[i]);
  }
    
  // Calculate weight deltas for the hidden layer
  #pragma omp parallel for
  for(int i=0; i < num_hidden; i++) {
    double sum = 0.0;
    for(int j=0; j < num_outputs; j++) {
      sum += output_weight_deltas[j] * output_weights[j][i];
    }
    hidden_weight_deltas[i] = sum * hv[i] * (1.0 - hv[i]);
  }
        
  // Update output layer weights
  #pragma omp parallel for
  for(int i=0; i < num_outputs; i++) {
    for(int j=0; j < num_hidden; j++) {
      output_weights[i][j] += eta * output_weight_deltas[i] * hv[j];
    }
  }
            
  // Update hidden layer weights
  #pragma omp parallel for
  for(int i=0; i < num_hidden; i++) {
    for(int j=0; j < num_inputs; j++) {
      hidden_weights[i][j] += eta * hidden_weight_deltas[i] * iv[j];
    }
  }
}

// Assembly:
subq $0x78, %rsp
movq %rdi, 0x70(%rsp)
movq %rsi, 0x68(%rsp)
movq %rdx, 0x60(%rsp)
movsd %xmm0, 0x58(%rsp)
movq 0x70(%rsp), %rdi
movq %rdi, 0x8(%rsp)
movq 0x68(%rsp), %rsi
callq 0x4ac0
movq 0x8(%rsp), %rax
movq 0x68(%rsp), %rcx
movq %rcx, 0x50(%rsp)
movq 0x28(%rax), %rcx
movq %rcx, 0x48(%rsp)
movq 0x48(%rax), %rax
movq %rax, 0x40(%rsp)
movq 0x60(%rsp), %rax
movq %rax, 0x38(%rsp)
movl $0x0, 0x34(%rsp)
movq 0x8(%rsp), %rcx
movl 0x34(%rsp), %eax
cmpl 0x8(%rcx), %eax
jge 0x4d36
movq 0x8(%rsp), %rax
movq 0x38(%rsp), %rcx
movslq 0x34(%rsp), %rdx
movsd (%rcx,%rdx,8), %xmm0
movq 0x40(%rsp), %rcx
movslq 0x34(%rsp), %rdx
subsd (%rcx,%rdx,8), %xmm0
movq 0x40(%rsp), %rcx
movslq 0x34(%rsp), %rdx
mulsd (%rcx,%rdx,8), %xmm0
movq 0x40(%rsp), %rcx
movslq 0x34(%rsp), %rdx
movsd 0x12fe(%rip), %xmm1     # 0x6010
subsd (%rcx,%rdx,8), %xmm1
mulsd %xmm1, %xmm0
movq 0x40(%rax), %rax
movslq 0x34(%rsp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl 0x34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0x4cc0
movl $0x0, 0x30(%rsp)
movq 0x8(%rsp), %rcx
movl 0x30(%rsp), %eax
cmpl 0x4(%rcx), %eax
jge 0x4e0d
xorps %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
movl $0x0, 0x24(%rsp)
movq 0x8(%rsp), %rcx
movl 0x24(%rsp), %eax
cmpl 0x8(%rcx), %eax
jge 0x4dba
movq 0x8(%rsp), %rax
movq 0x40(%rax), %rcx
movslq 0x24(%rsp), %rdx
movsd (%rcx,%rdx,8), %xmm0
movq 0x30(%rax), %rax
movslq 0x24(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0x30(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm2
movsd 0x28(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x28(%rsp)
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0x4d61
movq 0x8(%rsp), %rax
movsd 0x28(%rsp), %xmm0
movq 0x48(%rsp), %rcx
movslq 0x30(%rsp), %rdx
mulsd (%rcx,%rdx,8), %xmm0
movq 0x48(%rsp), %rcx
movslq 0x30(%rsp), %rdx
movsd 0x122a(%rip), %xmm1     # 0x6010
subsd (%rcx,%rdx,8), %xmm1
mulsd %xmm1, %xmm0
movq 0x20(%rax), %rax
movslq 0x30(%rsp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl 0x30(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x30(%rsp)
jmp 0x4d3e
movl $0x0, 0x20(%rsp)
movq 0x8(%rsp), %rcx
movl 0x20(%rsp), %eax
cmpl 0x8(%rcx), %eax
jge 0x4ea8
movl $0x0, 0x1c(%rsp)
movq 0x8(%rsp), %rcx
movl 0x1c(%rsp), %eax
cmpl 0x4(%rcx), %eax
jge 0x4e96
movq 0x8(%rsp), %rax
movsd 0x58(%rsp), %xmm0
movq 0x40(%rax), %rcx
movslq 0x20(%rsp), %rdx
mulsd (%rcx,%rdx,8), %xmm0
movq 0x48(%rsp), %rcx
movslq 0x1c(%rsp), %rdx
movsd (%rcx,%rdx,8), %xmm2
movq 0x30(%rax), %rax
movslq 0x20(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0x1c(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x4e2f
jmp 0x4e98
movl 0x20(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20(%rsp)
jmp 0x4e15
movl $0x0, 0x18(%rsp)
movq 0x8(%rsp), %rcx
movl 0x18(%rsp), %eax
cmpl 0x4(%rcx), %eax
jge 0x4f42
movl $0x0, 0x14(%rsp)
movq 0x8(%rsp), %rcx
movl 0x14(%rsp), %eax
cmpl (%rcx), %eax
jge 0x4f30
movq 0x8(%rsp), %rax
movsd 0x58(%rsp), %xmm0
movq 0x20(%rax), %rcx
movslq 0x18(%rsp), %rdx
mulsd (%rcx,%rdx,8), %xmm0
movq 0x50(%rsp), %rcx
movslq 0x14(%rsp), %rdx
movsd (%rcx,%rdx,8), %xmm2
movq 0x10(%rax), %rax
movslq 0x18(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0x14(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl 0x14(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x14(%rsp)
jmp 0x4eca
jmp 0x4f32
movl 0x18(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x18(%rsp)
jmp 0x4eb0
addq $0x78, %rsp
retq
nopw (%rax,%rax)