XCSF 1.5.1
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 double
156p_num_tau(const int num, const double tau)
157{
158 return 1 - pow(1 - tau, (double) num);
159}
160
169static struct Cl *
170ea_select_tournament(const struct XCSF *xcsf, const struct Set *set)
171{
172 const double tau = xcsf->ea->select_size;
173 struct Cl *clb = NULL;
174 while (clb == NULL) {
175 double maxf = 0;
176 const struct Clist *iter = set->list;
177 while (iter != NULL) {
178 const double f = iter->cl->fit / iter->cl->num;
179 const int num = iter->cl->num;
180 if ((clb == NULL || f > maxf) &&
181 rand_uniform(0, 1) < p_num_tau(num, tau)) {
182 clb = iter->cl;
183 maxf = f;
184 }
185 iter = iter->next;
186 }
187 }
188 return clb;
189}
190
198static void
199ea_select(const struct XCSF *xcsf, const struct Set *set, struct Cl **c1p,
200 struct Cl **c2p)
201{
202 if (xcsf->ea->select_type == EA_SELECT_ROULETTE) {
203 const double fit_sum = clset_total_fit(set);
204 *c1p = ea_select_rw(xcsf, set, fit_sum);
205 *c2p = ea_select_rw(xcsf, set, fit_sum);
206 } else {
207 *c1p = ea_select_tournament(xcsf, set);
208 *c2p = ea_select_tournament(xcsf, set);
209 }
210}
211
217void
218ea(struct XCSF *xcsf, const struct Set *set)
219{
220 ++(xcsf->time);
221 if (set->size == 0 || xcsf->time - clset_mean_time(set) < xcsf->ea->theta) {
222 return; // not yet time to run the EA
223 }
224 clset_set_times(xcsf, set);
225 // select parents
226 struct Cl *c1p = NULL;
227 struct Cl *c2p = NULL;
228 ea_select(xcsf, set, &c1p, &c2p);
229 // create offspring
230 for (int i = 0; i * 2 < xcsf->ea->lambda; ++i) {
231 // create copies of parents
232 struct Cl *c1 = malloc(sizeof(struct Cl));
233 struct Cl *c2 = malloc(sizeof(struct Cl));
234 cl_init(xcsf, c1, c1p->size, c1p->time);
235 cl_init(xcsf, c2, c2p->size, c2p->time);
236 cl_copy(xcsf, c1, c1p);
237 cl_copy(xcsf, c2, c2p);
238 // apply evolutionary operators to offspring
239 const bool cmod = cl_crossover(xcsf, c1, c2);
240 const bool m1mod = cl_mutate(xcsf, c1);
241 const bool m2mod = cl_mutate(xcsf, c2);
242 // initialise parameters
243 ea_init_offspring(xcsf, c1p, c2p, c1, c2, cmod);
244 // add to population
245 ea_add(xcsf, set, c1p, c2p, c1, cmod, m1mod);
246 ea_add(xcsf, set, c2p, c1p, c2, cmod, m2mod);
247 }
249}
250
255void
268
274char *
276{
277 cJSON *json = cJSON_CreateObject();
278 cJSON_AddStringToObject(json, "select_type",
279 ea_type_as_string(xcsf->ea->select_type));
280 if (xcsf->ea->select_type == EA_SELECT_TOURNAMENT) {
281 cJSON_AddNumberToObject(json, "select_size", xcsf->ea->select_size);
282 }
283 cJSON_AddNumberToObject(json, "theta_ea", xcsf->ea->theta);
284 cJSON_AddNumberToObject(json, "lambda", xcsf->ea->lambda);
285 cJSON_AddNumberToObject(json, "p_crossover", xcsf->ea->p_crossover);
286 cJSON_AddNumberToObject(json, "err_reduc", xcsf->ea->err_reduc);
287 cJSON_AddNumberToObject(json, "fit_reduc", xcsf->ea->fit_reduc);
288 cJSON_AddBoolToObject(json, "subsumption", xcsf->ea->subsumption);
289 cJSON_AddBoolToObject(json, "pred_reset", xcsf->ea->pred_reset);
290 char *string = cJSON_Print(json);
291 cJSON_Delete(json);
292 return string;
293}
294
300void
301ea_param_json_import(struct XCSF *xcsf, cJSON *json)
302{
303 for (cJSON *iter = json; iter != NULL; iter = iter->next) {
304 if (strncmp(iter->string, "select_type\0", 12) == 0 &&
305 cJSON_IsString(iter)) {
306 if (ea_param_set_type_string(xcsf, iter->valuestring) ==
308 printf("Invalid EA SELECT_TYPE: %s\n", iter->valuestring);
309 printf("Options: {%s}\n", EA_SELECT_OPTIONS);
310 exit(EXIT_FAILURE);
311 }
312 } else if (strncmp(iter->string, "select_size\0", 12) == 0 &&
313 cJSON_IsNumber(iter)) {
314 catch_error(ea_param_set_select_size(xcsf, iter->valuedouble));
315 } else if (strncmp(iter->string, "theta_ea\0", 9) == 0 &&
316 cJSON_IsNumber(iter)) {
317 catch_error(ea_param_set_theta(xcsf, iter->valuedouble));
318 } else if (strncmp(iter->string, "lambda\0", 7) == 0 &&
319 cJSON_IsNumber(iter)) {
320 catch_error(ea_param_set_lambda(xcsf, iter->valueint));
321 } else if (strncmp(iter->string, "p_crossover\0", 12) == 0 &&
322 cJSON_IsNumber(iter)) {
323 catch_error(ea_param_set_p_crossover(xcsf, iter->valuedouble));
324 } else if (strncmp(iter->string, "err_reduc\0", 10) == 0 &&
325 cJSON_IsNumber(iter)) {
326 catch_error(ea_param_set_err_reduc(xcsf, iter->valuedouble));
327 } else if (strncmp(iter->string, "fit_reduc\0", 10) == 0 &&
328 cJSON_IsNumber(iter)) {
329 catch_error(ea_param_set_fit_reduc(xcsf, iter->valuedouble));
330 } else if (strncmp(iter->string, "subsumption\0", 12) == 0 &&
331 cJSON_IsBool(iter)) {
332 const bool sub = true ? iter->type == cJSON_True : false;
334 } else if (strncmp(iter->string, "pred_reset\0", 11) == 0 &&
335 cJSON_IsBool(iter)) {
336 const bool reset = true ? iter->type == cJSON_True : false;
338 } else {
339 printf("Error importing EA parameter %s\n", iter->string);
340 exit(EXIT_FAILURE);
341 }
342 }
343}
344
351size_t
352ea_param_save(const struct XCSF *xcsf, FILE *fp)
353{
354 size_t s = 0;
355 s += fwrite(&xcsf->ea->select_type, sizeof(int), 1, fp);
356 s += fwrite(&xcsf->ea->select_size, sizeof(double), 1, fp);
357 s += fwrite(&xcsf->ea->theta, sizeof(double), 1, fp);
358 s += fwrite(&xcsf->ea->lambda, sizeof(int), 1, fp);
359 s += fwrite(&xcsf->ea->p_crossover, sizeof(double), 1, fp);
360 s += fwrite(&xcsf->ea->err_reduc, sizeof(double), 1, fp);
361 s += fwrite(&xcsf->ea->fit_reduc, sizeof(double), 1, fp);
362 s += fwrite(&xcsf->ea->subsumption, sizeof(bool), 1, fp);
363 s += fwrite(&xcsf->ea->pred_reset, sizeof(bool), 1, fp);
364 return s;
365}
366
373size_t
374ea_param_load(struct XCSF *xcsf, FILE *fp)
375{
376 size_t s = 0;
377 s += fread(&xcsf->ea->select_type, sizeof(int), 1, fp);
378 s += fread(&xcsf->ea->select_size, sizeof(double), 1, fp);
379 s += fread(&xcsf->ea->theta, sizeof(double), 1, fp);
380 s += fread(&xcsf->ea->lambda, sizeof(int), 1, fp);
381 s += fread(&xcsf->ea->p_crossover, sizeof(double), 1, fp);
382 s += fread(&xcsf->ea->err_reduc, sizeof(double), 1, fp);
383 s += fread(&xcsf->ea->fit_reduc, sizeof(double), 1, fp);
384 s += fread(&xcsf->ea->subsumption, sizeof(bool), 1, fp);
385 s += fread(&xcsf->ea->pred_reset, sizeof(bool), 1, fp);
386 return s;
387}
388
394const char *
395ea_type_as_string(const int type)
396{
397 if (type == EA_SELECT_ROULETTE) {
398 return EA_STRING_ROULETTE;
399 }
400 if (type == EA_SELECT_TOURNAMENT) {
402 }
403 printf("ea_type_as_string(): invalid type: %d\n", type);
404 exit(EXIT_FAILURE);
405}
406
412int
413ea_type_as_int(const char *type)
414{
415 if (strncmp(type, EA_STRING_ROULETTE, 9) == 0) {
416 return EA_SELECT_ROULETTE;
417 }
418 if (strncmp(type, EA_STRING_TOURNAMENT, 11) == 0) {
420 }
421 return EA_SELECT_INVALID;
422}
423
424/* parameter setters */
425
426const char *
427ea_param_set_select_size(struct XCSF *xcsf, const double a)
428{
429 if (a < 0 || a > 1) {
430 return "Invalid EA SELECT_SIZE. Range: [0,1]";
431 }
432 xcsf->ea->select_size = a;
433 return NULL;
434}
435
436const char *
437ea_param_set_theta(struct XCSF *xcsf, const double a)
438{
439 if (a < 0) {
440 return "EA THETA must be >= 0";
441 }
442 xcsf->ea->theta = a;
443 return NULL;
444}
445
446const char *
447ea_param_set_p_crossover(struct XCSF *xcsf, const double a)
448{
449 if (a < 0 || a > 1) {
450 return "Invalid EA P_CROSSOVER. Range: [0,1]";
451 }
452 xcsf->ea->p_crossover = a;
453 return NULL;
454}
455
456const char *
457ea_param_set_lambda(struct XCSF *xcsf, const int a)
458{
459 if (a < 2) {
460 return "EA LAMBDA must be >= 2";
461 }
462 xcsf->ea->lambda = a;
463 return NULL;
464}
465
466const char *
467ea_param_set_err_reduc(struct XCSF *xcsf, const double a)
468{
469 if (a < 0 || a > 1) {
470 return "Invalid EA ERR_REDUC. Range: [0,1]";
471 }
472 xcsf->ea->err_reduc = a;
473 return NULL;
474}
475
476const char *
477ea_param_set_fit_reduc(struct XCSF *xcsf, const double a)
478{
479 if (a < 0 || a > 1) {
480 return "Invalid EA FIT_REDUC. Range: [0,1]";
481 }
482 xcsf->ea->fit_reduc = a;
483 return NULL;
484}
485
486const char *
487ea_param_set_subsumption(struct XCSF *xcsf, const bool a)
488{
489 xcsf->ea->subsumption = a;
490 return NULL;
491}
492
493const char *
494ea_param_set_pred_reset(struct XCSF *xcsf, const bool a)
495{
496 xcsf->ea->pred_reset = a;
497 return NULL;
498}
499
500int
501ea_param_set_select_type(struct XCSF *xcsf, const int a)
502{
503 if (a == EA_SELECT_ROULETTE || a == EA_SELECT_TOURNAMENT) {
504 xcsf->ea->select_type = a;
505 return a;
506 }
507 return EA_SELECT_INVALID;
508}
509
510int
511ea_param_set_type_string(struct XCSF *xcsf, const char *a)
512{
513 const int type = ea_type_as_int(a);
514 if (type != EA_SELECT_INVALID) {
515 xcsf->ea->select_type = type;
516 return type;
517 }
518 return EA_SELECT_INVALID;
519}
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:275
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:170
void ea(struct XCSF *xcsf, const struct Set *set)
Executes the evolutionary algorithm (EA).
Definition ea.c:218
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:477
void ea_param_defaults(struct XCSF *xcsf)
Initialises default evolutionary algorithm parameters.
Definition ea.c:256
const char * ea_param_set_subsumption(struct XCSF *xcsf, const bool a)
Definition ea.c:487
const char * ea_param_set_p_crossover(struct XCSF *xcsf, const double a)
Definition ea.c:447
const char * ea_param_set_pred_reset(struct XCSF *xcsf, const bool a)
Definition ea.c:494
static void ea_select(const struct XCSF *xcsf, const struct Set *set, struct Cl **c1p, struct Cl **c2p)
Selects two parents.
Definition ea.c:199
static double p_num_tau(const int num, const double tau)
Probability a classifier with numerosity num is selected.
Definition ea.c:156
size_t ea_param_load(struct XCSF *xcsf, FILE *fp)
Loads evolutionary algorithm parameters.
Definition ea.c:374
const char * ea_param_set_theta(struct XCSF *xcsf, const double a)
Definition ea.c:437
int ea_type_as_int(const char *type)
Returns the integer representation of an EA selection type.
Definition ea.c:413
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:511
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:352
const char * ea_param_set_select_size(struct XCSF *xcsf, const double a)
Definition ea.c:427
const char * ea_param_set_err_reduc(struct XCSF *xcsf, const double a)
Definition ea.c:467
int ea_param_set_select_type(struct XCSF *xcsf, const int a)
Definition ea.c:501
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:457
void ea_param_json_import(struct XCSF *xcsf, cJSON *json)
Sets the EA parameters from a cJSON object.
Definition ea.c:301
const char * ea_type_as_string(const int type)
Returns a string representation of an EA select type from an integer.
Definition ea.c:395
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