XCSF  1.4.7
XCSF learning classifier system
cond_rectangle.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 "cond_rectangle.h"
25 #include "ea.h"
26 #include "sam.h"
27 #include "utils.h"
28 
29 #define N_MU (1)
30 
34 static const int MU_TYPE[N_MU] = { SAM_LOG_NORMAL };
35 
41 void
42 cond_rectangle_init(const struct XCSF *xcsf, struct Cl *c)
43 {
44  struct CondRectangle *new = malloc(sizeof(struct CondRectangle));
45  new->b1 = malloc(sizeof(double) * xcsf->x_dim);
46  new->b2 = malloc(sizeof(double) * xcsf->x_dim);
47  const double spread_max = fabs(xcsf->cond->max - xcsf->cond->min);
48  for (int i = 0; i < xcsf->x_dim; ++i) {
49  new->b1[i] = rand_uniform(xcsf->cond->min, xcsf->cond->max);
50  new->b2[i] = rand_uniform(xcsf->cond->min, xcsf->cond->max);
51  }
52  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
53  // csr: b1 = center, b2 = spread
54  for (int i = 0; i < xcsf->x_dim; ++i) {
55  new->b2[i] = rand_uniform(xcsf->cond->spread_min, spread_max);
56  }
57  }
58  new->mu = malloc(sizeof(double) * N_MU);
59  sam_init(new->mu, N_MU, MU_TYPE);
60  c->cond = new;
61 }
62 
68 void
69 cond_rectangle_free(const struct XCSF *xcsf, const struct Cl *c)
70 {
71  (void) xcsf;
72  const struct CondRectangle *cond = c->cond;
73  free(cond->b1);
74  free(cond->b2);
75  free(cond->mu);
76  free(c->cond);
77 }
78 
85 void
86 cond_rectangle_copy(const struct XCSF *xcsf, struct Cl *dest,
87  const struct Cl *src)
88 {
89  struct CondRectangle *new = malloc(sizeof(struct CondRectangle));
90  const struct CondRectangle *src_cond = src->cond;
91  new->b1 = malloc(sizeof(double) * xcsf->x_dim);
92  new->b2 = malloc(sizeof(double) * xcsf->x_dim);
93  new->mu = malloc(sizeof(double) * N_MU);
94  memcpy(new->b1, src_cond->b1, sizeof(double) * xcsf->x_dim);
95  memcpy(new->b2, src_cond->b2, sizeof(double) * xcsf->x_dim);
96  memcpy(new->mu, src_cond->mu, sizeof(double) * N_MU);
97  dest->cond = new;
98 }
99 
106 void
107 cond_rectangle_cover(const struct XCSF *xcsf, const struct Cl *c,
108  const double *x)
109 {
110  const struct CondRectangle *cond = c->cond;
111  const double spread_max = fabs(xcsf->cond->max - xcsf->cond->min);
112  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
113  for (int i = 0; i < xcsf->x_dim; ++i) {
114  cond->b1[i] = x[i];
115  cond->b2[i] = rand_uniform(xcsf->cond->spread_min, spread_max);
116  }
117  } else {
118  for (int i = 0; i < xcsf->x_dim; ++i) {
119  const double r1 = rand_uniform(xcsf->cond->spread_min, spread_max);
120  const double r2 = rand_uniform(xcsf->cond->spread_min, spread_max);
121  cond->b1[i] = x[i] - (r1 * 0.5);
122  cond->b2[i] = x[i] + (r2 * 0.5);
123  }
124  }
125 }
126 
134 void
135 cond_rectangle_update(const struct XCSF *xcsf, const struct Cl *c,
136  const double *x, const double *y)
137 {
138  (void) y;
139  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR &&
140  xcsf->cond->eta > 0) {
141  const struct CondRectangle *cond = c->cond;
142  for (int i = 0; i < xcsf->x_dim; ++i) {
143  cond->b1[i] += xcsf->cond->eta * (x[i] - cond->b1[i]);
144  }
145  }
146 }
147 
155 bool
156 cond_rectangle_match(const struct XCSF *xcsf, const struct Cl *c,
157  const double *x)
158 {
159  const struct CondRectangle *cond = c->cond;
160  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
161  for (int i = 0; i < xcsf->x_dim; ++i) {
162  const double lb = cond->b1[i] - cond->b2[i];
163  const double ub = cond->b1[i] + cond->b2[i];
164  if (x[i] < lb || x[i] > ub) {
165  return false;
166  }
167  }
168  } else { // ubr
169  for (int i = 0; i < xcsf->x_dim; ++i) {
170  const double lb = fmin(cond->b1[i], cond->b2[i]);
171  const double ub = fmax(cond->b1[i], cond->b2[i]);
172  if (x[i] < lb || x[i] > ub) {
173  return false;
174  }
175  }
176  }
177  return true;
178 }
179 
187 bool
188 cond_rectangle_crossover(const struct XCSF *xcsf, const struct Cl *c1,
189  const struct Cl *c2)
190 {
191  const struct CondRectangle *cond1 = c1->cond;
192  const struct CondRectangle *cond2 = c2->cond;
193  bool changed = false;
194  if (rand_uniform(0, 1) < xcsf->ea->p_crossover) {
195  for (int i = 0; i < xcsf->x_dim; ++i) {
196  if (rand_uniform(0, 1) < 0.5) {
197  const double tmp = cond1->b1[i];
198  cond1->b1[i] = cond2->b1[i];
199  cond2->b1[i] = tmp;
200  changed = true;
201  }
202  if (rand_uniform(0, 1) < 0.5) {
203  const double tmp = cond1->b2[i];
204  cond1->b2[i] = cond2->b2[i];
205  cond2->b2[i] = tmp;
206  changed = true;
207  }
208  }
209  }
210  return changed;
211 }
212 
219 bool
220 cond_rectangle_mutate(const struct XCSF *xcsf, const struct Cl *c)
221 {
222  bool changed = false;
223  const struct CondRectangle *cond = c->cond;
224  double *b1 = cond->b1;
225  double *b2 = cond->b2;
226  sam_adapt(cond->mu, N_MU, MU_TYPE);
227  for (int i = 0; i < xcsf->x_dim; ++i) {
228  double orig = b1[i];
229  b1[i] += rand_normal(0, cond->mu[0]);
230  b1[i] = clamp(b1[i], xcsf->cond->min, xcsf->cond->max);
231  if (orig != b1[i]) {
232  changed = true;
233  }
234  orig = b2[i];
235  b2[i] += rand_normal(0, cond->mu[0]);
236  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
237  b2[i] = fmax(DBL_EPSILON, b2[i]);
238  } else {
239  b2[i] = clamp(b2[i], xcsf->cond->min, xcsf->cond->max);
240  }
241  if (orig != b2[i]) {
242  changed = true;
243  }
244  }
245  return changed;
246 }
247 
255 bool
256 cond_rectangle_general(const struct XCSF *xcsf, const struct Cl *c1,
257  const struct Cl *c2)
258 {
259  const struct CondRectangle *cond1 = c1->cond;
260  const struct CondRectangle *cond2 = c2->cond;
261  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
262  for (int i = 0; i < xcsf->x_dim; ++i) {
263  const double l1 = cond1->b1[i] - cond1->b2[i];
264  const double l2 = cond2->b1[i] - cond2->b2[i];
265  const double u1 = cond1->b1[i] + cond1->b2[i];
266  const double u2 = cond2->b1[i] + cond2->b2[i];
267  if (l1 > l2 || u1 < u2) {
268  return false;
269  }
270  }
271  } else {
272  for (int i = 0; i < xcsf->x_dim; ++i) {
273  const double l1 = fmin(cond1->b1[i], cond1->b2[i]);
274  const double l2 = fmin(cond2->b1[i], cond2->b2[i]);
275  const double u1 = fmax(cond1->b1[i], cond1->b2[i]);
276  const double u2 = fmax(cond2->b1[i], cond2->b2[i]);
277  if (l1 > l2 || u1 < u2) {
278  return false;
279  }
280  }
281  }
282  return true;
283 }
284 
290 void
291 cond_rectangle_print(const struct XCSF *xcsf, const struct Cl *c)
292 {
293  char *json_str = cond_rectangle_json_export(xcsf, c);
294  printf("%s\n", json_str);
295  free(json_str);
296 }
297 
304 double
305 cond_rectangle_size(const struct XCSF *xcsf, const struct Cl *c)
306 {
307  (void) c;
308  return xcsf->x_dim;
309 }
310 
318 size_t
319 cond_rectangle_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
320 {
321  size_t s = 0;
322  const struct CondRectangle *cond = c->cond;
323  s += fwrite(cond->b1, sizeof(double), xcsf->x_dim, fp);
324  s += fwrite(cond->b2, sizeof(double), xcsf->x_dim, fp);
325  s += fwrite(cond->mu, sizeof(double), N_MU, fp);
326  return s;
327 }
328 
336 size_t
337 cond_rectangle_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
338 {
339  size_t s = 0;
340  struct CondRectangle *new = malloc(sizeof(struct CondRectangle));
341  new->b1 = malloc(sizeof(double) * xcsf->x_dim);
342  new->b2 = malloc(sizeof(double) * xcsf->x_dim);
343  new->mu = malloc(sizeof(double) * N_MU);
344  s += fread(new->b1, sizeof(double), xcsf->x_dim, fp);
345  s += fread(new->b2, sizeof(double), xcsf->x_dim, fp);
346  s += fread(new->mu, sizeof(double), N_MU, fp);
347  c->cond = new;
348  return s;
349 }
350 
357 char *
358 cond_rectangle_json_export(const struct XCSF *xcsf, const struct Cl *c)
359 {
360  const struct CondRectangle *cond = c->cond;
361  cJSON *json = cJSON_CreateObject();
362  cJSON *b1 = cJSON_CreateDoubleArray(cond->b1, xcsf->x_dim);
363  cJSON *b2 = cJSON_CreateDoubleArray(cond->b2, xcsf->x_dim);
364  cJSON *mutation = cJSON_CreateDoubleArray(cond->mu, N_MU);
365  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
366  cJSON_AddStringToObject(json, "type", "hyperrectangle_csr");
367  cJSON_AddItemToObject(json, "center", b1);
368  cJSON_AddItemToObject(json, "spread", b2);
369  } else {
370  cJSON_AddStringToObject(json, "type", "hyperrectangle_ubr");
371  cJSON_AddItemToObject(json, "bound1", b1);
372  cJSON_AddItemToObject(json, "bound2", b2);
373  }
374  cJSON_AddItemToObject(json, "mutation", mutation);
375  char *string = cJSON_Print(json);
376  cJSON_Delete(json);
377  return string;
378 }
379 
386 void
387 cond_rectangle_json_import(const struct XCSF *xcsf, struct Cl *c,
388  const cJSON *json)
389 {
390  struct CondRectangle *cond = c->cond;
391  bool csr = false;
392  if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
393  csr = true;
394  }
395  const char *b1_name = csr ? "center" : "bound1";
396  const char *b2_name = csr ? "spread" : "bound2";
397  const cJSON *item = cJSON_GetObjectItem(json, b1_name);
398  if (item != NULL && cJSON_IsArray(item)) {
399  if (cJSON_GetArraySize(item) == xcsf->x_dim) {
400  for (int i = 0; i < xcsf->x_dim; ++i) {
401  const cJSON *item_i = cJSON_GetArrayItem(item, i);
402  cond->b1[i] = item_i->valuedouble;
403  }
404  } else {
405  printf("Import error: %s length mismatch\n", b1_name);
406  exit(EXIT_FAILURE);
407  }
408  }
409  item = cJSON_GetObjectItem(json, b2_name);
410  if (item != NULL && cJSON_IsArray(item)) {
411  if (cJSON_GetArraySize(item) == xcsf->x_dim) {
412  for (int i = 0; i < xcsf->x_dim; ++i) {
413  const cJSON *item_i = cJSON_GetArrayItem(item, i);
414  cond->b2[i] = item_i->valuedouble;
415  }
416  } else {
417  printf("Import error: %s length mismatch\n", b2_name);
418  exit(EXIT_FAILURE);
419  }
420  }
421  sam_json_import(cond->mu, N_MU, json);
422 }
void cond_rectangle_copy(const struct XCSF *xcsf, struct Cl *dest, const struct Cl *src)
Copies a hyperrectangle condition from one classifier to another.
void cond_rectangle_free(const struct XCSF *xcsf, const struct Cl *c)
Frees the memory used by a hyperrectangle condition.
static const int MU_TYPE[(1)]
Self-adaptation method for mutating hyperrectangles.
bool cond_rectangle_general(const struct XCSF *xcsf, const struct Cl *c1, const struct Cl *c2)
Returns whether classifier c1 has a condition more general than c2.
void cond_rectangle_json_import(const struct XCSF *xcsf, struct Cl *c, const cJSON *json)
Creates a hyperrectangle from a cJSON object.
char * cond_rectangle_json_export(const struct XCSF *xcsf, const struct Cl *c)
Returns a json formatted string representation of a hyperrectangle.
void cond_rectangle_print(const struct XCSF *xcsf, const struct Cl *c)
Prints a hyperrectangle condition.
void cond_rectangle_update(const struct XCSF *xcsf, const struct Cl *c, const double *x, const double *y)
Updates a hyperrectangle, sliding the centers towards the mean input.
#define N_MU
Number of hyperrectangle mutation rates.
void cond_rectangle_init(const struct XCSF *xcsf, struct Cl *c)
Creates and initialises a hyperrectangle condition.
size_t cond_rectangle_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
Writes a hyperrectangle condition to a file.
bool cond_rectangle_mutate(const struct XCSF *xcsf, const struct Cl *c)
Mutates a hyperrectangle condition with the self-adaptive rate.
bool cond_rectangle_crossover(const struct XCSF *xcsf, const struct Cl *c1, const struct Cl *c2)
Performs uniform crossover with two hyperrectangle conditions.
double cond_rectangle_size(const struct XCSF *xcsf, const struct Cl *c)
Returns the size of a hyperrectangle condition.
size_t cond_rectangle_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
Reads a hyperrectangle condition from a file.
void cond_rectangle_cover(const struct XCSF *xcsf, const struct Cl *c, const double *x)
Generates a hyperrectangle that matches the current input.
bool cond_rectangle_match(const struct XCSF *xcsf, const struct Cl *c, const double *x)
Calculates whether a hyperrectangle condition matches an input.
Hyperrectangle condition functions.
#define COND_TYPE_HYPERRECTANGLE_CSR
Condition type CSR hyperrectangle.
Definition: condition.h:30
Evolutionary algorithm functions.
Definition: __init__.py:1
void sam_json_import(double *mu, const int N, const cJSON *json)
Initialises a mutation vector from a cJSON object.
Definition: sam.c:100
void sam_init(double *mu, const int N, const int *type)
Initialises self-adaptive mutation rates.
Definition: sam.c:43
void sam_adapt(double *mu, const int N, const int *type)
Self-adapts mutation rates.
Definition: sam.c:68
Self-adaptive mutation functions.
#define SAM_LOG_NORMAL
Log normal self-adaptation.
Definition: sam.h:28
Classifier data structure.
Definition: xcsf.h:45
void * cond
Condition structure.
Definition: xcsf.h:49
Hyperrectangle condition data structure.
double * b2
Spreads for CSR, second bound for UBR.
double * mu
Mutation rates.
double * b1
Centers for CSR, first bound for UBR.
XCSF data structure.
Definition: xcsf.h:85
double rand_normal(const double mu, const double sigma)
Returns a random Gaussian with specified mean and standard deviation.
Definition: utils.c:87
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 double clamp(const double a, const double min, const double max)
Returns a float clamped within the specified range.
Definition: utils.h:60