// File: 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:
subq $0xe8, %rsp
movq %rdi, 0xe0(%rsp)
movsd %xmm0, 0xd8(%rsp)
movsd %xmm1, 0xd0(%rsp)
movsd %xmm2, 0xc8(%rsp)
movl $0x0, 0xc4(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xb8(%rsp)
movq 0xe0(%rsp), %rsi
leaq 0x78(%rsp), %rdi
movl $0x40, %edx
callq 0x1050
movl $0x0, 0x74(%rsp)
callq 0x11e0
movsd %xmm0, 0x68(%rsp)
movsd 0xc8(%rsp), %xmm0
movsd 0x68(%rsp), %xmm1
subsd 0x2ede(%rip), %xmm1     # 0x4400
subsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
movl 0xc4(%rsp), %eax
andl $0x3ffff, %eax          # imm = 0x3FFFF
cmpl $0x0, %eax
jne 0x15d6
movq 0x2a98(%rip), %rax      # 0x3fe0
movq (%rax), %rax
movq %rax, 0x28(%rsp)
movl 0xc4(%rsp), %eax
movl %eax, 0x30(%rsp)
movl 0x74(%rsp), %eax
movl %eax, 0x34(%rsp)
movsd 0xd8(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0xd0(%rsp), %xmm0
divsd 0xd8(%rsp), %xmm0
movsd 0xb8(%rsp), %xmm1
callq 0x10a0
movaps %xmm0, %xmm1
movsd 0x20(%rsp), %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, 0x38(%rsp)
movq 0xe0(%rsp), %rdi
callq 0x1820
movq 0x28(%rsp), %rdi
movl 0x30(%rsp), %edx
movl 0x34(%rsp), %ecx
movaps %xmm0, %xmm1
movsd 0x38(%rsp), %xmm0
leaq 0xa75(%rip), %rsi       # 0x2044
movb $0x2, %al
callq 0x1080
movl 0xc4(%rsp), %eax
andl $0xf, %eax
cmpl $0x0, %eax
jne 0x161d
callq 0x11e0
subsd 0x68(%rsp), %xmm0
divsd 0x60(%rsp), %xmm0
movsd %xmm0, 0xb8(%rsp)
movsd 0xb8(%rsp), %xmm0
movsd 0xa20(%rip), %xmm1      # 0x2030
ucomisd %xmm1, %xmm0
jb 0x161b
jmp 0x1775
jmp 0x161d
leaq 0x58(%rsp), %rdi
callq 0x1830
movq 0xe0(%rsp), %rsi
leaq 0x58(%rsp), %rdi
callq 0x1860
leaq 0x58(%rsp), %rdi
callq 0x1a60
movsd %xmm0, 0x50(%rsp)
movb $0x0, 0x4f(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x50(%rsp), %xmm0
jb 0x1663
movb $0x1, 0x4f(%rsp)
jmp 0x16fb
movsd 0xd8(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0xd0(%rsp), %xmm0
divsd 0xd8(%rsp), %xmm0
movsd 0xb8(%rsp), %xmm1
callq 0x10a0
movaps %xmm0, %xmm1
movsd 0x10(%rsp), %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, 0x40(%rsp)
callq 0x1040
cvtsi2sd %eax, %xmm0
movsd 0x982(%rip), %xmm1      # 0x2038
divsd %xmm1, %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x50(%rsp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
divsd 0x40(%rsp), %xmm0
callq 0x10b0
movsd 0x18(%rsp), %xmm1
ucomisd %xmm1, %xmm0
seta %al
andb $0x1, %al
movb %al, 0x4f(%rsp)
testb $0x1, 0x4f(%rsp)
je 0x171f
movl 0x74(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x74(%rsp)
movq 0xe0(%rsp), %rsi
leaq 0x58(%rsp), %rdi
callq 0x1a70
movq 0xe0(%rsp), %rdi
callq 0x1820
movsd %xmm0, 0x8(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x1820
movsd 0x8(%rsp), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x175f
movq 0xe0(%rsp), %rsi
leaq 0x78(%rsp), %rdi
movl $0x40, %edx
callq 0x1050
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc4(%rsp)
jmp 0x152c
movq 0x2864(%rip), %rax      # 0x3fe0
movq (%rax), %rdi
movl 0xc4(%rsp), %edx
movl 0x74(%rsp), %ecx
leaq 0x8e6(%rip), %rsi       # 0x2077
movb $0x0, %al
callq 0x1080
movq 0xe0(%rsp), %rdi
leaq 0x78(%rsp), %rsi
movl $0x40, %edx
callq 0x1050
addq $0xe8, %rsp
retq
nopw (%rax,%rax)