-
Notifications
You must be signed in to change notification settings - Fork 0
/
sa.cpp
337 lines (265 loc) · 9.82 KB
/
sa.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
//
// name : sabd.cpp
// version : 1.0
// date : 99.05.07
// made by : sverre stikbakke
// description: Simulated annealing algorithm used
// on biodiversity data.
//
// syntax : sabd ck_0 Lk_0 red_rate outlevel
//
// reference : Aarts and Korst, 1989.
// Simulated Annealing and Boltzmann Machines.
//
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SPECIES 133 // number of species
#define UNITS 155 // number of UNITS
#define MAX_SELECTED 10 // number of UNITS to be selected
#define IMPROVEMENT_CRITERION 5 // part of stopcriterion
#define TEMPERATURE_CRITERION 0.00001 // part of stopcriterion
int data[UNITS][SPECIES] = // matrix of species composition
#include "species.txt"
int solution[MAX_SELECTED]; // vector of UNITS currently in the solution
int candidate_solution[MAX_SELECTED]; // vector of UNITS to be evaluated as the
// next solution
float ck; // control parameter (temperature)
int Lk; // step-length (iterations on each temperature)
float ck_0; // initial temperature
int Lk_0; // initial step-length
float red_rate; // temperature reduction rate
int outlevel; // output level control
int k; // step counter
int l; // iteration counter at each step
int m; // iteration counter
int no_improvement; // counter for non-improving steps
int accepted; // counter for accepted solutions on each step
int Z; // objective function value
int new_Z; // objective function value of new solution
int max_Z; // max value on each step
// function prototypes
void print_usage();
int random(int _max_val);
void init(int *_solution);
bool unique_units(int *_solution);
bool stopcriterion();
void generate(int *_solution, int *_candidate_solution);
int eval_obj_f(int *_canditate_solution);
bool accept(int _new_Z, int _Z, int *_candidate_solution, int *_solution);
void insert(int *_candidate_solution, int *_solution);
void calculate_control(float _red_rate);
void print_solution(int *_solution, int _Z);
void print_result();
using std::cout;
//----------------------------------------------------------------------------//
// main function
//----------------------------------------------------------------------------//
int main(int argc, char *argv[]) {
// command line argument handling
if (argc < 4) {
print_usage();
return -1;
}
sscanf(argv[1], "%g", &ck_0);
Lk_0 = atoi(argv[2]);
sscanf(argv[3], "%g", &red_rate);
outlevel = atoi(argv[4]) || 0;
// initialize parameters and make first solution
ck = ck_0;
Lk = Lk_0;
srand(time(NULL)); // random number generator initialization
do {
init(solution);
} while (!unique_units(solution));
Z = eval_obj_f(solution);
max_Z = Z;
// main loop
while (!stopcriterion()) {
// loop on each step (temperature)
max_Z = 0;
for (int l = 0; l < Lk; l++) {
do {
generate(solution, candidate_solution);
} while (!unique_units(candidate_solution));
new_Z = eval_obj_f(candidate_solution);
// save max Z value on each iteration
if (new_Z > max_Z) {
max_Z = new_Z;
}
if (accept(new_Z, Z, candidate_solution, solution)) {
insert(candidate_solution, solution);
Z = new_Z;
accepted++;
}
m++; // iteration counter
}
k++; // step counter
// update control parameters
if (accepted == 0) {
no_improvement++;
} else {
no_improvement = 0;
}
accepted = 0;
calculate_control(red_rate);
} // end main loop
print_result();
return 0;
}
//----------------------------------------------------------------------------//
// init - generate a random initial soluton
//----------------------------------------------------------------------------//
void init(int *_solution) {
for (int i = 0; i < MAX_SELECTED; i++) {
_solution[i] = random(UNITS);
}
}
//----------------------------------------------------------------------------//
// test if units in solution are unique
//----------------------------------------------------------------------------//
bool unique_units(int *_solution) {
for (int i = 0; i < MAX_SELECTED; i++) {
for (int j = 0; j < MAX_SELECTED; j++) {
if ((i != j) && (_solution[i] == _solution[j])) {
return false;
};
}
}
return true;
}
//----------------------------------------------------------------------------//
// generate - make a new solution by changing one unit randomly
//----------------------------------------------------------------------------//
void generate(int *_solution, int *_candidate_solution) {
for (int i = 0; i < MAX_SELECTED; i++) {
_candidate_solution[i] = _solution[i];
}
int position_to_change = random(MAX_SELECTED);
int new_unit_selected = random(UNITS);
_candidate_solution[position_to_change] = new_unit_selected;
}
//----------------------------------------------------------------------------//
// eval_obj_f - counts species in solution
//----------------------------------------------------------------------------//
int eval_obj_f(int *_solution) {
int units_with_specie = 0;
int species_in_solution = 0;
// loop over all species
for (int i = 0; i < SPECIES; i++) {
// loop over all units in _solution
// and count actual specie
units_with_specie = 0;
for (int j = 0; j < MAX_SELECTED; j++) {
units_with_specie = units_with_specie + data[_solution[j]][i];
}
if (units_with_specie > 0) {
species_in_solution++;
}
}
return species_in_solution;
}
//----------------------------------------------------------------------------//
// print_solution
//----------------------------------------------------------------------------//
void print_solution(int *_solution, int _Z) {
cout << "Z = " << _Z << " ";
for (int i = 0; i < MAX_SELECTED; i++) {
// prints unit number starting with index 1
cout << _solution[i] + 1 << " ";
}
cout << " m: " << m << "\n";
}
//----------------------------------------------------------------------------//
// accept - decides whether the candidate solution will
// replace current solution
//----------------------------------------------------------------------------//
bool accept(int _new_Z, int _Z, int *_candidate_solution, int *_solution) {
int diff = 0;
for (int i = 0; i < MAX_SELECTED; i++) {
if (_solution[i] != _candidate_solution[i]) {
diff++;
}
}
if (diff == 0) {
return false;
}
if (new_Z >= Z) {
return true;
} else {
// accept a non-improving solution?
// evaluate _new_Z against _Z under
// influence of temperature ck
float A = (_new_Z - _Z) / ck;
float eval = exp(A);
// generate random number in [0, 1]
float p = random(1000) * 0.001;
if (eval > p) {
return true;
}
}
return false;
}
//----------------------------------------------------------------------------//
// insert new solution
//----------------------------------------------------------------------------//
void insert(int *_candidate_solution, int *_solution) {
for (int i = 0; i < MAX_SELECTED; i++) {
_solution[i] = _candidate_solution[i];
}
}
//----------------------------------------------------------------------------//
// calculate_control: lower temperature
//----------------------------------------------------------------------------//
void calculate_control(float _red_rate) { ck = ck - ck * _red_rate; }
//----------------------------------------------------------------------------//
// stopcriterion based on non-improving steps
//----------------------------------------------------------------------------//
bool stopcriterion() {
if (no_improvement > IMPROVEMENT_CRITERION || ck < TEMPERATURE_CRITERION) {
return true;
} else
return false;
}
//----------------------------------------------------------------------------//
// random number function (seeded in main function)
//----------------------------------------------------------------------------//
int random(int _max_val) { return (rand() % _max_val); }
//----------------------------------------------------------------------------//
// print usage
//----------------------------------------------------------------------------//
void print_usage() {
cout << "\nUsage: \n\n";
cout << "sabd ck_0 Lk_0 red_rate outlevel\n\n";
cout << "where\n\n";
cout << "ck_0 = initial temperature (e.g. 35) \n";
cout << "Lk_0 = iterations on each step (e.g. 50) \n";
cout << "red_rate = temperature reduction rate (e.g. 0.2) \n";
cout << "outlevel = output level control (0,1,2,5,6,7) \n\n";
cout << " 0 : only summary \n";
cout << " 1,2,5,6,7 : not in effect in this version \n";
}
//----------------------------------------------------------------------------//
// print results
//----------------------------------------------------------------------------//
void print_result() {
cout << "\n############## Simulated annealing results summary ###############"
"###\n\n";
cout << "Parameters: \n\n";
cout << "initial temperature, ck_0: " << ck_0 << "\n";
cout << "iterations on each step, Lk_0: " << Lk_0 << "\n";
cout << "temperature reduction rate : " << red_rate << "\n";
cout << "output level control : " << outlevel << "\n";
cout << "\n";
cout << "Results: \n\n";
cout << "Steps (k): " << k << "\n";
cout << "Iterations (m): " << m << "\n";
cout << "Final state temperature: " << ck << "\n";
cout << "\n";
cout << "Last accepted solution: \n\n";
print_solution(solution, Z);
cout << "\n##################################################################"
"###\n";
}