XCSF 1.4.8
XCSF learning classifier system
Loading...
Searching...
No Matches
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
34static const int MU_TYPE[N_MU] = {
36};
37
43void
44pred_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
78void
79pred_nlms_copy(const struct XCSF *xcsf, struct Cl *dest, const struct Cl *src)
80{
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
95void
96pred_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
114void
115pred_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
137void
138pred_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
154void
155pred_nlms_print(const struct XCSF *xcsf, const struct Cl *c)
156{
158 printf("%s\n", json_str);
159 free(json_str);
160}
161
169bool
170pred_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
185bool
186pred_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
207double
208pred_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
222size_t
223pred_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
243size_t
244pred_nlms_load(const struct XCSF *xcsf, struct Cl *c, FILE *fp)
245{
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
263char *
264pred_nlms_json_export(const struct XCSF *xcsf, const struct Cl *c)
265{
266 const struct PredNLMS *pred = c->pred;
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 }
275 cJSON_AddNumberToObject(json, "eta", pred->eta);
277 cJSON_AddItemToObject(json, "mutation", mutation);
278 char *string = cJSON_Print(json);
280 return string;
281}
282
289void
290pred_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");
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
318char *
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
340char *
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.
static const int MU_TYPE[(1)]
Self-adaptation method for mutating NLMS predictions.
Definition pred_nlms.c:34
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_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
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
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
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
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