XCSF 1.5.1
XCSF learning classifier system
Loading...
Searching...
No Matches
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 2
30
34static const int MU_TYPE[N_MU] = { SAM_LOG_NORMAL, SAM_LOG_NORMAL };
35
45static double
46cond_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
64void
65cond_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 if (xcsf->cond->sam) { // self-adaptive mutation
77 sam_init(new->mu, N_MU, MU_TYPE);
78 } else { // constant mutation rate
79 new->mu[0] = xcsf->cond->p_mu;
80 new->mu[1] = xcsf->cond->mu;
81 }
82 c->cond = new;
83}
84
90void
91cond_ellipsoid_free(const struct XCSF *xcsf, const struct Cl *c)
92{
93 (void) xcsf;
94 const struct CondEllipsoid *cond = c->cond;
95 free(cond->center);
96 free(cond->spread);
97 free(cond->mu);
98 free(c->cond);
99}
100
107void
108cond_ellipsoid_copy(const struct XCSF *xcsf, struct Cl *dest,
109 const struct Cl *src)
110{
111 struct CondEllipsoid *new = malloc(sizeof(struct CondEllipsoid));
112 const struct CondEllipsoid *src_cond = src->cond;
113 new->center = malloc(sizeof(double) * xcsf->x_dim);
114 new->spread = malloc(sizeof(double) * xcsf->x_dim);
115 new->mu = malloc(sizeof(double) * N_MU);
116 memcpy(new->center, src_cond->center, sizeof(double) * xcsf->x_dim);
117 memcpy(new->spread, src_cond->spread, sizeof(double) * xcsf->x_dim);
118 memcpy(new->mu, src_cond->mu, sizeof(double) * N_MU);
119 dest->cond = new;
120}
121
128void
129cond_ellipsoid_cover(const struct XCSF *xcsf, const struct Cl *c,
130 const double *x)
131{
132 const struct CondEllipsoid *cond = c->cond;
133 const double spread_max = fabs(xcsf->cond->max - xcsf->cond->min);
134 for (int i = 0; i < xcsf->x_dim; ++i) {
135 cond->center[i] = x[i];
136 cond->spread[i] = rand_uniform(xcsf->cond->spread_min, spread_max);
137 }
138}
139
147void
148cond_ellipsoid_update(const struct XCSF *xcsf, const struct Cl *c,
149 const double *x, const double *y)
150{
151 (void) y;
152 if (xcsf->cond->eta > 0) {
153 const struct CondEllipsoid *cond = c->cond;
154 for (int i = 0; i < xcsf->x_dim; ++i) {
155 cond->center[i] += xcsf->cond->eta * (x[i] - cond->center[i]);
156 }
157 }
158}
159
167bool
168cond_ellipsoid_match(const struct XCSF *xcsf, const struct Cl *c,
169 const double *x)
170{
171 return (cond_ellipsoid_dist(xcsf, c, x) < 1);
172}
173
181bool
182cond_ellipsoid_crossover(const struct XCSF *xcsf, const struct Cl *c1,
183 const struct Cl *c2)
184{
185 const struct CondEllipsoid *cond1 = c1->cond;
186 const struct CondEllipsoid *cond2 = c2->cond;
187 bool changed = false;
188 if (rand_uniform(0, 1) < xcsf->ea->p_crossover) {
189 for (int i = 0; i < xcsf->x_dim; ++i) {
190 if (rand_uniform(0, 1) < 0.5) {
191 const double tmp = cond1->center[i];
192 cond1->center[i] = cond2->center[i];
193 cond2->center[i] = tmp;
194 changed = true;
195 }
196 if (rand_uniform(0, 1) < 0.5) {
197 const double tmp = cond1->spread[i];
198 cond1->spread[i] = cond2->spread[i];
199 cond2->spread[i] = tmp;
200 changed = true;
201 }
202 }
203 }
204 return changed;
205}
206
213bool
214cond_ellipsoid_mutate(const struct XCSF *xcsf, const struct Cl *c)
215{
216 bool changed = false;
217 const struct CondEllipsoid *cond = c->cond;
218 double *center = cond->center;
219 double *spread = cond->spread;
220
221 if (xcsf->cond->sam) {
222 sam_adapt(cond->mu, N_MU, MU_TYPE);
223 }
224
225 for (int i = 0; i < xcsf->x_dim; ++i) {
226 if (rand_uniform(0, 1) < cond->mu[0]) {
227 double orig = center[i];
228 center[i] += rand_normal(0, cond->mu[1]);
229 center[i] = clamp(center[i], xcsf->cond->min, xcsf->cond->max);
230 if (orig != center[i]) {
231 changed = true;
232 }
233
234 orig = spread[i];
235 spread[i] += rand_normal(0, cond->mu[1]);
236 spread[i] = fmax(DBL_EPSILON, spread[i]);
237 if (orig != spread[i]) {
238 changed = true;
239 }
240 }
241 }
242 return changed;
243}
244
252bool
253cond_ellipsoid_general(const struct XCSF *xcsf, const struct Cl *c1,
254 const struct Cl *c2)
255{
256 const struct CondEllipsoid *cond1 = c1->cond;
257 const struct CondEllipsoid *cond2 = c2->cond;
258 double *temp = malloc(sizeof(double) * xcsf->x_dim);
259 memcpy(temp, cond2->center, sizeof(double) * xcsf->x_dim);
260 for (int i = 0; i < xcsf->x_dim; ++i) {
261 if (cond1->center[i] != cond2->center[i] ||
262 cond1->spread[i] != cond2->spread[i]) {
263 temp[i] += cond2->spread[i];
264 if (cond_ellipsoid_dist(xcsf, c1, temp) > 1) {
265 free(temp);
266 return false;
267 }
268 temp[i] -= 2 * cond2->spread[i];
269 if (cond_ellipsoid_dist(xcsf, c1, temp) > 1) {
270 free(temp);
271 return false;
272 }
273 temp[i] = cond2->center[i];
274 }
275 }
276 free(temp);
277 return true;
278}
279
285void
286cond_ellipsoid_print(const struct XCSF *xcsf, const struct Cl *c)
287{
288 char *json_str = cond_ellipsoid_json_export(xcsf, c);
289 printf("%s\n", json_str);
290 free(json_str);
291}
292
299double
300cond_ellipsoid_size(const struct XCSF *xcsf, const struct Cl *c)
301{
302 (void) c;
303 return xcsf->x_dim;
304}
305
313size_t
314cond_ellipsoid_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
315{
316 size_t s = 0;
317 const struct CondEllipsoid *cond = c->cond;
318 s += fwrite(cond->center, sizeof(double), xcsf->x_dim, fp);
319 s += fwrite(cond->spread, sizeof(double), xcsf->x_dim, fp);
320 s += fwrite(cond->mu, sizeof(double), N_MU, fp);
321 return s;
322}
323
331size_t
332cond_ellipsoid_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
333{
334 size_t s = 0;
335 struct CondEllipsoid *new = malloc(sizeof(struct CondEllipsoid));
336 new->center = malloc(sizeof(double) * xcsf->x_dim);
337 new->spread = malloc(sizeof(double) * xcsf->x_dim);
338 new->mu = malloc(sizeof(double) * N_MU);
339 s += fread(new->center, sizeof(double), xcsf->x_dim, fp);
340 s += fread(new->spread, sizeof(double), xcsf->x_dim, fp);
341 s += fread(new->mu, sizeof(double), N_MU, fp);
342 c->cond = new;
343 return s;
344}
345
352char *
353cond_ellipsoid_json_export(const struct XCSF *xcsf, const struct Cl *c)
354{
355 const struct CondEllipsoid *cond = c->cond;
356 cJSON *json = cJSON_CreateObject();
357 cJSON_AddStringToObject(json, "type", "hyperellipsoid");
358 cJSON *center = cJSON_CreateDoubleArray(cond->center, xcsf->x_dim);
359 cJSON *spread = cJSON_CreateDoubleArray(cond->spread, xcsf->x_dim);
360 cJSON *mutation = cJSON_CreateDoubleArray(cond->mu, N_MU);
361 cJSON_AddItemToObject(json, "center", center);
362 cJSON_AddItemToObject(json, "spread", spread);
363 cJSON_AddItemToObject(json, "mutation", mutation);
364 char *string = cJSON_Print(json);
365 cJSON_Delete(json);
366 return string;
367}
368
375void
376cond_ellipsoid_json_import(const struct XCSF *xcsf, struct Cl *c,
377 const cJSON *json)
378{
379 struct CondEllipsoid *cond = c->cond;
380 const cJSON *item = cJSON_GetObjectItem(json, "center");
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->center[i] = item_i->valuedouble;
386 }
387 } else {
388 printf("Import error: center length mismatch\n");
389 exit(EXIT_FAILURE);
390 }
391 }
392 item = cJSON_GetObjectItem(json, "spread");
393 if (item != NULL && cJSON_IsArray(item)) {
394 if (cJSON_GetArraySize(item) == xcsf->x_dim) {
395 for (int i = 0; i < xcsf->x_dim; ++i) {
396 const cJSON *item_i = cJSON_GetArrayItem(item, i);
397 cond->spread[i] = item_i->valuedouble;
398 }
399 } else {
400 printf("Import error: spread length mismatch\n");
401 exit(EXIT_FAILURE);
402 }
403 }
404 sam_json_import(cond->mu, N_MU, json);
405}
void cond_ellipsoid_free(const struct XCSF *xcsf, const struct Cl *c)
Frees the memory used by a hyperellipsoid condition.
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.
char * cond_ellipsoid_json_export(const struct XCSF *xcsf, const struct Cl *c)
Returns a json formatted string representation of a hyperellipsoid.
static const int MU_TYPE[2]
Self-adaptation method for mutating hyperellipsoids.
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.
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.
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