#### Simulated Annealing

Examples using this package can be found in The N Queens Problem (SA), The Travelling Salesman Problem (SA) and Graceful Tree Labelling (SA).

```/* This is the procedure to be invoked by the application program, in      */
/*   which size/1, perturb/2, energy/2 and output/3 must be defined.       */
anneal:-
size(Size),
N is 10 * Size,             /* Number of iterations per temperature      */
MaxSucc is 1 * Size,        /* Maximum number of changes per temperature */
repeat,
perm_rand(Size, Xs),
energy(Xs, EnergyXs),
EnergyXs =\= 0, !,          /* Avoid division by zero in oracle/3        */
Temp is EnergyXs / Size,    /* Initial temperature                       */
anneal_1(100, N, Temp, 0.90, MaxSucc, s(Xs,EnergyXs), s([],32767),
s(Ys, EnergyYs), Result),
output(Result, Ys, EnergyYs).

/* anneal_1(M, N, Temp, Factor, MaxSucc, State, s([],32767), Best, Result) */
/*   is true if Best is the best state (a list and its energy) obtained by */
/*   annealing the State at M different temperatures (or after no changes  */
/*   have been made at a given temperature, or if the energy becomes zero),*/
/*   with N iterations per temperature (or after the state has been        */
/*   changed MaxSucc times at this temperature).  Temp is the initial      */
/*   temperature, and it is multiplied by Factor at each iteration. Result */
/*   indicates the result of the annealing: optimal - an optimal solution  */
/*   has been found; iterations - all iterations have been executed        */
/*   without finding an optimal solution; nochanges - no changes were made */
/*   at a given temperature and an optimal solution has not been found.    */
anneal_1(_, _, _, _, _, _, s(Xs, 0), s(Xs, 0), optimal):-!.
anneal_1(0, _, _, _, _, _, Best, Best, iterations):-!.
anneal_1(M, TempIters, Temp, Factor, MaxSucc, State0, Best0, Best, Res):-
anneal_2(TempIters, MaxSucc, MaxSucc, Temp, State0, State1, Best0, Best1),
!,
M1 is M - 1,
Temp1 is Temp * Factor,
anneal_1(M1, TempIters, Temp1, Factor, MaxSucc, State1, Best1, Best, Res).
anneal_1(_, _, _, _, _, _, Best, Best, nochanges).

/* anneal_2(N, MaxSucc, MaxSucc, Temp, State0, State, Best0, Best) is true */
/*   if State0 (a list and its energy) is transformed into State after N   */
/*   iterations at this Temp, or after the state has been changed MaxSucc  */
/*   times. Best0 is the previous best-so-far, and Best is the new best-   */
/*   so-far state.  It fails if, at the end of N iterations, no changes    */
anneal_2(0, Success, MaxSucc, _, State, State, Best, Best):-!,
Success < MaxSucc.
/* All iterations have been performed and at least one change made */
anneal_2(_, 0, _, _, State, State, Best, Best):-!.
/* The specified number of changes have been made */
anneal_2(N, Success, MaxSucc, Temp, s(Xs0, Energy0), State, Best0, Best):-
perturb(Xs0, Xs1),
energy(Xs1, Energy1),
oracle(Energy0, Energy1, Temp), !,
better(Best0, s(Xs1, Energy1), Best1),
Success1 is Success - 1,
N1 is N - 1,
anneal_2(N1, Success1, MaxSucc, Temp, s(Xs1, Energy1), State, Best1, Best).
anneal_2(N, Success, MaxSucc, Temp, State0, State, Best0, Best):-
N1 is N - 1,
anneal_2(N1, Success, MaxSucc, Temp, State0, State, Best0, Best).

/* oracle(EnergyXs, EnergyYs, Temp) is true if EnergyYs < EnergyXs         */
/*   or Random < exp((EnergyYs - EnergyXs) / -Temp).                       */
oracle(EnergyXs, EnergyYs, _):-
EnergyYs < EnergyXs, !.
oracle(EnergyXs, EnergyYs, Temp):-
ln(rand(1)) < (EnergyXs - EnergyYs) / Temp.

/* better(State0, State1, State) is true if State is the better of State0  */
/*   and State1.  (The state with the lower energy is the better state.)   */
better(s(_, Energy0), s(Xs1, Energy1), s(Xs1, Energy1)):-
Energy1 < Energy0, !.
better(State, _, State).

/* perm_rand(N, Perm) is true if Perm is a pseudo-random permutation of    */
/*   the integers 1 to N inclusive.                                        */
perm_rand(N, Perm):-
N >= 0,
perm_rand_1(N, N, [], Perm).

perm_rand_1(0, _, Perm, Perm):-!.
perm_rand_1(M, N, Perm0, Perm):-
repeat,
random(N, Rand),
\+ member(Rand, Perm0), !,
M1 is M - 1,
perm_rand_1(M1, N, [Rand|Perm0], Perm).

/* random(I, J) is true if J is a pseudo-random integer in the range       */
/*   1..J.                                                                 */
random(I, J):-J is int(rand(I))+1.

/* member(X, Ys) is true if the element X is contained in the list Ys.     */
% member(X, [X|_]).
% member(X, [_|Ys]):-member(X, Ys).

/* repeat/0 always succeeds.                                               */
% repeat.
% repeat:-repeat.
```