// File: /workspace/github_cpp_makefile_star2_O1/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, 0x8(%rsp)
movsd %xmm1, (%rsp)
movsd %xmm0, 0x10(%rsp)
movq %rdi, %rbx
movups (%rdi), %xmm0
movups 0x10(%rdi), %xmm1
movups 0x20(%rdi), %xmm2
movups 0x2c(%rdi), %xmm3
movups %xmm3, 0x8c(%rsp)
movaps %xmm2, 0x80(%rsp)
movaps %xmm1, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movl 0x3c(%rdi), %r12d
xorl %r14d, %r14d
leaq 0x20(%rsp), %r15
movq %r15, %rdi
xorl %esi, %esi
callq 0x1080
cvtsi2sdq (%r15), %xmm0
cvtsi2sdq 0x8(%r15), %xmm1
mulsd 0xed1(%rip), %xmm1      # 0x2008
addsd %xmm0, %xmm1
movsd %xmm1, 0x48(%rsp)
movapd %xmm1, %xmm0
subsd 0x32b3(%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)
pushq $0xf
popq %r13
xorl %ebp, %ebp
testl $0x3ffff, %ebp          # imm = 0x3FFFF
je 0x12b5
testb $0xf, %bpl
jne 0x11d3
movq %r15, %rdi
xorl %esi, %esi
callq 0x1080
cvtsi2sdq 0x20(%rsp), %xmm0
cvtsi2sdq 0x28(%rsp), %xmm1
mulsd 0xe59(%rip), %xmm1      # 0x2008
addsd %xmm0, %xmm1
subsd 0x48(%rsp), %xmm1
divsd 0x8(%rsp), %xmm1
movsd %xmm1, 0x18(%rsp)
ucomisd 0xe63(%rip), %xmm1      # 0x2030
jae 0x12fc
callq 0x1040
cltd
idivl %r13d
movl %edx, 0x20(%rsp)
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1620
movl 0x24(%rsp), %eax
testl %eax, %eax
jle 0x1251
cvtsi2sd %eax, %xmm0
xorpd 0xe81(%rip), %xmm0      # 0x2080
movapd %xmm0, 0x30(%rsp)
movsd (%rsp), %xmm0
movsd 0x18(%rsp), %xmm1
callq 0x1090
mulsd 0x10(%rsp), %xmm0
movsd %xmm0, 0x58(%rsp)
callq 0x1040
cvtsi2sd %eax, %xmm0
divsd 0xe06(%rip), %xmm0      # 0x2038
movsd %xmm0, 0x50(%rsp)
movapd 0x30(%rsp), %xmm0
divsd 0x58(%rsp), %xmm0
callq 0x10a0
ucomisd 0x50(%rsp), %xmm0
jbe 0x1276
incl %r14d
movslq 0x20(%rsp), %rcx
movl (%rbx,%rcx,4), %esi
leal 0x1(%rcx), %eax
cltd
idivl %r13d
movslq %edx, %rax
movl (%rbx,%rax,4), %edx
movl %edx, (%rbx,%rcx,4)
movl %esi, (%rbx,%rax,4)
movl 0x24(%rsp), %eax
addl %eax, 0x3c(%rbx)
movl 0x3c(%rbx), %eax
cmpl %r12d, %eax
jge 0x12ae
movupd (%rbx), %xmm0
movupd 0x10(%rbx), %xmm1
movups 0x20(%rbx), %xmm2
movups 0x2c(%rbx), %xmm3
movups %xmm3, 0x8c(%rsp)
movaps %xmm2, 0x80(%rsp)
movapd %xmm1, 0x70(%rsp)
movapd %xmm0, 0x60(%rsp)
movl %eax, %r12d
incl %ebp
jmp 0x117d
movq 0x2d24(%rip), %rax      # 0x3fe0
movq (%rax), %rax
movq %rax, 0x30(%rsp)
movsd (%rsp), %xmm0
movsd 0x18(%rsp), %xmm1
callq 0x1090
mulsd 0x10(%rsp), %xmm0
cvtsi2sdl 0x3c(%rbx), %xmm1
movq 0x30(%rsp), %rdi
leaq 0xda9(%rip), %rsi       # 0x2094
movl %ebp, %edx
movl %r14d, %ecx
movb $0x2, %al
callq 0x1070
jmp 0x1189
movq 0x2cdd(%rip), %rax      # 0x3fe0
movq (%rax), %rdi
leaq 0xdba(%rip), %rsi       # 0x20c7
movl %ebp, %edx
movl %r14d, %ecx
xorl %eax, %eax
callq 0x1070
movaps 0x60(%rsp), %xmm0
movaps 0x70(%rsp), %xmm1
movaps 0x80(%rsp), %xmm2
movups %xmm0, (%rbx)
movups %xmm1, 0x10(%rbx)
movups %xmm2, 0x20(%rbx)
movups 0x8c(%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