XCSF 1.5.1
XCSF learning classifier system
Loading...
Searching...
No Matches
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 2
30
34static const int MU_TYPE[N_MU] = { SAM_LOG_NORMAL, SAM_LOG_NORMAL };
35
41void
42cond_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 if (xcsf->cond->sam) { // self-adaptive mutation
60 sam_init(new->mu, N_MU, MU_TYPE);
61 } else { // constant mutation rate
62 new->mu[0] = xcsf->cond->p_mu;
63 new->mu[1] = xcsf->cond->mu;
64 }
65 c->cond = new;
66}
67
73void
74cond_rectangle_free(const struct XCSF *xcsf, const struct Cl *c)
75{
76 (void) xcsf;
77 const struct CondRectangle *cond = c->cond;
78 free(cond->b1);
79 free(cond->b2);
80 free(cond->mu);
81 free(c->cond);
82}
83
90void
91cond_rectangle_copy(const struct XCSF *xcsf, struct Cl *dest,
92 const struct Cl *src)
93{
94 struct CondRectangle *new = malloc(sizeof(struct CondRectangle));
95 const struct CondRectangle *src_cond = src->cond;
96 new->b1 = malloc(sizeof(double) * xcsf->x_dim);
97 new->b2 = malloc(sizeof(double) * xcsf->x_dim);
98 new->mu = malloc(sizeof(double) * N_MU);
99 memcpy(new->b1, src_cond->b1, sizeof(double) * xcsf->x_dim);
100 memcpy(new->b2, src_cond->b2, sizeof(double) * xcsf->x_dim);
101 memcpy(new->mu, src_cond->mu, sizeof(double) * N_MU);
102 dest->cond = new;
103}
104
111void
112cond_rectangle_cover(const struct XCSF *xcsf, const struct Cl *c,
113 const double *x)
114{
115 const struct CondRectangle *cond = c->cond;
116 const double spread_max = fabs(xcsf->cond->max - xcsf->cond->min);
117 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
118 for (int i = 0; i < xcsf->x_dim; ++i) {
119 cond->b1[i] = x[i];
120 cond->b2[i] = rand_uniform(xcsf->cond->spread_min, spread_max);
121 }
122 } else {
123 for (int i = 0; i < xcsf->x_dim; ++i) {
124 const double r1 = rand_uniform(xcsf->cond->spread_min, spread_max);
125 const double r2 = rand_uniform(xcsf->cond->spread_min, spread_max);
126 cond->b1[i] = x[i] - (r1 * 0.5);
127 cond->b2[i] = x[i] + (r2 * 0.5);
128 cond->b1[i] = clamp(cond->b1[i], xcsf->cond->min, xcsf->cond->max);
129 cond->b2[i] = clamp(cond->b2[i], xcsf->cond->min, xcsf->cond->max);
130 }
131 }
132}
133
141void
142cond_rectangle_update(const struct XCSF *xcsf, const struct Cl *c,
143 const double *x, const double *y)
144{
145 (void) y;
146 if (xcsf->cond->eta > 0) {
147 const struct CondRectangle *cond = c->cond;
148 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
149 for (int i = 0; i < xcsf->x_dim; ++i) {
150 cond->b1[i] += xcsf->cond->eta * (x[i] - cond->b1[i]);
151 }
152 } else { // ubr
153 for (int i = 0; i < xcsf->x_dim; ++i) {
154 const double center = (cond->b1[i] + cond->b2[i]) * 0.5;
155 const double update = (x[i] - center) * 0.5 * xcsf->cond->eta;
156 cond->b1[i] += update;
157 cond->b2[i] += update;
158 }
159 }
160 }
161}
162
170bool
171cond_rectangle_match(const struct XCSF *xcsf, const struct Cl *c,
172 const double *x)
173{
174 const struct CondRectangle *cond = c->cond;
175 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
176 for (int i = 0; i < xcsf->x_dim; ++i) {
177 const double lb = cond->b1[i] - cond->b2[i];
178 const double ub = cond->b1[i] + cond->b2[i];
179 if (x[i] < lb || x[i] > ub) {
180 return false;
181 }
182 }
183 } else { // ubr
184 for (int i = 0; i < xcsf->x_dim; ++i) {
185 const double lb = fmin(cond->b1[i], cond->b2[i]);
186 const double ub = fmax(cond->b1[i], cond->b2[i]);
187 if (x[i] < lb || x[i] > ub) {
188 return false;
189 }
190 }
191 }
192 return true;
193}
194
202bool
203cond_rectangle_crossover(const struct XCSF *xcsf, const struct Cl *c1,
204 const struct Cl *c2)
205{
206 const struct CondRectangle *cond1 = c1->cond;
207 const struct CondRectangle *cond2 = c2->cond;
208 bool changed = false;
209 if (rand_uniform(0, 1) < xcsf->ea->p_crossover) {
210 for (int i = 0; i < xcsf->x_dim; ++i) {
211 if (rand_uniform(0, 1) < 0.5) {
212 const double tmp = cond1->b1[i];
213 cond1->b1[i] = cond2->b1[i];
214 cond2->b1[i] = tmp;
215 changed = true;
216 }
217 if (rand_uniform(0, 1) < 0.5) {
218 const double tmp = cond1->b2[i];
219 cond1->b2[i] = cond2->b2[i];
220 cond2->b2[i] = tmp;
221 changed = true;
222 }
223 }
224 }
225 return changed;
226}
227
234bool
235cond_rectangle_mutate(const struct XCSF *xcsf, const struct Cl *c)
236{
237 bool changed = false;
238 const struct CondRectangle *cond = c->cond;
239 double *b1 = cond->b1;
240 double *b2 = cond->b2;
241
242 if (xcsf->cond->sam) {
243 sam_adapt(cond->mu, N_MU, MU_TYPE);
244 }
245
246 for (int i = 0; i < xcsf->x_dim; ++i) {
247 if (rand_uniform(0, 1) < cond->mu[0]) {
248 // first bound (or center)
249 double orig = b1[i];
250 b1[i] += rand_normal(0, cond->mu[1]);
251 b1[i] = clamp(b1[i], xcsf->cond->min, xcsf->cond->max);
252 if (orig != b1[i]) {
253 changed = true;
254 }
255
256 // second bound (or spread)
257 orig = b2[i];
258 b2[i] += rand_normal(0, cond->mu[1]);
259 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
260 b2[i] = fmax(DBL_EPSILON, b2[i]);
261 } else {
262 b2[i] = clamp(b2[i], xcsf->cond->min, xcsf->cond->max);
263 }
264 if (orig != b2[i]) {
265 changed = true;
266 }
267 }
268 }
269
270 return changed;
271}
272
280bool
281cond_rectangle_general(const struct XCSF *xcsf, const struct Cl *c1,
282 const struct Cl *c2)
283{
284 const struct CondRectangle *cond1 = c1->cond;
285 const struct CondRectangle *cond2 = c2->cond;
286 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
287 for (int i = 0; i < xcsf->x_dim; ++i) {
288 const double l1 = cond1->b1[i] - cond1->b2[i];
289 const double l2 = cond2->b1[i] - cond2->b2[i];
290 const double u1 = cond1->b1[i] + cond1->b2[i];
291 const double u2 = cond2->b1[i] + cond2->b2[i];
292 if (l1 > l2 || u1 < u2) {
293 return false;
294 }
295 }
296 } else {
297 for (int i = 0; i < xcsf->x_dim; ++i) {
298 const double l1 = fmin(cond1->b1[i], cond1->b2[i]);
299 const double l2 = fmin(cond2->b1[i], cond2->b2[i]);
300 const double u1 = fmax(cond1->b1[i], cond1->b2[i]);
301 const double u2 = fmax(cond2->b1[i], cond2->b2[i]);
302 if (l1 > l2 || u1 < u2) {
303 return false;
304 }
305 }
306 }
307 return true;
308}
309
315void
316cond_rectangle_print(const struct XCSF *xcsf, const struct Cl *c)
317{
318 char *json_str = cond_rectangle_json_export(xcsf, c);
319 printf("%s\n", json_str);
320 free(json_str);
321}
322
329double
330cond_rectangle_size(const struct XCSF *xcsf, const struct Cl *c)
331{
332 (void) c;
333 return xcsf->x_dim;
334}
335
343size_t
344cond_rectangle_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
345{
346 size_t s = 0;
347 const struct CondRectangle *cond = c->cond;
348 s += fwrite(cond->b1, sizeof(double), xcsf->x_dim, fp);
349 s += fwrite(cond->b2, sizeof(double), xcsf->x_dim, fp);
350 s += fwrite(cond->mu, sizeof(double), N_MU, fp);
351 return s;
352}
353
361size_t
362cond_rectangle_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
363{
364 size_t s = 0;
365 struct CondRectangle *new = malloc(sizeof(struct CondRectangle));
366 new->b1 = malloc(sizeof(double) * xcsf->x_dim);
367 new->b2 = malloc(sizeof(double) * xcsf->x_dim);
368 new->mu = malloc(sizeof(double) * N_MU);
369 s += fread(new->b1, sizeof(double), xcsf->x_dim, fp);
370 s += fread(new->b2, sizeof(double), xcsf->x_dim, fp);
371 s += fread(new->mu, sizeof(double), N_MU, fp);
372 c->cond = new;
373 return s;
374}
375
382char *
383cond_rectangle_json_export(const struct XCSF *xcsf, const struct Cl *c)
384{
385 const struct CondRectangle *cond = c->cond;
386 cJSON *json = cJSON_CreateObject();
387 cJSON *b1 = cJSON_CreateDoubleArray(cond->b1, xcsf->x_dim);
388 cJSON *b2 = cJSON_CreateDoubleArray(cond->b2, xcsf->x_dim);
389 cJSON *mutation = cJSON_CreateDoubleArray(cond->mu, N_MU);
390 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
391 cJSON_AddStringToObject(json, "type", "hyperrectangle_csr");
392 cJSON_AddItemToObject(json, "center", b1);
393 cJSON_AddItemToObject(json, "spread", b2);
394 } else {
395 cJSON_AddStringToObject(json, "type", "hyperrectangle_ubr");
396 cJSON_AddItemToObject(json, "bound1", b1);
397 cJSON_AddItemToObject(json, "bound2", b2);
398 }
399 cJSON_AddItemToObject(json, "mutation", mutation);
400 char *string = cJSON_Print(json);
401 cJSON_Delete(json);
402 return string;
403}
404
411void
412cond_rectangle_json_import(const struct XCSF *xcsf, struct Cl *c,
413 const cJSON *json)
414{
415 struct CondRectangle *cond = c->cond;
416 bool csr = false;
417 if (xcsf->cond->type == COND_TYPE_HYPERRECTANGLE_CSR) {
418 csr = true;
419 }
420 const char *b1_name = csr ? "center" : "bound1";
421 const char *b2_name = csr ? "spread" : "bound2";
422 const cJSON *item = cJSON_GetObjectItem(json, b1_name);
423 if (item != NULL && cJSON_IsArray(item)) {
424 if (cJSON_GetArraySize(item) == xcsf->x_dim) {
425 for (int i = 0; i < xcsf->x_dim; ++i) {
426 const cJSON *item_i = cJSON_GetArrayItem(item, i);
427 cond->b1[i] = item_i->valuedouble;
428 }
429 } else {
430 printf("Import error: %s length mismatch\n", b1_name);
431 exit(EXIT_FAILURE);
432 }
433 }
434 item = cJSON_GetObjectItem(json, b2_name);
435 if (item != NULL && cJSON_IsArray(item)) {
436 if (cJSON_GetArraySize(item) == xcsf->x_dim) {
437 for (int i = 0; i < xcsf->x_dim; ++i) {
438 const cJSON *item_i = cJSON_GetArrayItem(item, i);
439 cond->b2[i] = item_i->valuedouble;
440 }
441 } else {
442 printf("Import error: %s length mismatch\n", b2_name);
443 exit(EXIT_FAILURE);
444 }
445 }
446 sam_json_import(cond->mu, N_MU, json);
447}
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.
char * cond_rectangle_json_export(const struct XCSF *xcsf, const struct Cl *c)
Returns a json formatted string representation of a hyperrectangle.
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.
static const int MU_TYPE[2]
Self-adaptation method for mutating hyperrectangles.
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.
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