XCSF  1.4.7
XCSF learning classifier system
pred_nlms.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 "pred_nlms.h"
25 #include "blas.h"
26 #include "sam.h"
27 #include "utils.h"
28 
29 #define N_MU (1)
30 
34 static const int MU_TYPE[N_MU] = {
36 };
37 
43 void
44 pred_nlms_init(const struct XCSF *xcsf, struct Cl *c)
45 {
46  struct PredNLMS *pred = malloc(sizeof(struct PredNLMS));
47  c->pred = pred;
48  // set the length of weights per predicted variable
49  if (xcsf->pred->type == PRED_TYPE_NLMS_QUADRATIC) {
50  // offset(1) + n linear + n quadratic + n*(n-1)/2 mixed terms
51  pred->n = 1 + 2 * xcsf->x_dim + xcsf->x_dim * (xcsf->x_dim - 1) / 2;
52  } else {
53  pred->n = xcsf->x_dim + 1;
54  }
55  // initialise weights
56  pred->n_weights = pred->n * xcsf->y_dim;
57  pred->weights = calloc(pred->n_weights, sizeof(double));
58  blas_fill(xcsf->y_dim, xcsf->pred->x0, pred->weights, pred->n);
59  // initialise learning rate
60  pred->mu = malloc(sizeof(double) * N_MU);
61  if (xcsf->pred->evolve_eta) {
62  sam_init(pred->mu, N_MU, MU_TYPE);
63  pred->eta = rand_uniform(xcsf->pred->eta_min, xcsf->pred->eta);
64  } else {
65  memset(pred->mu, 0, sizeof(double) * N_MU);
66  pred->eta = xcsf->pred->eta;
67  }
68  // initialise temporary storage for weight updating
69  pred->tmp_input = malloc(sizeof(double) * pred->n);
70 }
71 
78 void
79 pred_nlms_copy(const struct XCSF *xcsf, struct Cl *dest, const struct Cl *src)
80 {
81  pred_nlms_init(xcsf, dest);
82  struct PredNLMS *dest_pred = dest->pred;
83  const struct PredNLMS *src_pred = src->pred;
84  memcpy(dest_pred->weights, src_pred->weights,
85  sizeof(double) * src_pred->n_weights);
86  memcpy(dest_pred->mu, src_pred->mu, sizeof(double) * N_MU);
87  dest_pred->eta = src_pred->eta;
88 }
89 
95 void
96 pred_nlms_free(const struct XCSF *xcsf, const struct Cl *c)
97 {
98  (void) xcsf;
99  struct PredNLMS *pred = c->pred;
100  free(pred->weights);
101  free(pred->tmp_input);
102  free(pred->mu);
103  free(pred);
104 }
105 
114 void
115 pred_nlms_update(const struct XCSF *xcsf, const struct Cl *c, const double *x,
116  const double *y)
117 {
118  const struct PredNLMS *pred = c->pred;
119  // normalise update
120  const int n = pred->n;
121  const double X0 = xcsf->pred->x0;
122  const double norm = X0 * X0 + blas_dot(xcsf->x_dim, x, 1, x, 1);
123  // update weights using the error
124  for (int i = 0; i < xcsf->y_dim; ++i) {
125  const double error = y[i] - c->prediction[i];
126  const double correction = (pred->eta * error) / norm;
127  blas_axpy(n, correction, pred->tmp_input, 1, &pred->weights[i * n], 1);
128  }
129 }
130 
137 void
138 pred_nlms_compute(const struct XCSF *xcsf, const struct Cl *c, const double *x)
139 {
140  const struct PredNLMS *pred = c->pred;
141  const int n = pred->n;
142  pred_transform_input(xcsf, x, xcsf->pred->x0, pred->tmp_input);
143  for (int i = 0; i < xcsf->y_dim; ++i) {
144  c->prediction[i] =
145  blas_dot(n, &pred->weights[i * n], 1, pred->tmp_input, 1);
146  }
147 }
148 
154 void
155 pred_nlms_print(const struct XCSF *xcsf, const struct Cl *c)
156 {
157  char *json_str = pred_nlms_json_export(xcsf, c);
158  printf("%s\n", json_str);
159  free(json_str);
160 }
161 
169 bool
170 pred_nlms_crossover(const struct XCSF *xcsf, const struct Cl *c1,
171  const struct Cl *c2)
172 {
173  (void) xcsf;
174  (void) c1;
175  (void) c2;
176  return false;
177 }
178 
185 bool
186 pred_nlms_mutate(const struct XCSF *xcsf, const struct Cl *c)
187 {
188  if (xcsf->pred->evolve_eta) {
189  struct PredNLMS *pred = c->pred;
190  sam_adapt(pred->mu, N_MU, MU_TYPE);
191  const double orig = pred->eta;
192  pred->eta += rand_normal(0, pred->mu[0]);
193  pred->eta = clamp(pred->eta, xcsf->pred->eta_min, xcsf->pred->eta);
194  if (orig != pred->eta) {
195  return true;
196  }
197  }
198  return false;
199 }
200 
207 double
208 pred_nlms_size(const struct XCSF *xcsf, const struct Cl *c)
209 {
210  (void) xcsf;
211  const struct PredNLMS *pred = c->pred;
212  return pred->n_weights;
213 }
214 
222 size_t
223 pred_nlms_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
224 {
225  (void) xcsf;
226  const struct PredNLMS *pred = c->pred;
227  size_t s = 0;
228  s += fwrite(&pred->n, sizeof(int), 1, fp);
229  s += fwrite(&pred->n_weights, sizeof(int), 1, fp);
230  s += fwrite(pred->weights, sizeof(double), pred->n_weights, fp);
231  s += fwrite(pred->mu, sizeof(double), N_MU, fp);
232  s += fwrite(&pred->eta, sizeof(double), 1, fp);
233  return s;
234 }
235 
243 size_t
244 pred_nlms_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
245 {
246  pred_nlms_init(xcsf, c);
247  struct PredNLMS *pred = c->pred;
248  size_t s = 0;
249  s += fread(&pred->n, sizeof(int), 1, fp);
250  s += fread(&pred->n_weights, sizeof(int), 1, fp);
251  s += fread(pred->weights, sizeof(double), pred->n_weights, fp);
252  s += fread(pred->mu, sizeof(double), N_MU, fp);
253  s += fread(&pred->eta, sizeof(double), 1, fp);
254  return s;
255 }
256 
263 char *
264 pred_nlms_json_export(const struct XCSF *xcsf, const struct Cl *c)
265 {
266  const struct PredNLMS *pred = c->pred;
267  cJSON *json = cJSON_CreateObject();
268  if (xcsf->pred->type == PRED_TYPE_NLMS_QUADRATIC) {
269  cJSON_AddStringToObject(json, "type", "nlms_quadratic");
270  } else {
271  cJSON_AddStringToObject(json, "type", "nlms_linear");
272  }
273  cJSON *weights = cJSON_CreateDoubleArray(pred->weights, pred->n_weights);
274  cJSON_AddItemToObject(json, "weights", weights);
275  cJSON_AddNumberToObject(json, "eta", pred->eta);
276  cJSON *mutation = cJSON_CreateDoubleArray(pred->mu, N_MU);
277  cJSON_AddItemToObject(json, "mutation", mutation);
278  char *string = cJSON_Print(json);
279  cJSON_Delete(json);
280  return string;
281 }
282 
289 void
290 pred_nlms_json_import(const struct XCSF *xcsf, struct Cl *c, const cJSON *json)
291 {
292  (void) xcsf;
293  struct PredNLMS *pred = c->pred;
294  const cJSON *item = cJSON_GetObjectItem(json, "weights");
295  if (item != NULL && cJSON_IsArray(item)) {
296  if (cJSON_GetArraySize(item) == pred->n_weights) {
297  for (int i = 0; i < pred->n_weights; ++i) {
298  const cJSON *item_i = cJSON_GetArrayItem(item, i);
299  pred->weights[i] = item_i->valuedouble;
300  }
301  } else {
302  printf("Import error: weight length mismatch\n");
303  exit(EXIT_FAILURE);
304  }
305  }
306  item = cJSON_GetObjectItem(json, "eta");
307  if (item != NULL && cJSON_IsNumber(item)) {
308  pred->eta = item->valuedouble;
309  }
310  sam_json_import(pred->mu, N_MU, json);
311 }
312 
318 char *
320 {
321  const struct ArgsPred *pred = xcsf->pred;
322  cJSON *json = cJSON_CreateObject();
323  cJSON_AddNumberToObject(json, "x0", pred->x0);
324  cJSON_AddNumberToObject(json, "eta", pred->eta);
325  cJSON_AddBoolToObject(json, "evolve_eta", pred->evolve_eta);
326  if (pred->evolve_eta) {
327  cJSON_AddNumberToObject(json, "eta_min", pred->eta_min);
328  }
329  char *string = cJSON_Print(json);
330  cJSON_Delete(json);
331  return string;
332 }
333 
340 char *
341 pred_nlms_param_json_import(struct XCSF *xcsf, cJSON *json)
342 {
343  for (cJSON *iter = json; iter != NULL; iter = iter->next) {
344  if (strncmp(iter->string, "x0\0", 3) == 0 && cJSON_IsNumber(iter)) {
345  pred_param_set_x0(xcsf, iter->valuedouble);
346  } else if (strncmp(iter->string, "eta\0", 4) == 0 &&
347  cJSON_IsNumber(iter)) {
348  pred_param_set_eta(xcsf, iter->valuedouble);
349  } else if (strncmp(iter->string, "evolve_eta\0", 11) == 0 &&
350  cJSON_IsBool(iter)) {
351  const bool evolve = true ? iter->type == cJSON_True : false;
353  } else if (strncmp(iter->string, "eta_min\0", 8) == 0 &&
354  cJSON_IsNumber(iter)) {
355  pred_param_set_eta_min(xcsf, iter->valuedouble);
356  } else {
357  return iter->string;
358  }
359  }
360  return NULL;
361 }
void blas_fill(const int N, const double ALPHA, double *X, const int INCX)
Fills the vector X with the value ALPHA.
Definition: blas.c:181
double blas_dot(const int N, const double *X, const int INCX, const double *Y, const int INCY)
Computes the dot product of two vectors.
Definition: blas.c:198
void blas_axpy(const int N, const double ALPHA, const double *X, const int INCX, double *Y, const int INCY)
Multiplies vector X by the scalar ALPHA and adds it to the vector Y.
Definition: blas.c:138
Basic linear algebra functions.
Definition: __init__.py:1
static const int MU_TYPE[(1)]
Self-adaptation method for mutating NLMS predictions.
Definition: pred_nlms.c:34
void pred_nlms_json_import(const struct XCSF *xcsf, struct Cl *c, const cJSON *json)
Creates an NLMS prediction from a cJSON object.
Definition: pred_nlms.c:290
char * pred_nlms_param_json_export(const struct XCSF *xcsf)
Returns a json formatted string of the NLMS parameters.
Definition: pred_nlms.c:319
void pred_nlms_compute(const struct XCSF *xcsf, const struct Cl *c, const double *x)
Computes the current NLMS prediction for a provided input.
Definition: pred_nlms.c:138
char * pred_nlms_json_export(const struct XCSF *xcsf, const struct Cl *c)
Returns a json formatted string representation of an NLMS prediction.
Definition: pred_nlms.c:264
size_t pred_nlms_save(const struct XCSF *xcsf, const struct Cl *c, FILE *fp)
Writes an NLMS prediction to a file.
Definition: pred_nlms.c:223
bool pred_nlms_crossover(const struct XCSF *xcsf, const struct Cl *c1, const struct Cl *c2)
Dummy function since NLMS predictions do not perform crossover.
Definition: pred_nlms.c:170
#define N_MU
Number of self-adaptive mutation rates.
Definition: pred_nlms.c:29
void pred_nlms_print(const struct XCSF *xcsf, const struct Cl *c)
Prints an NLMS prediction.
Definition: pred_nlms.c:155
void pred_nlms_init(const struct XCSF *xcsf, struct Cl *c)
Initialises an NLMS prediction.
Definition: pred_nlms.c:44
void pred_nlms_free(const struct XCSF *xcsf, const struct Cl *c)
Frees the memory used by an NLMS prediction.
Definition: pred_nlms.c:96
bool pred_nlms_mutate(const struct XCSF *xcsf, const struct Cl *c)
Mutates the gradient descent rate used to update an NLMS prediction.
Definition: pred_nlms.c:186
double pred_nlms_size(const struct XCSF *xcsf, const struct Cl *c)
Returns the size of an NLMS prediction.
Definition: pred_nlms.c:208
void pred_nlms_update(const struct XCSF *xcsf, const struct Cl *c, const double *x, const double *y)
Updates an NLMS prediction for a given input and truth sample.
Definition: pred_nlms.c:115
char * pred_nlms_param_json_import(struct XCSF *xcsf, cJSON *json)
Sets the NLMS parameters from a cJSON object.
Definition: pred_nlms.c:341
void pred_nlms_copy(const struct XCSF *xcsf, struct Cl *dest, const struct Cl *src)
Copies an NLMS prediction from one classifier to another.
Definition: pred_nlms.c:79
size_t pred_nlms_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
Reads an NLMS prediction from a file.
Definition: pred_nlms.c:244
Normalised least mean squares prediction functions.
void pred_param_set_x0(struct XCSF *xcsf, const double a)
Definition: prediction.c:331
void pred_param_set_eta_min(struct XCSF *xcsf, const double a)
Definition: prediction.c:305
void pred_param_set_evolve_eta(struct XCSF *xcsf, const bool a)
Definition: prediction.c:337
void pred_param_set_eta(struct XCSF *xcsf, const double a)
Definition: prediction.c:291
void pred_transform_input(const struct XCSF *xcsf, const double *x, const double X0, double *tmp_input)
Prepares the input state for least squares computation.
Definition: prediction.c:265
#define PRED_TYPE_NLMS_QUADRATIC
Prediction type quadratic nlms.
Definition: prediction.h:31
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
Parameters for initialising and operating predictions.
Definition: prediction.h:50
double eta_min
Minimum gradient descent rate.
Definition: prediction.h:54
bool evolve_eta
Whether to evolve the gradient descent rate.
Definition: prediction.h:52
double x0
Prediction weight vector offset value.
Definition: prediction.h:57
double eta
Gradient descent rate.
Definition: prediction.h:53
Classifier data structure.
Definition: xcsf.h:45
void * pred
Prediction structure.
Definition: xcsf.h:50
double * prediction
Current classifier prediction.
Definition: xcsf.h:59
Normalised least mean squares prediction data structure.
Definition: pred_nlms.h:32
double * mu
Mutation rates.
Definition: pred_nlms.h:36
int n_weights
Total number of weights.
Definition: pred_nlms.h:34
double * tmp_input
Temporary storage for updating weights.
Definition: pred_nlms.h:38
int n
Number of weights for each predicted variable.
Definition: pred_nlms.h:33
double eta
Gradient descent rate.
Definition: pred_nlms.h:37
double * weights
Weights used to compute prediction.
Definition: pred_nlms.h:35
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