-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalgorithm.c
More file actions
208 lines (194 loc) · 6.49 KB
/
algorithm.c
File metadata and controls
208 lines (194 loc) · 6.49 KB
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
#include <stdlib.h>
#include <limits.h>
#include "algorithm.h"
double get_random()
{
// utility to get a random double between 0 and 1
return (double) rand() / RAND_MAX;
}
int less_than(const void * a, const void * b) {
// function used to sort doubles with qsort
return ( *(double*)a > *(double*)b ) ? 1 : 0;
}
void algorithm_get_parents_and_mutants(int* p1, int* p2, int* m)
{
// this function fills the arrays p1 and p2 with the indexes selected to be parents
// (at random according to the probability) and m with the indexes selected to mutate.
double random;
int index_m = 0, index_p = 0;
for (int i = 0; i < POPSIZE; i++) {
random = get_random();
if (random < MUTATIONPROB) {
m[index_m++] = i;
}
else if (random < MUTATIONPROB + CROSSOVERPROB) {
if (index_p % 2) {
p2[index_p/2] = i;
}
else {
p1[index_p/2] = i;
}
index_p++;
}
}
p1[index_p/2] = -1;
p2[index_p/2] = -1;
m[index_m] = -1;
}
void generation_init(struct generation* self)
{
// initialization of the struct generation
self->population = (struct precalcs*)malloc(POPSIZE*sizeof(struct precalcs));
self->best = (struct precalcs*)malloc(sizeof(struct precalcs));
for (int i = 0; i < POPSIZE; i++) {
weights_init(&self->population[i]);
}
}
void generation_destruct(struct generation* self)
{
// memory release
free(self->population);
free(self->best);
}
void algorithm_mutation(struct precalcs* weights)
{
// mutation consists in increasing or decreasing each weight in a random number up to
// 10 with a certain probability.
// valid flag is used for not having to recalculate the score in unmodified individuals
if (get_random() < CHANGEPROB) {
weights->holes += (rand() % 21) - 10;
}
if (get_random() < CHANGEPROB) {
weights->row_transitions += (rand() % 21) - 10;
}
if (get_random() < CHANGEPROB) {
weights->column_transitions += (rand() % 21) - 10;
}
if (get_random() < CHANGEPROB) {
weights->heights += (rand() % 21) - 10;
}
weights->valid = 0;
}
void algorithm_crossover(struct precalcs* weights1, struct precalcs* weights2)
{
// crossover consists in swapping each weight of a couple of individuals with a
// certain probability.
// valid flag is used for not having to recalculate the score in unmodified individuals
int aux;
if (get_random() < CHANGEPROB) {
aux = weights1->holes;
weights1->holes = weights2->holes;
weights2->holes = aux;
}
if (get_random() < CHANGEPROB) {
aux = weights1->row_transitions;
weights1->row_transitions = weights2->row_transitions;
weights2->row_transitions = aux;
}
if (get_random() < CHANGEPROB) {
aux = weights1->column_transitions;
weights1->column_transitions = weights2->column_transitions;
weights2->column_transitions = aux;
}
if (get_random() < CHANGEPROB) {
aux = weights1->heights;
weights1->heights = weights2->heights;
weights2->heights = aux;
}
weights1->valid = 0;
weights2->valid = 0;
}
void algorithm_get_scores(struct generation* self, struct data* info)
{
// calculate the score of each individual
for (int i = 0; i < POPSIZE; i++) {
if (!self->population[i].valid) {
weights_run_loop(&self->population[i], info, 0, 0);
}
}
}
void algorithm_set_slices(struct generation* self)
{
// using the roulette's method here.
// this function set the slices with the accumulative probability for selection
int best_index = 0, best_score = INT_MIN;
self->total = 0;
self->worst = 0;
for (int i = 0; i < POPSIZE; i++) {
self->total += self->population[i].score;
if (self->population[i].score < self->worst) {
self->worst = self->population[i].score;
}
if (self->population[i].score > best_score) {
best_index = i;
}
}
self->total += -POPSIZE * self->worst;
weights_copy(self->best, &self->population[best_index]);
for (int i = 0; i < POPSIZE; i++) {
self->slices[i] = (self->population[i].score - self->worst) / self->total;
self->slices[i] += (i > 0 ? self->slices[i-1] : 0);
//printf("%d, %f\n", i, self->slices[i]);
}
//printf("\n");
}
void algorithm_selection(struct generation* self)
{
// a set of random doubles is generated and the new individuals are selected
// depending where do they land on the roulette
double rands[POPSIZE];
struct precalcs aux[POPSIZE];
for (int i = 0; i < POPSIZE; i++) {
rands[i] = get_random();
weights_copy(&aux[i], &self->population[i]);
}
qsort(rands, POPSIZE, sizeof(double), less_than);
int current_index = 0;
for (int i = 0; i < POPSIZE; i++) {
while (rands[i] > self->slices[current_index] && current_index < POPSIZE) {
current_index++;
}
weights_copy(&self->population[i], &aux[current_index]);
//printf("%d, %f\n", current_index, rands[i]);
}
}
void algorithm_crossover_and_mutate(struct generation* self)
{
// after the selection parents and mutants are selected at random and modifications take place
int p1[POPSIZE];
int p2[POPSIZE];
int m[POPSIZE];
algorithm_get_parents_and_mutants(p1, p2, m);
for (int i = 0; p1[i] != -1; i++) {
algorithm_crossover(&self->population[p1[i]], &self->population[p2[i]]);
}
for (int i = 0; m[i] != -1; i++) {
algorithm_mutation(&self->population[m[i]]);
}
}
void algorithm_elitism(struct generation* self)
{
// the worst scored not-modified individual is replaced with the best individual
// of the previous generation
int worst_score = INT_MAX;
int worst_index = -1;
for (int i = 0; i < POPSIZE; i++) {
if (self->population[i].valid && self->population[i].score < worst_score) {
worst_score = self->population[i].score;
worst_index = i;
}
}
weights_copy(&self->population[worst_index], self->best);
}
void algorithm_run_evolution(struct generation* self, struct data* info)
{
// the full genetic algorithm
for (int i = 0; i < MAXGENS; i++) {
algorithm_get_scores(self, info);
algorithm_set_slices(self);
algorithm_selection(self);
algorithm_elitism(self);
}
algorithm_get_scores(self, info);
algorithm_set_slices(self);
}