ECF 1.5
sga.c
1/* sga.c
2 *
3 * (C) 2018 Carlos M. Fonseca <cmfonsec@dei.uc.pt>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <math.h>
23#include <gsl/gsl_rng.h>
24#include <gsl/gsl_randist.h>
25#include "sga.h"
26
27extern gsl_rng *rng; /* The single rng instance used by the whole code */
28
30 struct problem *p;
31 struct solution **parent, **offspring, *best;
32 struct move *v;
33 struct pathState *ps;
34 double *cost, *fitness, mincost, **ranking_aux;
35 int popsize, i;
36 double Px, Pm, SP;
37};
38
39/* Auxiliary functions */
40
41static int cmp_doublep(const void *a, const void *b) {
42 double x = **(double **) a;
43 double y = **(double **) b;
44 if (x < y)
45 return -1;
46 else if (x > y)
47 return 1;
48 else
49 return 0;
50}
51
52static void ranking(double *fitness, double **aux, double *cost, double sp, int n) {
53 int i, j, k;
54 double num, den;
55 for (i = 0; i < n; i++)
56 aux[i] = cost + i;
57 qsort(aux, n, sizeof(double *), cmp_doublep);
58 for (i = 0; i < n; i = j) {
59 num = sp - (sp-1.) * 2.0 * i / (n-1.);
60 den = 1.;
61 for (j = i+1; j < n && *aux[i] == *aux[j]; j++) {
62 num += sp - (sp-1.) * 2.0 * j / (n-1.);
63 den += 1.;
64 }
65 for (k = i; k < j; k++)
66 fitness[aux[k]-cost] = num / den;
67 }
68}
69
70static void sus(struct solution **o, struct solution **p, const double *f, int nsel, int n) {
71 struct solution *tmp;
72 double x, cumfit, totfit = 0.0;
73 int i, j, last_i;
74
75 for (i = j = 0; i < n; i++)
76 totfit += f[i];
77 x = gsl_rng_uniform(rng);
78 cumfit = f[0];
79 last_i = -1;
80 i = j = 0;
81 while (j < nsel) {
82 if (totfit * x < cumfit * nsel) {
83 if (i != last_i) { /* avoid copying the first time */
84 tmp = o[j];
85 o[j] = p[i];
86 p[i] = tmp;
87 last_i = i;
88 } else
89 copySolution(o[j], o[j-1]);
90 j++;
91 x += 1.;
92 } else if (i < n-1) {
93 cumfit += f[++i];
94 } else {
95 /* should never *ever* happen */
96 fprintf(stderr, "SUS warning: end of parent array reached.");
97 break;
98 }
99 }
100 /* Shuffle offspring */
101 for (i = n-1; i > 0; i--) {
102 j = gsl_rng_uniform_int(rng, i+1);
103 tmp = o[i];
104 o[i] = o[j];
105 o[j] = tmp;
106 }
107}
108
109/* Single step mutation (in place) */
110static void single_step_mutation(struct solution **pop, int n, double Pm, struct move *tmpmove) {
111 int i;
112 for (i = 0; i < n; i++)
113 if (gsl_rng_uniform(rng) < Pm) {
114 randomMove(tmpmove, pop[i]);
115 applyMove(pop[i], tmpmove);
116 }
117}
118
119/* Standard mutation (in place) */
120static void standard_mutation(struct solution **pop, int n, double Pm, struct move *tmpmove, struct pathState *tmppath) {
121 double pm;
122 int i, j, k;
123 for (i = 0; i < n; i++) {
124 initPathAwayFrom(tmppath, pop[i]);
125 k = getPathLength(tmppath);
126 pm = 1.-pow(1.-Pm, 1./k);
127 k = gsl_ran_binomial(rng, pm, k);
128 for (j = 0; j < k; j++) {
129 nextRandomMove(tmpmove, tmppath);
130 applyMove(pop[i], tmpmove);
131 }
132 }
133}
134
135/* Geometric recombination (in place) */
136static void geometric_recombination(struct solution **pop, int n, double Px, struct move *tmpmove, struct pathState *tmppath) {
137 struct solution *tmpsol;
138 int i, k;
139 tmpsol = pop[n-1];
140 for (i = 0; i < n; i++) {
141 if (gsl_rng_uniform(rng) < Px) {
142 initPathTo(tmppath, tmpsol, pop[i]);
143 k = getPathLength(tmppath);
144 if (k > 1) {
145 k -= gsl_rng_uniform_int(rng, k/2)+1;
146 /* This depends on the current path length being updated by
147 * nextRandomMove() and assumes that calling getPathLength() is
148 * cheap. */
149 while (getPathLength(tmppath) > k) {
150 nextRandomMove(tmpmove, tmppath);
151 applyMove(tmpsol, tmpmove);
152 }
153 }
154 }
155 tmpsol = pop[i];
156 }
157}
158
159/* Solver API functions */
160
161struct solverState *newSolver(struct problem *p, int popsize) {
162 struct solverState *ss;
163 int i;
164 /* memory allocation */
165 ss = malloc(sizeof (struct solverState));
166 ss->p = p;
167 ss->popsize = popsize;
168 ss->parent = malloc(popsize * sizeof (struct solution *));
169 for (i = 0; i < popsize; i++)
170 ss->parent[i] = allocSolution(p);
171 ss->best = allocSolution(p);
172 ss->cost = malloc(popsize * sizeof (double));
173 /* temporary workspace */
174 ss->offspring = malloc(popsize * sizeof (struct solution *));
175 for (i = 0; i < popsize; i++)
176 ss->offspring[i] = allocSolution(p);
177 ss->v = allocMove(p);
178 ss->ps = allocPathState(p);
179 ss->ranking_aux = malloc(popsize * sizeof (double *));
180 ss->fitness = malloc(popsize * sizeof (double));
181 /* state initialisation */
182 for (i = 0; i < popsize; i++) {
183 randomSolution(ss->parent[i]);
184 }
185 ss->mincost = INFINITY;
186 for (i = 0; i < popsize; i++) {
187 ss->cost[i] = getObjectiveValue(ss->parent[i]);
188 if (ss->cost[i] < ss->mincost) {
189 ss->mincost = ss->cost[i];
190 copySolution(ss->best, ss->parent[i]);
191 }
192 }
193 /* default parameter values */
194 ss->SP = 2.;
195 ss->Px = .6;
196 ss->Pm = (1.-1./ss->SP)*.8;
197 return ss;
198}
199
200void freeSolver(struct solverState *ss) {
201 int i;
202 free(ss->ranking_aux);
203 free(ss->fitness);
204 freePathState(ss->ps);
205 freeMove(ss->v);
206 for (i = 0; i < ss->popsize; i++) {
207 freeSolution(ss->offspring[i]);
208 freeSolution(ss->parent[i]);
209 }
210 freeSolution(ss->best);
211 free(ss->cost);
212 free(ss->offspring);
213 free(ss->parent);
214 free(ss);
215}
216
217struct solverState *nextSolverState(struct solverState *ss) {
218 struct solution **tmppop;
219 int popsize = ss->popsize, i;
220
221 /* Fitness assignment */
222 ranking(ss->fitness, ss->ranking_aux, ss->cost, ss->SP, ss->popsize);
223
224 /* Parental selection (sampling) */
225 sus(ss->offspring, ss->parent, ss->fitness, popsize, popsize);
226
227 /* Geometric recombination (in place) */
228 geometric_recombination(ss->offspring, popsize, ss->Px, ss->v, ss->ps);
229
230#if 1
231 /* Single-step mutation (in place) */
232 single_step_mutation(ss->offspring, popsize, ss->Pm, ss->v);
233#else
234 /* Independent mutation (in place) */
235 standard_mutation(ss->offspring, popsize, ss->Pm, ss->v, ss->ps);
236#endif
237
238 /* Unconditional generational replacement */
239 tmppop = ss->parent;
240 ss->parent = ss->offspring;
241 ss->offspring = tmppop;
242 for (i = 0; i < popsize; i++) {
243 ss->cost[i] = getObjectiveValue(ss->parent[i]);
244 if (ss->cost[i] < ss->mincost) {
245 ss->mincost = ss->cost[i];
246 copySolution(ss->best, ss->parent[i]);
247 }
248 }
249 return ss;
250}
251
252struct solution *getSolverSolution(struct solverState *ss) {
253 return ss->best;
254}
255
256void printSolverState(struct solverState *ss) {
257 fprintf(stderr, "sga: printSolverState() not implemented yet.\n");
258}
259
260/* Solver specific functions */
261
262double getSelectivePressure(struct solverState *ss) {
263 return ss->SP;
264}
265
266double getRecombinationRate(struct solverState *ss) {
267 return ss->Px;
268}
269
270double getMutationRate(struct solverState *ss) {
271 return ss->Pm;
272}
273
274void setSelectivePressure(struct solverState *ss, double SP) {
275 if (SP >= 1. && SP <= 2.)
276 ss->SP = SP;
277 else
278 fprintf(stderr, "sga: Invalid selective pressure. Unchanged.\n");
279}
280
281void setRecombinationRate(struct solverState *ss, double Px) {
282 if (Px >= 0. && Px <= 1.)
283 ss->Px = Px;
284 else
285 fprintf(stderr, "sga: Invalid recombination rate. Unchanged.\n");
286}
287
288void setMutationRate(struct solverState *ss, double Pm) {
289 if (Pm >= 0. && Pm <= 1.)
290 ss->Pm = Pm;
291 else
292 fprintf(stderr, "sga: Invalid mutation rate. Unchanged.\n");
293}
294
Definition: flowshop.h:78