XCSF 1.4.8
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 (1)
30
34static const int MU_TYPE[N_MU] = { 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 sam_init(new->mu, N_MU, MU_TYPE);
60 c->cond = new;
61}
62
68void
69cond_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
85void
86cond_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
106void
107cond_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
134void
135cond_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
155bool
156cond_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
187bool
188cond_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
219bool
220cond_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
255bool
256cond_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
290void
291cond_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
304double
305cond_rectangle_size(const struct XCSF *xcsf, const struct Cl *c)
306{
307 (void) c;
308 return xcsf->x_dim;
309}
310
318size_t
319cond_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
336size_t
337cond_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
357char *
358cond_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
386void
387cond_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.
char * cond_rectangle_json_export(const struct XCSF *xcsf, const struct Cl *c)
Returns a json formatted string representation of a hyperrectangle.
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.
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