// File: /workspace/github_cpp_makefile_star2_O2/ruippeixotog[P]algo-lib/simulated-annealing.cpp
// Function: void simulatedAnnealing<Sol, Mut>(Sol&, double, double, double)
void simulatedAnnealing(
    Sol& solution, double maxt, double mint, double finishAtTime) {

  // sync means calculating current temperature from current work time
  static const int ITERS_PER_SYNC = 16;       // must be power of two
  // sometimes we dump current progress to stderr
  static const int ITERS_PER_DUMP = 0x40000;  // must be power of two
  // type of solution score
  typedef double ScoreType;

  // number of iterations done so far
  int iters = 0;
  // part of the full cooling schedule passed
  double done = 0.0;
  // best solution so far
  Sol best = solution;
  // number of accepted mutations overall
  int accMuts = 0;

  // time when the SA begins
  double startTime = getTime();
  // time dedicated for SA processing
  double hasTime = finishAtTime - (startTime - globalStartTime);

  while(true) {
    // dump stats so that you can watch the progress of SA
    if (!(iters & (ITERS_PER_DUMP - 1)))
      fprintf(stderr, "Iteration:%6d  Acc:%6d  Temp:%7.3lf  Score:%0.5lf\n",
              iters, accMuts, maxt * pow(mint / maxt, done),
              solution.getScore());
    // synchronize the temperature with time
    if (!(iters & (ITERS_PER_SYNC - 1))) {
      done = (getTime() - startTime) / hasTime;
      if (done >= 1.0) break;
    }

    // create mutation for current solution
    Mut mut;
    mut.init(solution);
    // get the score delta of the mutation
    ScoreType delta = mut.getScore();

    //if mutated solution is better, accept it
    bool move = false;
    if (delta <= 0) move = true;
    else {
      // otherwise calculate current temperature
      double temp = maxt * pow(mint / maxt, done);
      // and accept with the tricky probability
      move = ((double) rand() / (RAND_MAX)) < exp(-delta / temp);
    }

    // if mutation is accepted, apply it to the solution
    if (move) { accMuts++; mut.apply(solution); }

    // do not forget to store the best solution
    if (solution.getScore() < best.getScore()) best = solution;
    iters++;
  }

  //return the best solution as the result
  fprintf(stderr, "Simulated annealing made %d iterations (accepted: %d)\n",
          iters, accMuts);
  solution = best;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movsd %xmm2, 0x8(%rsp)
movsd %xmm1, (%rsp)
movsd %xmm0, 0x10(%rsp)
movq %rdi, %rbx
movupd (%rdi), %xmm0
movups 0x10(%rdi), %xmm1
movups 0x20(%rdi), %xmm2
movups 0x2c(%rdi), %xmm3
movups %xmm3, 0x6c(%rsp)
movaps %xmm2, 0x60(%rsp)
movaps %xmm1, 0x50(%rsp)
movapd %xmm0, 0x40(%rsp)
movl 0x3c(%rdi), %r14d
callq 0x11bc
movsd %xmm0, 0x28(%rsp)
subsd 0x3061(%rip), %xmm0     # 0x4400
movsd 0x8(%rsp), %xmm1
subsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
movsd (%rsp), %xmm0
divsd 0x10(%rsp), %xmm0
movsd %xmm0, (%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
xorl %ebp, %ebp
pushq $0xf
popq %r13
leaq 0x20(%rsp), %r12
xorl %r15d, %r15d
testl $0x3ffff, %r15d         # imm = 0x3FFFF
je 0x14da
testb $0xf, %r15b
jne 0x140f
callq 0x11bc
subsd 0x28(%rsp), %xmm0
divsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
ucomisd 0xc27(%rip), %xmm0      # 0x2030
jae 0x151e
callq 0x1040
cltd
idivl %r13d
movl %edx, 0x20(%rsp)
movq %r12, %rdi
movq %rbx, %rsi
callq 0x1574
movl 0x24(%rsp), %eax
testl %eax, %eax
jle 0x1493
cvtsi2sd %eax, %xmm0
xorpd 0xc05(%rip), %xmm0      # 0x2040
movapd %xmm0, 0x80(%rsp)
movsd (%rsp), %xmm0
movsd 0x18(%rsp), %xmm1
callq 0x1090
mulsd 0x10(%rsp), %xmm0
movsd %xmm0, 0x38(%rsp)
callq 0x1040
cvtsi2sd %eax, %xmm0
divsd 0xbc7(%rip), %xmm0      # 0x2038
movsd %xmm0, 0x30(%rsp)
movapd 0x80(%rsp), %xmm0
divsd 0x38(%rsp), %xmm0
callq 0x10a0
ucomisd 0x30(%rsp), %xmm0
jbe 0x14a0
incl %ebp
movq %r12, %rdi
movq %rbx, %rsi
callq 0x160c
movl 0x3c(%rbx), %eax
cmpl %r14d, %eax
jge 0x14d2
movupd (%rbx), %xmm0
movupd 0x10(%rbx), %xmm1
movups 0x20(%rbx), %xmm2
movups 0x2c(%rbx), %xmm3
movups %xmm3, 0x6c(%rsp)
movaps %xmm2, 0x60(%rsp)
movapd %xmm1, 0x50(%rsp)
movapd %xmm0, 0x40(%rsp)
movl %eax, %r14d
incl %r15d
jmp 0x13d7
movq 0x2aff(%rip), %rax      # 0x3fe0
movq (%rax), %r13
movsd (%rsp), %xmm0
movsd 0x18(%rsp), %xmm1
callq 0x1090
mulsd 0x10(%rsp), %xmm0
cvtsi2sdl 0x3c(%rbx), %xmm1
movq %r13, %rdi
pushq $0xf
popq %r13
leaq 0xb47(%rip), %rsi       # 0x2054
movl %r15d, %edx
movl %ebp, %ecx
movb $0x2, %al
callq 0x1070
jmp 0x13e4
movq 0x2abb(%rip), %rax      # 0x3fe0
movq (%rax), %rdi
leaq 0xb58(%rip), %rsi       # 0x2087
movl %r15d, %edx
movl %ebp, %ecx
xorl %eax, %eax
callq 0x1070
movaps 0x40(%rsp), %xmm0
movaps 0x50(%rsp), %xmm1
movaps 0x60(%rsp), %xmm2
movups %xmm0, (%rbx)
movups %xmm1, 0x10(%rbx)
movups %xmm2, 0x20(%rbx)
movups 0x6c(%rsp), %xmm0
movups %xmm0, 0x2c(%rbx)
movl %r14d, 0x3c(%rbx)
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq