XCSF 1.4.8
XCSF learning classifier system
Loading...
Searching...
No Matches
ea.c
Go to the documentation of this file.
1/*
2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
24#include "ea.h"
25#include "cl.h"
26#include "clset.h"
27#include "utils.h"
28
38static void
39ea_init_offspring(const struct XCSF *xcsf, const struct Cl *c1p,
40 const struct Cl *c2p, struct Cl *c1, struct Cl *c2,
41 const bool cmod)
42{
43 if (cmod) {
44 c1->err = xcsf->ea->err_reduc * ((c1p->err + c2p->err) * 0.5);
45 c2->err = c1->err;
46 c1->fit = c1p->fit / c1p->num;
47 c2->fit = c2p->fit / c2p->num;
48 c1->fit = xcsf->ea->fit_reduc * ((c1->fit + c2->fit) * 0.5);
49 c2->fit = c1->fit;
50 } else {
51 c1->err = xcsf->ea->err_reduc * c1p->err;
52 c2->err = xcsf->ea->err_reduc * c2p->err;
53 c1->fit = xcsf->ea->fit_reduc * (c1p->fit / c1p->num);
54 c2->fit = xcsf->ea->fit_reduc * (c2p->fit / c2p->num);
55 }
56}
57
66static void
67ea_subsume(struct XCSF *xcsf, struct Cl *c, struct Cl *c1p, struct Cl *c2p,
68 const struct Set *set)
69{
70 // check if either parent subsumes the offspring
71 if (cl_subsumer(xcsf, c1p) && cl_general(xcsf, c1p, c)) {
72 ++(c1p->num);
73 ++(xcsf->pset.num);
74 cl_free(xcsf, c);
75 } else if (cl_subsumer(xcsf, c2p) && cl_general(xcsf, c2p, c)) {
76 ++(c2p->num);
77 ++(xcsf->pset.num);
78 cl_free(xcsf, c);
79 }
80 // attempt to find a random subsumer from the set
81 else {
82 struct Clist *candidates[set->size];
83 int choices = 0;
84 for (struct Clist *iter = set->list; iter != NULL; iter = iter->next) {
85 if (cl_subsumer(xcsf, iter->cl) && cl_general(xcsf, iter->cl, c)) {
86 candidates[choices] = iter;
87 ++choices;
88 }
89 }
90 if (choices > 0) { // found
91 ++(candidates[rand_uniform_int(0, choices)]->cl->num);
92 ++(xcsf->pset.num);
93 cl_free(xcsf, c);
94 }
95 // if no subsumers are found the offspring is added to the population
96 else {
97 clset_add(&xcsf->pset, c);
98 }
99 }
100}
101
112static void
113ea_add(struct XCSF *xcsf, const struct Set *set, struct Cl *c1p, struct Cl *c2p,
114 struct Cl *c1, const bool cmod, const bool mmod)
115{
116 if (!cmod && !mmod) {
117 ++(c1p->num);
118 ++(xcsf->pset.num);
119 cl_free(xcsf, c1);
120 } else if (xcsf->ea->subsumption) {
121 ea_subsume(xcsf, c1, c1p, c2p, set);
122 } else {
123 clset_add(&xcsf->pset, c1);
124 }
125}
126
134static struct Cl *
135ea_select_rw(const struct XCSF *xcsf, const struct Set *set,
136 const double fit_sum)
137{
138 (void) xcsf;
139 const double p = rand_uniform(0, fit_sum);
140 const struct Clist *iter = set->list;
141 double sum = iter->cl->fit;
142 while (p > sum) {
143 iter = iter->next;
144 sum += iter->cl->fit;
145 }
146 return iter->cl;
147}
148
155static struct Cl *
156ea_select_tournament(const struct XCSF *xcsf, const struct Set *set)
157{
158 struct Cl *winner = NULL;
159 while (winner == NULL) {
160 const struct Clist *iter = set->list;
161 while (iter != NULL) {
162 if ((rand_uniform(0, 1) < xcsf->ea->select_size) &&
163 (winner == NULL || iter->cl->fit > winner->fit)) {
164 winner = iter->cl;
165 }
166 iter = iter->next;
167 }
168 }
169 return winner;
170}
171
179static void
180ea_select(const struct XCSF *xcsf, const struct Set *set, struct Cl **c1p,
181 struct Cl **c2p)
182{
183 if (xcsf->ea->select_type == EA_SELECT_ROULETTE) {
184 const double fit_sum = clset_total_fit(set);
185 *c1p = ea_select_rw(xcsf, set, fit_sum);
186 *c2p = ea_select_rw(xcsf, set, fit_sum);
187 } else {
188 *c1p = ea_select_tournament(xcsf, set);
189 *c2p = ea_select_tournament(xcsf, set);
190 }
191}
192
198void
199ea(struct XCSF *xcsf, const struct Set *set)
200{
201 ++(xcsf->time);
202 if (set->size == 0 || xcsf->time - clset_mean_time(set) < xcsf->ea->theta) {
203 return; // not yet time to run the EA
204 }
205 clset_set_times(xcsf, set);
206 // select parents
207 struct Cl *c1p = NULL;
208 struct Cl *c2p = NULL;
209 ea_select(xcsf, set, &c1p, &c2p);
210 // create offspring
211 for (int i = 0; i * 2 < xcsf->ea->lambda; ++i) {
212 // create copies of parents
213 struct Cl *c1 = malloc(sizeof(struct Cl));
214 struct Cl *c2 = malloc(sizeof(struct Cl));
215 cl_init(xcsf, c1, c1p->size, c1p->time);
216 cl_init(xcsf, c2, c2p->size, c2p->time);
217 cl_copy(xcsf, c1, c1p);
218 cl_copy(xcsf, c2, c2p);
219 // apply evolutionary operators to offspring
220 const bool cmod = cl_crossover(xcsf, c1, c2);
221 const bool m1mod = cl_mutate(xcsf, c1);
222 const bool m2mod = cl_mutate(xcsf, c2);
223 // initialise parameters
224 ea_init_offspring(xcsf, c1p, c2p, c1, c2, cmod);
225 // add to population
226 ea_add(xcsf, set, c1p, c2p, c1, cmod, m1mod);
227 ea_add(xcsf, set, c2p, c1p, c2, cmod, m2mod);
228 }
230}
231
236void
249
255char *
257{
258 cJSON *json = cJSON_CreateObject();
259 cJSON_AddStringToObject(json, "select_type",
260 ea_type_as_string(xcsf->ea->select_type));
261 if (xcsf->ea->select_type == EA_SELECT_TOURNAMENT) {
262 cJSON_AddNumberToObject(json, "select_size", xcsf->ea->select_size);
263 }
264 cJSON_AddNumberToObject(json, "theta_ea", xcsf->ea->theta);
265 cJSON_AddNumberToObject(json, "lambda", xcsf->ea->lambda);
266 cJSON_AddNumberToObject(json, "p_crossover", xcsf->ea->p_crossover);
267 cJSON_AddNumberToObject(json, "err_reduc", xcsf->ea->err_reduc);
268 cJSON_AddNumberToObject(json, "fit_reduc", xcsf->ea->fit_reduc);
269 cJSON_AddBoolToObject(json, "subsumption", xcsf->ea->subsumption);
270 cJSON_AddBoolToObject(json, "pred_reset", xcsf->ea->pred_reset);
271 char *string = cJSON_Print(json);
272 cJSON_Delete(json);
273 return string;
274}
275
281void
282ea_param_json_import(struct XCSF *xcsf, cJSON *json)
283{
284 for (cJSON *iter = json; iter != NULL; iter = iter->next) {
285 if (strncmp(iter->string, "select_type\0", 12) == 0 &&
286 cJSON_IsString(iter)) {
287 if (ea_param_set_type_string(xcsf, iter->valuestring) ==
289 printf("Invalid EA SELECT_TYPE: %s\n", iter->valuestring);
290 printf("Options: {%s}\n", EA_SELECT_OPTIONS);
291 exit(EXIT_FAILURE);
292 }
293 } else if (strncmp(iter->string, "select_size\0", 12) == 0 &&
294 cJSON_IsNumber(iter)) {
295 catch_error(ea_param_set_select_size(xcsf, iter->valuedouble));
296 } else if (strncmp(iter->string, "theta_ea\0", 9) == 0 &&
297 cJSON_IsNumber(iter)) {
298 catch_error(ea_param_set_theta(xcsf, iter->valuedouble));
299 } else if (strncmp(iter->string, "lambda\0", 7) == 0 &&
300 cJSON_IsNumber(iter)) {
301 catch_error(ea_param_set_lambda(xcsf, iter->valueint));
302 } else if (strncmp(iter->string, "p_crossover\0", 12) == 0 &&
303 cJSON_IsNumber(iter)) {
304 catch_error(ea_param_set_p_crossover(xcsf, iter->valuedouble));
305 } else if (strncmp(iter->string, "err_reduc\0", 10) == 0 &&
306 cJSON_IsNumber(iter)) {
307 catch_error(ea_param_set_err_reduc(xcsf, iter->valuedouble));
308 } else if (strncmp(iter->string, "fit_reduc\0", 10) == 0 &&
309 cJSON_IsNumber(iter)) {
310 catch_error(ea_param_set_fit_reduc(xcsf, iter->valuedouble));
311 } else if (strncmp(iter->string, "subsumption\0", 12) == 0 &&
312 cJSON_IsBool(iter)) {
313 const bool sub = true ? iter->type == cJSON_True : false;
315 } else if (strncmp(iter->string, "pred_reset\0", 11) == 0 &&
316 cJSON_IsBool(iter)) {
317 const bool reset = true ? iter->type == cJSON_True : false;
319 } else {
320 printf("Error importing EA parameter %s\n", iter->string);
321 exit(EXIT_FAILURE);
322 }
323 }
324}
325
332size_t
333ea_param_save(const struct XCSF *xcsf, FILE *fp)
334{
335 size_t s = 0;
336 s += fwrite(&xcsf->ea->select_type, sizeof(int), 1, fp);
337 s += fwrite(&xcsf->ea->select_size, sizeof(double), 1, fp);
338 s += fwrite(&xcsf->ea->theta, sizeof(double), 1, fp);
339 s += fwrite(&xcsf->ea->lambda, sizeof(int), 1, fp);
340 s += fwrite(&xcsf->ea->p_crossover, sizeof(double), 1, fp);
341 s += fwrite(&xcsf->ea->err_reduc, sizeof(double), 1, fp);
342 s += fwrite(&xcsf->ea->fit_reduc, sizeof(double), 1, fp);
343 s += fwrite(&xcsf->ea->subsumption, sizeof(bool), 1, fp);
344 s += fwrite(&xcsf->ea->pred_reset, sizeof(bool), 1, fp);
345 return s;
346}
347
354size_t
355ea_param_load(struct XCSF *xcsf, FILE *fp)
356{
357 size_t s = 0;
358 s += fread(&xcsf->ea->select_type, sizeof(int), 1, fp);
359 s += fread(&xcsf->ea->select_size, sizeof(double), 1, fp);
360 s += fread(&xcsf->ea->theta, sizeof(double), 1, fp);
361 s += fread(&xcsf->ea->lambda, sizeof(int), 1, fp);
362 s += fread(&xcsf->ea->p_crossover, sizeof(double), 1, fp);
363 s += fread(&xcsf->ea->err_reduc, sizeof(double), 1, fp);
364 s += fread(&xcsf->ea->fit_reduc, sizeof(double), 1, fp);
365 s += fread(&xcsf->ea->subsumption, sizeof(bool), 1, fp);
366 s += fread(&xcsf->ea->pred_reset, sizeof(bool), 1, fp);
367 return s;
368}
369
375const char *
376ea_type_as_string(const int type)
377{
378 if (type == EA_SELECT_ROULETTE) {
379 return EA_STRING_ROULETTE;
380 }
381 if (type == EA_SELECT_TOURNAMENT) {
383 }
384 printf("ea_type_as_string(): invalid type: %d\n", type);
385 exit(EXIT_FAILURE);
386}
387
393int
394ea_type_as_int(const char *type)
395{
396 if (strncmp(type, EA_STRING_ROULETTE, 9) == 0) {
397 return EA_SELECT_ROULETTE;
398 }
399 if (strncmp(type, EA_STRING_TOURNAMENT, 11) == 0) {
401 }
402 return EA_SELECT_INVALID;
403}
404
405/* parameter setters */
406
407const char *
408ea_param_set_select_size(struct XCSF *xcsf, const double a)
409{
410 if (a < 0 || a > 1) {
411 return "Invalid EA SELECT_SIZE. Range: [0,1]";
412 }
413 xcsf->ea->select_size = a;
414 return NULL;
415}
416
417const char *
418ea_param_set_theta(struct XCSF *xcsf, const double a)
419{
420 if (a < 0) {
421 return "EA THETA must be >= 0";
422 }
423 xcsf->ea->theta = a;
424 return NULL;
425}
426
427const char *
428ea_param_set_p_crossover(struct XCSF *xcsf, const double a)
429{
430 if (a < 0 || a > 1) {
431 return "Invalid EA P_CROSSOVER. Range: [0,1]";
432 }
433 xcsf->ea->p_crossover = a;
434 return NULL;
435}
436
437const char *
438ea_param_set_lambda(struct XCSF *xcsf, const int a)
439{
440 if (a < 2) {
441 return "EA LAMBDA must be >= 2";
442 }
443 xcsf->ea->lambda = a;
444 return NULL;
445}
446
447const char *
448ea_param_set_err_reduc(struct XCSF *xcsf, const double a)
449{
450 if (a < 0 || a > 1) {
451 return "Invalid EA ERR_REDUC. Range: [0,1]";
452 }
453 xcsf->ea->err_reduc = a;
454 return NULL;
455}
456
457const char *
458ea_param_set_fit_reduc(struct XCSF *xcsf, const double a)
459{
460 if (a < 0 || a > 1) {
461 return "Invalid EA FIT_REDUC. Range: [0,1]";
462 }
463 xcsf->ea->fit_reduc = a;
464 return NULL;
465}
466
467const char *
468ea_param_set_subsumption(struct XCSF *xcsf, const bool a)
469{
470 xcsf->ea->subsumption = a;
471 return NULL;
472}
473
474const char *
475ea_param_set_pred_reset(struct XCSF *xcsf, const bool a)
476{
477 xcsf->ea->pred_reset = a;
478 return NULL;
479}
480
481int
482ea_param_set_select_type(struct XCSF *xcsf, const int a)
483{
484 if (a == EA_SELECT_ROULETTE || a == EA_SELECT_TOURNAMENT) {
485 xcsf->ea->select_type = a;
486 return a;
487 }
488 return EA_SELECT_INVALID;
489}
490
491int
492ea_param_set_type_string(struct XCSF *xcsf, const char *a)
493{
494 const int type = ea_type_as_int(a);
495 if (type != EA_SELECT_INVALID) {
496 xcsf->ea->select_type = type;
497 return type;
498 }
499 return EA_SELECT_INVALID;
500}
void cl_init(const struct XCSF *xcsf, struct Cl *c, const double size, const int time)
Initialises a new classifier - but not condition, action, prediction.
Definition cl.c:40
bool cl_general(const struct XCSF *xcsf, const struct Cl *c1, const struct Cl *c2)
Returns whether classifier c1 is more general than c2.
Definition cl.c:347
bool cl_mutate(const struct XCSF *xcsf, const struct Cl *c)
Performs classifier mutation.
Definition cl.c:362
void cl_copy(const struct XCSF *xcsf, struct Cl *dest, const struct Cl *src)
Copies condition, action, and prediction structures.
Definition cl.c:63
bool cl_crossover(const struct XCSF *xcsf, const struct Cl *c1, const struct Cl *c2)
Performs classifier crossover.
Definition cl.c:381
void cl_free(const struct XCSF *xcsf, struct Cl *c)
Frees the memory used by a classifier.
Definition cl.c:223
bool cl_subsumer(const struct XCSF *xcsf, const struct Cl *c)
Returns whether a classifier is a potential subsumer.
Definition cl.c:331
Functions operating on classifiers.
double clset_total_fit(const struct Set *set)
Calculates the total fitness of classifiers in the set.
Definition clset.c:545
double clset_mean_time(const struct Set *set)
Calculates the mean time stamp of classifiers in the set.
Definition clset.c:562
void clset_pset_enforce_limit(struct XCSF *xcsf)
Enforces the maximum population size limit.
Definition clset.c:340
void clset_add(struct Set *set, struct Cl *c)
Adds a classifier to the set.
Definition clset.c:423
void clset_set_times(const struct XCSF *xcsf, const struct Set *set)
Sets the time stamps for classifiers in the set.
Definition clset.c:530
Functions operating on sets of classifiers.
char * ea_param_json_export(const struct XCSF *xcsf)
Returns a json formatted string representation of the EA parameters.
Definition ea.c:256
static struct Cl * ea_select_tournament(const struct XCSF *xcsf, const struct Set *set)
Selects a classifier from the set via tournament.
Definition ea.c:156
void ea(struct XCSF *xcsf, const struct Set *set)
Executes the evolutionary algorithm (EA).
Definition ea.c:199
static void ea_add(struct XCSF *xcsf, const struct Set *set, struct Cl *c1p, struct Cl *c2p, struct Cl *c1, const bool cmod, const bool mmod)
Adds offspring to the population.
Definition ea.c:113
const char * ea_param_set_fit_reduc(struct XCSF *xcsf, const double a)
Definition ea.c:458
void ea_param_defaults(struct XCSF *xcsf)
Initialises default evolutionary algorithm parameters.
Definition ea.c:237
const char * ea_param_set_subsumption(struct XCSF *xcsf, const bool a)
Definition ea.c:468
const char * ea_param_set_p_crossover(struct XCSF *xcsf, const double a)
Definition ea.c:428
const char * ea_param_set_pred_reset(struct XCSF *xcsf, const bool a)
Definition ea.c:475
static void ea_select(const struct XCSF *xcsf, const struct Set *set, struct Cl **c1p, struct Cl **c2p)
Selects two parents.
Definition ea.c:180
size_t ea_param_load(struct XCSF *xcsf, FILE *fp)
Loads evolutionary algorithm parameters.
Definition ea.c:355
const char * ea_param_set_theta(struct XCSF *xcsf, const double a)
Definition ea.c:418
int ea_type_as_int(const char *type)
Returns the integer representation of an EA selection type.
Definition ea.c:394
static void ea_init_offspring(const struct XCSF *xcsf, const struct Cl *c1p, const struct Cl *c2p, struct Cl *c1, struct Cl *c2, const bool cmod)
Initialises offspring error and fitness.
Definition ea.c:39
int ea_param_set_type_string(struct XCSF *xcsf, const char *a)
Definition ea.c:492
static void ea_subsume(struct XCSF *xcsf, struct Cl *c, struct Cl *c1p, struct Cl *c2p, const struct Set *set)
Performs evolutionary algorithm subsumption.
Definition ea.c:67
size_t ea_param_save(const struct XCSF *xcsf, FILE *fp)
Saves evolutionary algorithm parameters.
Definition ea.c:333
const char * ea_param_set_select_size(struct XCSF *xcsf, const double a)
Definition ea.c:408
const char * ea_param_set_err_reduc(struct XCSF *xcsf, const double a)
Definition ea.c:448
int ea_param_set_select_type(struct XCSF *xcsf, const int a)
Definition ea.c:482
static struct Cl * ea_select_rw(const struct XCSF *xcsf, const struct Set *set, const double fit_sum)
Selects a classifier from the set via roulette wheel.
Definition ea.c:135
const char * ea_param_set_lambda(struct XCSF *xcsf, const int a)
Definition ea.c:438
void ea_param_json_import(struct XCSF *xcsf, cJSON *json)
Sets the EA parameters from a cJSON object.
Definition ea.c:282
const char * ea_type_as_string(const int type)
Returns a string representation of an EA select type from an integer.
Definition ea.c:376
Evolutionary algorithm functions.
#define EA_SELECT_TOURNAMENT
Tournament parental selection.
Definition ea.h:30
#define EA_STRING_TOURNAMENT
Tournament.
Definition ea.h:33
#define EA_SELECT_OPTIONS
Valid EA types.
Definition ea.h:35
#define EA_STRING_ROULETTE
Roulette.
Definition ea.h:32
#define EA_SELECT_INVALID
Error code for invalid selection.
Definition ea.h:28
#define EA_SELECT_ROULETTE
Roulette wheel parental selection.
Definition ea.h:29
Classifier data structure.
Definition xcsf.h:45
int time
Time EA last executed in a participating set.
Definition xcsf.h:57
double err
Error.
Definition xcsf.h:52
int num
Numerosity.
Definition xcsf.h:54
double size
Average participated set size.
Definition xcsf.h:56
double fit
Fitness.
Definition xcsf.h:53
Classifier linked list.
Definition xcsf.h:68
struct Clist * next
Pointer to the next list element.
Definition xcsf.h:70
struct Cl * cl
Pointer to classifier data structure.
Definition xcsf.h:69
Classifier set.
Definition xcsf.h:76
int size
Number of macro-classifiers.
Definition xcsf.h:78
struct Clist * list
Linked list of classifiers.
Definition xcsf.h:77
XCSF data structure.
Definition xcsf.h:85
int rand_uniform_int(const int min, const int max)
Returns a uniform random integer [min,max] not inclusive of max.
Definition utils.c:74
double rand_uniform(const double min, const double max)
Returns a uniform random float [min,max].
Definition utils.c:62
Utility functions for random number handling, etc.
static void catch_error(const char *ret)
Catches parameter value errors.
Definition utils.h:134