// File: /workspace/github_cpp_makefile_star2_O3/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 $0xa8, %rsp
movsd %xmm2, 0x10(%rsp)
movsd %xmm1, 0x8(%rsp)
movsd %xmm0, 0x18(%rsp)
movq %rdi, %rbx
movups (%rdi), %xmm0
movups 0x10(%rdi), %xmm1
movups 0x20(%rdi), %xmm2
movups 0x2c(%rdi), %xmm3
movups %xmm3, 0x7c(%rsp)
movaps %xmm2, 0x70(%rsp)
movaps %xmm1, 0x60(%rsp)
movaps %xmm0, 0x50(%rsp)
movl 0x3c(%rdi), %r12d
xorl %r14d, %r14d
leaq 0x28(%rsp), %r13
movq %r13, %rdi
xorl %esi, %esi
callq 0x1080
cvtsi2sdq (%r13), %xmm0
cvtsi2sdq 0x8(%r13), %xmm1
mulsd 0xed5(%rip), %xmm1      # 0x2008
addsd %xmm0, %xmm1
movsd %xmm1, 0x38(%rsp)
movapd %xmm1, %xmm0
subsd 0x32b7(%rip), %xmm0     # 0x4400
movsd 0x10(%rsp), %xmm1
subsd %xmm0, %xmm1
movsd %xmm1, 0x10(%rsp)
movsd 0x8(%rsp), %xmm0
divsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
pushq $0xf
popq %r15
xorl %ebp, %ebp
testl $0x3ffff, %ebp          # imm = 0x3FFFF
je 0x12b9
testb $0xf, %bpl
jne 0x11d1
movq %r13, %rdi
xorl %esi, %esi
callq 0x1080
cvtsi2sdq 0x28(%rsp), %xmm0
cvtsi2sdq 0x30(%rsp), %xmm1
mulsd 0xe5b(%rip), %xmm1      # 0x2008
addsd %xmm0, %xmm1
subsd 0x38(%rsp), %xmm1
divsd 0x10(%rsp), %xmm1
movsd %xmm1, 0x20(%rsp)
ucomisd 0xe65(%rip), %xmm1      # 0x2030
jae 0x12ff
callq 0x1040
cltd
idivl %r15d
movl %edx, 0x28(%rsp)
movq %r13, %rdi
movq %rbx, %rsi
callq 0x1620
movl 0x2c(%rsp), %ecx
testl %ecx, %ecx
jle 0x125a
cvtsi2sd %ecx, %xmm0
xorpd 0xe83(%rip), %xmm0      # 0x2080
movapd %xmm0, 0x90(%rsp)
movsd 0x8(%rsp), %xmm0
movsd 0x20(%rsp), %xmm1
callq 0x1090
mulsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
callq 0x1040
cvtsi2sd %eax, %xmm0
divsd 0xe04(%rip), %xmm0      # 0x2038
movsd %xmm0, 0x40(%rsp)
movapd 0x90(%rsp), %xmm0
divsd 0x48(%rsp), %xmm0
callq 0x10a0
ucomisd 0x40(%rsp), %xmm0
jbe 0x1280
movl 0x2c(%rsp), %ecx
incl %r14d
movslq 0x28(%rsp), %rsi
movl (%rbx,%rsi,4), %edi
leal 0x1(%rsi), %eax
cltd
idivl %r15d
movslq %edx, %rax
movl (%rbx,%rax,4), %edx
movl %edx, (%rbx,%rsi,4)
movl %edi, (%rbx,%rax,4)
addl 0x3c(%rbx), %ecx
movl %ecx, 0x3c(%rbx)
jmp 0x1283
movl 0x3c(%rbx), %ecx
cmpl %r12d, %ecx
jge 0x12b2
movupd (%rbx), %xmm0
movupd 0x10(%rbx), %xmm1
movups 0x20(%rbx), %xmm2
movups 0x2c(%rbx), %xmm3
movups %xmm3, 0x7c(%rsp)
movaps %xmm2, 0x70(%rsp)
movapd %xmm1, 0x60(%rsp)
movapd %xmm0, 0x50(%rsp)
movl %ecx, %r12d
incl %ebp
jmp 0x117b
movq 0x2d20(%rip), %rax      # 0x3fe0
movq (%rax), %r13
movsd 0x8(%rsp), %xmm0
movsd 0x20(%rsp), %xmm1
callq 0x1090
mulsd 0x18(%rsp), %xmm0
cvtsi2sdl 0x3c(%rbx), %xmm1
movq %r13, %rdi
leaq 0x28(%rsp), %r13
leaq 0xda6(%rip), %rsi       # 0x2094
movl %ebp, %edx
movl %r14d, %ecx
movb $0x2, %al
callq 0x1070
jmp 0x1187
movq 0x2cda(%rip), %rax      # 0x3fe0
movq (%rax), %rdi
leaq 0xdb7(%rip), %rsi       # 0x20c7
movl %ebp, %edx
movl %r14d, %ecx
xorl %eax, %eax
callq 0x1070
movaps 0x50(%rsp), %xmm0
movaps 0x60(%rsp), %xmm1
movaps 0x70(%rsp), %xmm2
movups %xmm0, (%rbx)
movups %xmm1, 0x10(%rbx)
movups %xmm2, 0x20(%rbx)
movups 0x7c(%rsp), %xmm0
movups %xmm0, 0x2c(%rbx)
movl %r12d, 0x3c(%rbx)
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq