XCSF  1.4.7
XCSF learning classifier system
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 
38 static void
39 ea_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 
66 static void
67 ea_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 
112 static void
113 ea_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 
134 static struct Cl *
135 ea_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 
155 static struct Cl *
156 ea_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 
179 static void
180 ea_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 
198 void
199 ea(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 
236 void
238 {
248 }
249 
255 char *
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 
281 void
282 ea_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 
332 size_t
333 ea_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 
354 size_t
355 ea_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 
375 const char *
376 ea_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) {
382  return EA_STRING_TOURNAMENT;
383  }
384  printf("ea_type_as_string(): invalid type: %d\n", type);
385  exit(EXIT_FAILURE);
386 }
387 
393 int
394 ea_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) {
400  return EA_SELECT_TOURNAMENT;
401  }
402  return EA_SELECT_INVALID;
403 }
404 
405 /* parameter setters */
406 
407 const char *
408 ea_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 
417 const char *
418 ea_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 
427 const char *
428 ea_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 
437 const char *
438 ea_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 
447 const char *
448 ea_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 
457 const char *
458 ea_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 
467 const char *
468 ea_param_set_subsumption(struct XCSF *xcsf, const bool a)
469 {
470  xcsf->ea->subsumption = a;
471  return NULL;
472 }
473 
474 const char *
475 ea_param_set_pred_reset(struct XCSF *xcsf, const bool a)
476 {
477  xcsf->ea->pred_reset = a;
478  return NULL;
479 }
480 
481 int
482 ea_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 
491 int
492 ea_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.
const char * ea_param_set_subsumption(struct XCSF *xcsf, const bool a)
Definition: ea.c:468
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
void ea_param_defaults(struct XCSF *xcsf)
Initialises default evolutionary algorithm parameters.
Definition: ea.c:237
const char * ea_param_set_lambda(struct XCSF *xcsf, const int a)
Definition: ea.c:438
const char * ea_param_set_theta(struct XCSF *xcsf, const double a)
Definition: ea.c:418
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
const char * ea_param_set_err_reduc(struct XCSF *xcsf, const double a)
Definition: ea.c:448
char * ea_param_json_export(const struct XCSF *xcsf)
Returns a json formatted string representation of the EA parameters.
Definition: ea.c:256
const char * ea_param_set_fit_reduc(struct XCSF *xcsf, const double a)
Definition: ea.c:458
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
const char * ea_param_set_pred_reset(struct XCSF *xcsf, const bool a)
Definition: ea.c:475
size_t ea_param_load(struct XCSF *xcsf, FILE *fp)
Loads evolutionary algorithm parameters.
Definition: ea.c:355
int ea_type_as_int(const char *type)
Returns the integer representation of an EA selection type.
Definition: ea.c:394
const char * ea_param_set_p_crossover(struct XCSF *xcsf, const double a)
Definition: ea.c:428
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
int ea_param_set_select_type(struct XCSF *xcsf, const int a)
Definition: ea.c:482
void ea_param_json_import(struct XCSF *xcsf, cJSON *json)
Sets the EA parameters from a cJSON object.
Definition: ea.c:282
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_select_size(struct XCSF *xcsf, const double a)
Definition: ea.c:408
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
Definition: __init__.py:1
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