XCSF  1.4.7
XCSF learning classifier system
cond_ellipsoid.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_ellipsoid.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 
45 static double
46 cond_ellipsoid_dist(const struct XCSF *xcsf, const struct Cl *c,
47  const double *x)
48 {
49  const struct CondEllipsoid *cond = c->cond;
50  double dist = 0;
51  for (int i = 0; i < xcsf->x_dim; ++i) {
52  const double d = (x[i] - cond->center[i]) / cond->spread[i];
53  dist += d * d;
54  }
55  return dist;
56 }
57 
64 void
65 cond_ellipsoid_init(const struct XCSF *xcsf, struct Cl *c)
66 {
67  struct CondEllipsoid *new = malloc(sizeof(struct CondEllipsoid));
68  new->center = malloc(sizeof(double) * xcsf->x_dim);
69  new->spread = malloc(sizeof(double) * xcsf->x_dim);
70  new->mu = malloc(sizeof(double) * N_MU);
71  const double spread_max = fabs(xcsf->cond->max - xcsf->cond->min);
72  for (int i = 0; i < xcsf->x_dim; ++i) {
73  new->center[i] = rand_uniform(xcsf->cond->min, xcsf->cond->max);
74  new->spread[i] = rand_uniform(xcsf->cond->spread_min, spread_max);
75  }
76  sam_init(new->mu, N_MU, MU_TYPE);
77  c->cond = new;
78 }
79 
85 void
86 cond_ellipsoid_free(const struct XCSF *xcsf, const struct Cl *c)
87 {
88  (void) xcsf;
89  const struct CondEllipsoid *cond = c->cond;
90  free(cond->center);
91  free(cond->spread);
92  free(cond->mu);
93  free(c->cond);
94 }
95 
102 void
103 cond_ellipsoid_copy(const struct XCSF *xcsf, struct Cl *dest,
104  const struct Cl *src)
105 {
106  struct CondEllipsoid *new = malloc(sizeof(struct CondEllipsoid));
107  const struct CondEllipsoid *src_cond = src->cond;
108  new->center = malloc(sizeof(double) * xcsf->x_dim);
109  new->spread = malloc(sizeof(double) * xcsf->x_dim);
110  new->mu = malloc(sizeof(double) * N_MU);
111  memcpy(new->center, src_cond->center, sizeof(double) * xcsf->x_dim);
112  memcpy(new->spread, src_cond->spread, sizeof(double) * xcsf->x_dim);
113  memcpy(new->mu, src_cond->mu, sizeof(double) * N_MU);
114  dest->cond = new;
115 }
116 
123 void
124 cond_ellipsoid_cover(const struct XCSF *xcsf, const struct Cl *c,
125  const double *x)
126 {
127  const struct CondEllipsoid *cond = c->cond;
128  const double spread_max = fabs(xcsf->cond->max - xcsf->cond->min);
129  for (int i = 0; i < xcsf->x_dim; ++i) {
130  cond->center[i] = x[i];
131  cond->spread[i] = rand_uniform(xcsf->cond->spread_min, spread_max);
132  }
133 }
134 
142 void
143 cond_ellipsoid_update(const struct XCSF *xcsf, const struct Cl *c,
144  const double *x, const double *y)
145 {
146  (void) y;
147  if (xcsf->cond->eta > 0) {
148  const struct CondEllipsoid *cond = c->cond;
149  for (int i = 0; i < xcsf->x_dim; ++i) {
150  cond->center[i] += xcsf->cond->eta * (x[i] - cond->center[i]);
151  }
152  }
153 }
154 
162 bool
163 cond_ellipsoid_match(const struct XCSF *xcsf, const struct Cl *c,
164  const double *x)
165 {
166  return (cond_ellipsoid_dist(xcsf, c, x) < 1);
167 }
168 
176 bool
177 cond_ellipsoid_crossover(const struct XCSF *xcsf, const struct Cl *c1,
178  const struct Cl *c2)
179 {
180  const struct CondEllipsoid *cond1 = c1->cond;
181  const struct CondEllipsoid *cond2 = c2->cond;
182  bool changed = false;
183  if (rand_uniform(0, 1) < xcsf->ea->p_crossover) {
184  for (int i = 0; i < xcsf->x_dim; ++i) {
185  if (rand_uniform(0, 1) < 0.5) {
186  const double tmp = cond1->center[i];
187  cond1->center[i] = cond2->center[i];
188  cond2->center[i] = tmp;
189  changed = true;
190  }
191  if (rand_uniform(0, 1) < 0.5) {
192  const double tmp = cond1->spread[i];
193  cond1->spread[i] = cond2->spread[i];
194  cond2->spread[i] = tmp;
195  changed = true;
196  }
197  }
198  }
199  return changed;
200 }
201 
208 bool
209 cond_ellipsoid_mutate(const struct XCSF *xcsf, const struct Cl *c)
210 {
211  bool changed = false;
212  const struct CondEllipsoid *cond = c->cond;
213  double *center = cond->center;
214  double *spread = cond->spread;
215  sam_adapt(cond->mu, N_MU, MU_TYPE);
216  for (int i = 0; i < xcsf->x_dim; ++i) {
217  double orig = center[i];
218  center[i] += rand_normal(0, cond->mu[0]);
219  center[i] = clamp(center[i], xcsf->cond->min, xcsf->cond->max);
220  if (orig != center[i]) {
221  changed = true;
222  }
223  orig = spread[i];
224  spread[i] += rand_normal(0, cond->mu[0]);
225  spread[i] = fmax(DBL_EPSILON, spread[i]);
226  if (orig != spread[i]) {
227  changed = true;
228  }
229  }
230  return changed;
231 }
232 
240 bool
241 cond_ellipsoid_general(const struct XCSF *xcsf, const struct Cl *c1,
242  const struct Cl *c2)
243 {
244  const struct CondEllipsoid *cond1 = c1->cond;
245  const struct CondEllipsoid *cond2 = c2->cond;
246  double *temp = malloc(sizeof(double) * xcsf->x_dim);
247  memcpy(temp, cond2->center, sizeof(double) * xcsf->x_dim);
248  for (int i = 0; i < xcsf->x_dim; ++i) {
249  if (cond1->center[i] != cond2->center[i] ||
250  cond1->spread[i] != cond2->spread[i]) {
251  temp[i] += cond2->spread[i];
252  if (cond_ellipsoid_dist(xcsf, c1, temp) > 1) {
253  free(temp);
254  return false;
255  }
256  temp[i] -= 2 * cond2->spread[i];
257  if (cond_ellipsoid_dist(xcsf, c1, temp) > 1) {
258  free(temp);
259  return false;
260  }
261  temp[i] = cond2->center[i];
262  }
263  }
264  free(temp);
265  return true;
266 }
267 
273 void
274 cond_ellipsoid_print(const struct XCSF *xcsf, const struct Cl *c)
275 {
276  char *json_str = cond_ellipsoid_json_export(xcsf, c);
277  printf("%s\n", json_str);
278  free(json_str);
279 }
280 
287 double
288 cond_ellipsoid_size(const struct XCSF *xcsf, const struct Cl *c)
289 {
290  (void) c;
291  return xcsf->x_dim;
292 }
293 
301 size_t
302 cond_ellipsoid_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
303 {
304  size_t s = 0;
305  const struct CondEllipsoid *cond = c->cond;
306  s += fwrite(cond->center, sizeof(double), xcsf->x_dim, fp);
307  s += fwrite(cond->spread, sizeof(double), xcsf->x_dim, fp);
308  s += fwrite(cond->mu, sizeof(double), N_MU, fp);
309  return s;
310 }
311 
319 size_t
320 cond_ellipsoid_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
321 {
322  size_t s = 0;
323  struct CondEllipsoid *new = malloc(sizeof(struct CondEllipsoid));
324  new->center = malloc(sizeof(double) * xcsf->x_dim);
325  new->spread = malloc(sizeof(double) * xcsf->x_dim);
326  new->mu = malloc(sizeof(double) * N_MU);
327  s += fread(new->center, sizeof(double), xcsf->x_dim, fp);
328  s += fread(new->spread, sizeof(double), xcsf->x_dim, fp);
329  s += fread(new->mu, sizeof(double), N_MU, fp);
330  c->cond = new;
331  return s;
332 }
333 
340 char *
341 cond_ellipsoid_json_export(const struct XCSF *xcsf, const struct Cl *c)
342 {
343  const struct CondEllipsoid *cond = c->cond;
344  cJSON *json = cJSON_CreateObject();
345  cJSON_AddStringToObject(json, "type", "hyperellipsoid");
346  cJSON *center = cJSON_CreateDoubleArray(cond->center, xcsf->x_dim);
347  cJSON *spread = cJSON_CreateDoubleArray(cond->spread, xcsf->x_dim);
348  cJSON *mutation = cJSON_CreateDoubleArray(cond->mu, N_MU);
349  cJSON_AddItemToObject(json, "center", center);
350  cJSON_AddItemToObject(json, "spread", spread);
351  cJSON_AddItemToObject(json, "mutation", mutation);
352  char *string = cJSON_Print(json);
353  cJSON_Delete(json);
354  return string;
355 }
356 
363 void
364 cond_ellipsoid_json_import(const struct XCSF *xcsf, struct Cl *c,
365  const cJSON *json)
366 {
367  struct CondEllipsoid *cond = c->cond;
368  const cJSON *item = cJSON_GetObjectItem(json, "center");
369  if (item != NULL && cJSON_IsArray(item)) {
370  if (cJSON_GetArraySize(item) == xcsf->x_dim) {
371  for (int i = 0; i < xcsf->x_dim; ++i) {
372  const cJSON *item_i = cJSON_GetArrayItem(item, i);
373  cond->center[i] = item_i->valuedouble;
374  }
375  } else {
376  printf("Import error: center length mismatch\n");
377  exit(EXIT_FAILURE);
378  }
379  }
380  item = cJSON_GetObjectItem(json, "spread");
381  if (item != NULL && cJSON_IsArray(item)) {
382  if (cJSON_GetArraySize(item) == xcsf->x_dim) {
383  for (int i = 0; i < xcsf->x_dim; ++i) {
384  const cJSON *item_i = cJSON_GetArrayItem(item, i);
385  cond->spread[i] = item_i->valuedouble;
386  }
387  } else {
388  printf("Import error: spread length mismatch\n");
389  exit(EXIT_FAILURE);
390  }
391  }
392  sam_json_import(cond->mu, N_MU, json);
393 }
void cond_ellipsoid_free(const struct XCSF *xcsf, const struct Cl *c)
Frees the memory used by a hyperellipsoid condition.
static const int MU_TYPE[(1)]
Self-adaptation method for mutating hyperellipsoids.
size_t cond_ellipsoid_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
Reads a hyperellipsoid condition from a file.
void cond_ellipsoid_print(const struct XCSF *xcsf, const struct Cl *c)
Prints a hyperellipsoid condition.
size_t cond_ellipsoid_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
Writes a hyperellipsoid condition to a file.
bool cond_ellipsoid_match(const struct XCSF *xcsf, const struct Cl *c, const double *x)
Calculates whether a hyperellipsoid condition matches an input.
void cond_ellipsoid_json_import(const struct XCSF *xcsf, struct Cl *c, const cJSON *json)
Creates a hyperellipsoid from a cJSON object.
#define N_MU
Number of hyperellipsoid mutation rates.
static double cond_ellipsoid_dist(const struct XCSF *xcsf, const struct Cl *c, const double *x)
Returns the relative distance to a hyperellipsoid.
double cond_ellipsoid_size(const struct XCSF *xcsf, const struct Cl *c)
Returns the size of a hyperellipsoid condition.
void cond_ellipsoid_update(const struct XCSF *xcsf, const struct Cl *c, const double *x, const double *y)
Updates a hyperellipsoid, sliding the centers towards the mean input.
char * cond_ellipsoid_json_export(const struct XCSF *xcsf, const struct Cl *c)
Returns a json formatted string representation of a hyperellipsoid.
bool cond_ellipsoid_crossover(const struct XCSF *xcsf, const struct Cl *c1, const struct Cl *c2)
Performs uniform crossover with two hyperellipsoid conditions.
bool cond_ellipsoid_mutate(const struct XCSF *xcsf, const struct Cl *c)
Mutates a hyperellipsoid condition with the self-adaptive rate.
bool cond_ellipsoid_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_ellipsoid_init(const struct XCSF *xcsf, struct Cl *c)
Creates and initialises a hyperellipsoid condition.
void cond_ellipsoid_copy(const struct XCSF *xcsf, struct Cl *dest, const struct Cl *src)
Copies a hyperellipsoid condition from one classifier to another.
void cond_ellipsoid_cover(const struct XCSF *xcsf, const struct Cl *c, const double *x)
Generates a hyperellipsoid that matches the current input.
Hyperellipsoid condition functions.
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
Hyperellipsoid condition data structure.
double * center
Centers.
double * spread
Spreads.
double * mu
Mutation rates.
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