1
{ **********************************************************************
4
* (c) J. Debord, August 2000 *
5
**********************************************************************
6
This unit implements simulated annealing for function minimization
7
**********************************************************************
8
Reference: Program SIMANN.FOR by Bill Goffe
9
(http://www.netlib.org/simann)
10
********************************************************************** }
17
FMath, Matrices, Optim, Stat;
20
SA_Nt : Integer = 5; { Number of loops at constant temperature }
21
SA_Ns : Integer = 15; { Number of loops before step adjustment }
22
SA_Rt : Float = 0.9; { Temperature reduction factor }
23
SA_NCycles : Integer = 1; { Number of cycles }
25
function SimAnn(Func : TFuncNVar;
26
X, Xmin, Xmax : PVector;
27
Lbound, Ubound : Integer;
30
var F_min : Float) : Integer;
31
{ ----------------------------------------------------------------------
32
Minimization of a function of several variables by simulated annealing
33
----------------------------------------------------------------------
34
Input parameters : Func = objective function to be minimized
35
X = initial minimum coordinates
36
Xmin = minimum value of X
37
Xmax = maximum value of X
39
Ubound = indices of first and last variables
40
MaxIter = max number of annealing steps
41
Tol = required precision
42
----------------------------------------------------------------------
43
Output parameter : X = refined minimum coordinates
44
F_min = function value at minimum
45
----------------------------------------------------------------------
46
Possible results : OPT_OK
48
---------------------------------------------------------------------- }
53
LogFile : Text; { Stores the result of each minimization step }
55
procedure CreateLogFile;
57
Assign(LogFile, LogFileName);
61
function InitTemp(Func : TFuncNVar;
62
X, Xmin, Range : PVector;
63
Lbound, Ubound : Integer) : Float;
64
{ ----------------------------------------------------------------------
65
Computes the initial temperature so that the probability
66
of accepting an increase of the function is about 0.5
67
---------------------------------------------------------------------- }
69
N_EVAL = 50; { Number of function evaluations }
71
T : Float; { Temperature }
72
F, F1 : Float; { Function values }
73
DeltaF : PVector; { Function increases }
74
N_inc : Integer; { Number of function increases }
75
I : Integer; { Index of function evaluation }
76
K : Integer; { Index of parameter }
78
DimVector(DeltaF, N_EVAL);
84
{ Compute N_EVAL function values, changing each parameter in turn }
86
for I := 1 to N_EVAL do
88
X^[K] := Xmin^[K] + RanMar * Range^[K];
93
DeltaF^[N_inc] := F1 - F;
97
if K > Ubound then K := Lbound;
100
{ The median M of these N_eval values has a probability of 1/2.
101
From Boltzmann's formula: Exp(-M/T) = 1/2 ==> T = M / Ln(2) }
102
T := Median(DeltaF, 1, N_inc) / LN2;
103
if T = 0.0 then T := 1.0;
106
DelVector(DeltaF, N_EVAL);
109
function ParamConv(X, Step : PVector;
110
Lbound, Ubound : Integer;
111
Tol : Float) : Boolean;
112
{ ----------------------------------------------------------------------
113
Checks for convergence on parameters
114
---------------------------------------------------------------------- }
122
Conv := Conv and (Step^[I] < FMax(Tol, Tol * Abs(X^[I])));
124
until (Conv = False) or (I > Ubound);
128
function Accept(DeltaF, T : Float;
129
var N_inc, N_acc : Integer) : Boolean;
130
{ ----------------------------------------------------------------------
131
Checks if a variation DeltaF of the function at temperature T is
132
acceptable. Updates the counters N_inc (number of increases of the
133
function) and N_acc (number of accepted increases).
134
---------------------------------------------------------------------- }
141
if Expo(- DeltaF / T) > RanMar then
151
function SimAnnCycle(Func : TFuncNVar;
152
X, Xmin, Xmax : PVector;
153
Lbound, Ubound : Integer;
157
var F_min : Float) : Integer;
158
{ ----------------------------------------------------------------------
159
Performs one cycle of simulated annealing
160
---------------------------------------------------------------------- }
162
N_FACT = 2.0; { Factor for step reduction }
164
I, Iter, J, K, N_inc, N_acc : Integer;
165
F, F1, DeltaF, Ratio, T, OldX : Float;
166
Range, Step, Xopt : PVector;
169
DimVector(Step, Ubound);
170
DimVector(Xopt, Ubound);
171
DimVector(Range, Ubound);
172
DimIntVector(Nacc, Ubound);
174
{ Determine parameter range, step and optimum }
175
for K := Lbound to Ubound do
177
Range^[K] := Xmax^[K] - Xmin^[K];
178
Step^[K] := 0.5 * Range^[K];
182
{ Initialize function values }
186
{ Initialize temperature and iteration count }
187
T := InitTemp(Func, X, Xmin, Range, Lbound, Ubound);
191
{ Perform SA_Nt evaluations at constant temperature }
192
N_inc := 0; N_acc := 0;
193
for I := 1 to SA_Nt do
195
for J := 1 to SA_Ns do
196
for K := Lbound to Ubound do
198
{ Save current parameter value }
201
{ Pick new value, keeping it within Range }
202
X^[K] := X^[K] + (2.0 * RanMar - 1.0) * Step^[K];
203
if (X^[K] < Xmin^[K]) or (X^[K] > Xmax^[K]) then
204
X^[K] := Xmin^[K] + RanMar * Range^[K];
206
{ Compute new function value }
210
{ Check for acceptance }
211
if Accept(DeltaF, T, N_inc, N_acc) then
217
{ Restore parameter value }
220
{ Update minimum if necessary }
228
{ Ajust step length to maintain an acceptance
229
ratio of about 50% for each parameter }
230
for K := Lbound to Ubound do
232
Ratio := Int(Nacc^[K]) / Int(SA_Ns);
235
{ Increase step length, keeping it within Range }
236
Step^[K] := Step^[K] * (1.0 + ((Ratio - 0.6) / 0.4) * N_FACT);
237
if Step^[K] > Range^[K] then Step^[K] := Range^[K];
239
else if Ratio < 0.4 then
240
{ Reduce step length }
241
Step^[K] := Step^[K] / (1.0 + ((0.4 - Ratio) / 0.4) * N_FACT);
249
WriteLn(LogFile, Iter:4, ' ', T:12, ' ', F:12, N_inc:6, N_acc:6);
251
{ Update temperature and iteration count }
254
until ParamConv(Xopt, Step, Lbound, Ubound, Tol) or (Iter > MaxIter);
256
for K := Lbound to Ubound do
259
DelVector(Step, Ubound);
260
DelVector(Xopt, Ubound);
261
DelVector(Range, Ubound);
262
DelIntVector(Nacc, Ubound);
264
if Iter > MaxIter then
265
SimAnnCycle := OPT_NON_CONV
267
SimAnnCycle := OPT_OK;
270
function SimAnn(Func : TFuncNVar;
271
X, Xmin, Xmax : PVector;
272
Lbound, Ubound : Integer;
275
var F_min : Float) : Integer;
277
Cycle, ErrCode : Integer;
282
{ Initialize the Marsaglia random number generator
283
using the standard Pascal generator }
285
RMarIn(System.Random(10000), System.Random(10000));
291
WriteLn(LogFile, 'Simulated annealing: Cycle ', Cycle);
293
WriteLn(LogFile, 'Iter T F Inc Acc');
296
ErrCode := SimAnnCycle(Func, X, Xmin, Xmax, Lbound, Ubound,
297
MaxIter, Tol, LogFile, F_min);
300
until (Cycle > SA_NCycles) or (ErrCode <> OPT_OK);