libfgen  0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
ffit.c
00001 /*
00002     ffit.c -- ffit functionality.
00003 
00004     fgen -- Library for optimization using a genetic algorithm or particle swarm optimization.
00005     Copyright 2012, Harm Hanemaaijer
00006 
00007     This file is part of fgen.
00008 
00009     fgen is free software: you can redistribute it and/or modify it
00010     under the terms of the GNU Lesser General Public License as published
00011     by the Free Software Foundation, either version 3 of the License, or
00012     (at your option) any later version.
00013 
00014     fgen is distributed in the hope that it will be useful, but WITHOUT
00015     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00017     License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public
00020     License along with fgen.  If not, see <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 /*
00025  * Ffit functionality.
00026  */
00027 
00028 #include <stdlib.h>
00029 #include <stdint.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #ifndef __GNUC__
00033 #define _USE_MATH_DEFINES
00034 #endif
00035 #include <math.h>
00036 #include <limits.h>
00037 #include <malloc.h>
00038 #include "fgen.h"
00039 
00040 static void ffit_fgen_generation_callback(FgenPopulation *pop, int generation);
00041 static void ffit_fgen_archipelago_generation_callback(FgenPopulation *pop, int generation);
00042 static double ffit_fgen_calculate_fitness(const FgenPopulation *pop, const unsigned char *bitstring);
00043 static void ffit_fgen_extract_parameters(const Ffit *fit, const FgenPopulation *pop, const unsigned
00044 char *bitstring, double *param);
00045 // static void ffit_fgen_hill_climb(Ffit *fit, FgenPopulation *pop);
00046 static double ffit_map_parameter(const Ffit *fit, int i, double f);
00047 static void ffit_fgen_real_valued_seed(FgenPopulation *pop, unsigned char *bitstring);
00048 static void ffit_fgen_real_valued_mutation(FgenPopulation *pop, const unsigned char *parent, unsigned char *child);
00049 static void ffit_fgen_real_valued_crossover(FgenPopulation *pop, const unsigned char *parent1, const unsigned char *parent2,
00050 unsigned char *child1, unsigned char *child2);
00051 static void ffit_fpso_generation_callback(FpsoPopulation *pop, int generation);
00052 static double ffit_fpso_calculate_error(const FpsoPopulation *pop, const double *params);
00053 
00065 Ffit *ffit_create(int nu_params, FfitGenerationCallbackFunc generation_callback_func,
00066 FfitCalculateErrorFunc calculate_error_func) {
00067         Ffit *fit = (Ffit *)malloc(sizeof(Ffit));
00068         fit->nu_params = nu_params;
00069         fit->ffit_generation_callback_func = generation_callback_func;
00070         fit->ffit_calculate_error_func = calculate_error_func;
00071         fit->range_min = (double *)malloc(sizeof(double) * nu_params);
00072         fit->range_max = (double *)malloc(sizeof(double) * nu_params);
00073         fit->mapping = (int *)malloc(sizeof(int) * nu_params);
00074         fit->threading_level = FFIT_THREADING_DISABLED;
00075         fit->generation_callback_interval = 1;
00076         return fit;
00077 }
00078 
00094 void ffit_set_parameter_range_and_mapping(Ffit *fit, int index, double range_min, double range_max, int mapping) {
00095         fit->range_min[index] = range_min;
00096         fit->range_max[index] = range_max;
00097         fit->mapping[index] = mapping;
00098 }
00099 
00114 void ffit_run_fgen_with_defaults(Ffit *fit) {
00115         ffit_run_fgen(fit, 1024, 32, FGEN_ELITIST_SUS, fgen_crossover_uniform_per_element, 0.9, 0.015, 0.050);
00116 }
00117 
00133 void ffit_run_fgen(Ffit *fit, int population_size, int nu_bits_per_param, int selection_type,
00134 FgenCrossoverFunc crossover, float crossover_probability_float, float mutation_per_bit_probability_float,
00135 float macro_mutation_probability_float) {
00136         FgenPopulation *pop;
00137         pop = fgen_create(
00138                 population_size,                                /* Population size. */
00139                 fit->nu_params * nu_bits_per_param,             /* Individual size in bits. */
00140                 nu_bits_per_param,                              /* Data element size. */
00141                 ffit_fgen_generation_callback,
00142                 ffit_fgen_calculate_fitness,
00143                 fgen_seed_random,
00144                 fgen_mutation_per_bit_plus_macro_mutation_fast,
00145                 crossover);
00146         fgen_random_seed_with_timer(pop->rng);
00147         fgen_set_parameters(
00148                 pop,
00149                 selection_type,                 /* Selection type. */
00150                 FGEN_SUBTRACT_MIN_FITNESS,      /* Selection fitness type. */
00151                 crossover_probability_float,    /* Crossover probability. */
00152                 mutation_per_bit_probability_float,     /* Mutation probability per bit. */
00153                 macro_mutation_probability_float);      /* Macro-mutation probability. */
00154         fgen_set_generation_callback_interval(pop, fit->generation_callback_interval);
00155         fgen_set_user_data(pop, fit);
00156         fit->population_size = population_size;
00157         fit->nu_bits_per_param = nu_bits_per_param;
00158         fit->optimization_type = FFIT_OPTIMIZATION_FGEN;
00159         fit->stop_signalled = 0;
00160         fit->model_change_signalled = 0;
00161         fit->population = pop;
00162         if (fit->threading_level >= FFIT_THREADING_ENABLED)
00163                 fgen_run_threaded(pop, - 1);
00164         else
00165                 fgen_run(pop, - 1);
00166 }
00167 
00181 void ffit_run_fgen_real_valued(Ffit *fit, int population_size, int selection_type,
00182 float crossover_probability_float, float mutation_per_element_probability_float,
00183 float macro_mutation_probability_float) {
00184         FgenPopulation *pop;
00185         pop = fgen_create(
00186                 population_size,                                /* Population size. */
00187                 fit->nu_params * 64,                            /* Individual size in bits. */
00188                 64,                                             /* Data element size. */
00189                 ffit_fgen_generation_callback,
00190                 ffit_fgen_calculate_fitness,
00191                 ffit_fgen_real_valued_seed,
00192                 ffit_fgen_real_valued_mutation,
00193                 ffit_fgen_real_valued_crossover);
00194         fgen_random_seed_with_timer(pop->rng);
00195         fgen_set_parameters(
00196                 pop,
00197                 selection_type,                 /* Selection type. */
00198                 FGEN_SUBTRACT_MIN_FITNESS,      /* Selection fitness type. */
00199                 crossover_probability_float,    /* Crossover probability. */
00200                 mutation_per_element_probability_float, /* Mutation probability per data element. */
00201                 macro_mutation_probability_float);      /* Macro-mutation probability. */
00202         fgen_set_generation_callback_interval(pop, fit->generation_callback_interval);
00203         fgen_set_user_data(pop, fit);
00204         fit->population_size = population_size;
00205         fit->optimization_type = FFIT_OPTIMIZATION_FGEN_REAL_VALUED;
00206         fit->stop_signalled = 0;
00207         fit->model_change_signalled = 0;
00208         fit->population = pop;
00209         if (fit->threading_level >= FFIT_THREADING_ENABLED)
00210                 fgen_run_threaded(pop, - 1);
00211         else
00212                 fgen_run(pop, - 1);
00213 }
00214 
00215 #if 0
00216 
00217 void ffit_run_fgen_with_hill_climb(Ffit *fit, int population_size, int nu_bits_per_param, int selection_type, FgenCrossoverFunc crossover, float crossover_probability_float, float mutation_per_bit_probability_float, float macro_mutation_probability_float) {
00218         FgenPopulation *pop;
00219         pop = fgen_create(
00220                 population_size,                                /* Population size. */
00221                 fit->nu_params * nu_bits_per_param,             /* Individual size in bits. */
00222                 nu_bits_per_param,                              /* Data element size. */
00223                 ffit_fgen_generation_callback,
00224                 ffit_fgen_calculate_fitness,
00225                 fgen_seed_random,
00226                 fgen_mutation_per_bit_plus_macro_mutation,
00227                 crossover);
00228         fgen_random_seed_with_timer(pop->rng);
00229         fgen_set_parameters(
00230                 pop,
00231                 selection_type,                 /* Selection type. */
00232                 FGEN_SUBTRACT_MIN_FITNESS,      /* Selection fitness type. */
00233                 crossover_probability_float,    /* Crossover probability. */
00234                 mutation_per_bit_probability_float,     /* Mutation probability per bit. */
00235                 macro_mutation_probability_float);      /* Macro-mutation probability. */
00236         fgen_set_generation_callback_interval(pop, fit->generation_callback_interval);
00237         fgen_set_user_data(pop, fit);
00238         fit->population_size = population_size;
00239         fit->nu_bits_per_param = nu_bits_per_param;
00240         fit->optimization_type = FFIT_OPTIMIZATION_FGEN_WITH_HILL_CLIMB;
00241         fit->stop_signalled = 0;
00242         fit->population = pop;
00243         if (fit->threading_level >= FFIT_THREADING_ENABLED)
00244                 fgen_run_threaded(pop, INT_MAX);
00245         else
00246                 fgen_run(pop, INT_MAX);
00247 }
00248 
00249 #endif
00250 
00270 void ffit_run_fgen_archipelago(Ffit *fit, int nu_islands, int population_size,
00271 int nu_bits_per_param, int selection_type, FgenCrossoverFunc crossover, float
00272 crossover_probability_float, float mutation_probability_float, float macro_mutation_probability_float,
00273 float migration_probability_float, int migration_interval) {
00274         FgenPopulation **pops;
00275         int i;
00276         pops = (FgenPopulation **)malloc(sizeof(FgenPopulation *) * nu_islands);
00277         for (i = 0; i < nu_islands; i++) {
00278                 pops[i] = fgen_create(
00279                         population_size,                                /* Population size. */
00280                         fit->nu_params * nu_bits_per_param,             /* Individual size in bits. */
00281                         nu_bits_per_param,                              /* Data element size. */
00282                         ffit_fgen_archipelago_generation_callback,
00283                         ffit_fgen_calculate_fitness,
00284                         fgen_seed_random,
00285                         fgen_mutation_per_bit_plus_macro_mutation_fast,
00286                         crossover);
00287                 fgen_set_parameters(
00288                         pops[i],
00289                         selection_type,                 /* Selection type. */
00290                         FGEN_SUBTRACT_MIN_FITNESS,      /* Selection fitness type. */
00291                         crossover_probability_float,    /* Crossover probability. */
00292                         mutation_probability_float,     /* Mutation probability per bit. */
00293                         macro_mutation_probability_float);      /* Macro-mutation probability. */
00294                 fgen_set_migration_probability(pops[i], migration_probability_float);
00295                 fgen_set_migration_interval(pops[i], migration_interval);
00296                 fgen_set_generation_callback_interval(pops[i], fit->generation_callback_interval);
00297                 fgen_set_user_data(pops[i], fit);
00298         }
00299         fgen_random_seed_with_timer(pops[0]->rng);
00300         fit->population_size = population_size;
00301         fit->nu_bits_per_param = nu_bits_per_param;
00302         fit->optimization_type = FFIT_OPTIMIZATION_FGEN_ARCHIPELAGO;
00303         fit->stop_signalled = 0;
00304         fit->population = pops;
00305         fit->nu_islands = nu_islands;
00306         fit->best_island_params = (double *)malloc(sizeof(double) * fit->nu_params); 
00307         if (fit->threading_level >= FFIT_THREADING_ENABLED)
00308                 fgen_run_archipelago_threaded(nu_islands, pops, - 1);
00309         else
00310                 fgen_run_archipelago(nu_islands, pops, - 1);
00311 }
00312 
00328 void ffit_run_fgen_real_valued_archipelago(Ffit *fit, int nu_islands, int population_size,
00329 int selection_type, float crossover_probability_float, float mutation_probability_float,
00330 float macro_mutation_probability_float, float migration_probability_float, int migration_interval) {
00331         FgenPopulation **pops;
00332         int i;
00333         pops = (FgenPopulation **)malloc(sizeof(FgenPopulation *) * nu_islands);
00334         for (i = 0; i < nu_islands; i++) {
00335                 pops[i] = fgen_create(
00336                         population_size,                                /* Population size. */
00337                         fit->nu_params * 64,                            /* Individual size in bits. */
00338                         64,                                             /* Data element size. */
00339                         ffit_fgen_archipelago_generation_callback,
00340                         ffit_fgen_calculate_fitness,
00341                         ffit_fgen_real_valued_seed,
00342                         ffit_fgen_real_valued_mutation,
00343                         ffit_fgen_real_valued_crossover);
00344                 fgen_set_parameters(
00345                         pops[i],
00346                         selection_type,                 /* Selection type. */
00347                         FGEN_SUBTRACT_MIN_FITNESS,      /* Selection fitness type. */
00348                         crossover_probability_float,    /* Crossover probability. */
00349                         mutation_probability_float,     /* Mutation probability per element. */
00350                         macro_mutation_probability_float);      /* Macro-mutation probability. */
00351                 fgen_set_migration_probability(pops[i], migration_probability_float);
00352                 fgen_set_migration_interval(pops[i], migration_interval);
00353                 fgen_set_generation_callback_interval(pops[i], fit->generation_callback_interval);
00354                 fgen_set_user_data(pops[i], fit);
00355         }
00356         fgen_random_seed_with_timer(pops[0]->rng);
00357         fit->population_size = population_size;
00358         fit->optimization_type = FFIT_OPTIMIZATION_FGEN_REAL_VALUED_ARCHIPELAGO;
00359         fit->stop_signalled = 0;
00360         fit->population = pops;
00361         fit->nu_islands = nu_islands;
00362         fit->best_island_params = (double *)malloc(sizeof(double) * fit->nu_params); 
00363         if (fit->threading_level >= FFIT_THREADING_ENABLED)
00364                 fgen_run_archipelago_threaded(nu_islands, pops, - 1);
00365         else
00366                 fgen_run_archipelago(nu_islands, pops, - 1);
00367 }
00368 
00385 void ffit_run_fpso(Ffit *fit, int population_size, int topology, int bounding_strategy,
00386 double omega, double phi1, double phi2) {
00387         FpsoPopulation *pop;
00388         int i;
00389         pop = fpso_create(
00390                 population_size,
00391                 fit->nu_params,
00392                 ffit_fpso_generation_callback,
00393                 ffit_fpso_calculate_error);
00394         fgen_random_seed_with_timer(pop->rng);
00395         fpso_set_parameters(
00396                 pop,
00397                 topology,
00398                 bounding_strategy,
00399                 omega,
00400                 phi1,
00401                 phi2);
00402         /* Use normalized parameter values. */
00403         for (i = 0; i < pop->nu_params; i++)
00404                 fpso_set_parameter_bounds(pop, i, 0, 1.0);
00405         fpso_set_user_data(pop, fit);
00406         fit->population_size = population_size;
00407         fit->optimization_type = FFIT_OPTIMIZATION_FPSO;
00408         fit->stop_signalled = 0;
00409         fit->model_change_signalled = 0;
00410         fit->population = pop;
00411         fpso_run(pop, - 1);
00412 }
00413 
00420 void ffit_destroy(Ffit *fit) {
00421         if ((fit->optimization_type & FFIT_OPTIMIZATION_FGEN_ELEMENT)
00422         && !(fit->optimization_type & FFIT_OPTIMIZATION_ARCHIPELAGO_ELEMENT))
00423                 fgen_destroy((FgenPopulation *)fit->population);
00424         if (fit->optimization_type & FFIT_OPTIMIZATION_ARCHIPELAGO_ELEMENT) {
00425                 int i;
00426                 for (i = 0; i < fit->nu_islands; i++) {
00427                     FgenPopulation **pops = (FgenPopulation **)fit->population;
00428                     fgen_destroy(pops[i]);
00429                 }
00430                 free(fit->best_island_params);
00431         }
00432         if (fit->optimization_type & FFIT_OPTIMIZATION_FPSO)
00433                 fpso_destroy((FpsoPopulation *)fit->population);
00434         free(fit->range_min);
00435         free(fit->range_max);
00436         free(fit->mapping);
00437         free(fit);
00438 }
00439 
00446 int ffit_get_population_size(const Ffit *fit) {
00447         if (!(fit->optimization_type & FFIT_OPTIMIZATION_ARCHIPELAGO_ELEMENT))
00448                 return fit->population_size;
00449         /* FFIT_OPTIMIZATION_FGEN_ARCHIPELAGO */
00450         return fit->population_size * fit->nu_islands;
00451 }
00452 
00462 void *ffit_get_population(const Ffit *fit) {
00463         return fit->population;
00464 }
00465 
00475 void ffit_get_individual_params(const Ffit *fit, int index, double *params) {
00476         FgenPopulation **pops;
00477         int island;
00478         if ((fit->optimization_type & FFIT_OPTIMIZATION_FGEN_ELEMENT)
00479         && !(fit->optimization_type & FFIT_OPTIMIZATION_ARCHIPELAGO_ELEMENT)) {
00480                 if (!(fit->optimization_type & FFIT_OPTIMIZATION_FGEN_REAL_VALUED_ELEMENT)) {
00481                         FgenPopulation *pop = (FgenPopulation *)fit->population;
00482                         ffit_fgen_extract_parameters(fit, pop, pop->ind[index]->bitstring, params);
00483                         return;
00484                 }
00485                 /* Real-valued genetic algorithm. */
00486                 FgenPopulation *pop = (FgenPopulation *)fit->population;
00487                 for (int i = 0; i < fit->nu_params; i++)
00488                         params[i] = ffit_map_parameter(fit, i, ((double *)pop->ind[index]->bitstring)[i]);
00489                 return;
00490         }
00491         if (fit->optimization_type & FFIT_OPTIMIZATION_FPSO_ELEMENT) {
00492                 int i;
00493                 FpsoPopulation *pop = (FpsoPopulation *)fit->population;
00494                 for (i = 0; i < pop->nu_params; i++)
00495                         params[i] = ffit_map_parameter(fit, i, pop->ind[index].position[i]);
00496                 return;
00497         }
00498         /* FFIT_OPTIMIZATION_ARCHIPELAGO_ELEMENT set. */
00499         pops = (FgenPopulation **)fit->population;
00500         island = index / fit->population_size;
00501         if (!(fit->optimization_type & FFIT_OPTIMIZATION_FGEN_REAL_VALUED_ELEMENT)) {
00502                 ffit_fgen_extract_parameters(fit, pops[island], pops[island]->ind[index % fit->population_size]->bitstring,
00503                         params);
00504                 return;
00505         }
00506         /* Real-valued genetic algorithm. */
00507         for (int i = 0; i < fit->nu_params; i++)
00508                 params[i] = ffit_map_parameter(fit, i, ((double *)pops[island]->ind[
00509                         index % fit->population_size]->bitstring)[i]); 
00510         return;
00511 }
00512 
00513 double ffit_map_parameter(const Ffit *fit, int i, double f) {
00514         double f2;
00515         switch (fit->mapping[i]) {
00516         case FFIT_MAPPING_LINEAR :
00517                 return (fit->range_max[i] - fit->range_min[i]) * f + fit->range_min[i];
00518         case FFIT_MAPPING_SQUARE :
00519                 return (fit->range_max[i] - fit->range_min[i]) * f * f + fit->range_min[i];
00520         case FFIT_MAPPING_CUBE :
00521                 return (fit->range_max[i] - fit->range_min[i]) * f * f * f + fit->range_min[i];
00522         case FFIT_MAPPING_LOG :
00523                 f2 = log(f * (M_E - 1) + 1);    /* Map to [0, 1[ with log. */
00524                 return (fit->range_max[i] - fit->range_min[i]) * f + fit->range_min[i];
00525         case FFIT_MAPPING_BINOMIAL_1_TO_5 :
00526                 f2 = pow(2, (f * 4) + 1) - 2;   // Map to [0, 30[ with a bias to lower values.
00527                 return f2 * (fit->range_max[i] - fit->range_min[i]) / 30.0 + fit->range_min[i];
00528         case FFIT_MAPPING_BINOMIAL_1_TO_7 :
00529                 f2 = pow(2, (f * 6) + 1) - 2;   // Map to [0, 126[ with a bias to lower values.
00530                 return f2 * (fit->range_max[i] - fit->range_min[i]) / 126.0 + fit->range_min[i];
00531         }
00532         return 0;
00533 }
00534 
00541 void ffit_signal_stop(Ffit *fit) {
00542         fit->stop_signalled = 1;
00543 }
00544 
00550 void ffit_signal_model_change(Ffit *fit) {
00551         fit->model_change_signalled = 1;
00552 }
00553 
00554 
00561 void ffit_set_threading(Ffit *fit, int level) {
00562         fit->threading_level = level;
00563 }
00564 
00571 void ffit_set_generation_callback_interval(Ffit *fit, int interval) {
00572         fit->generation_callback_interval = interval;
00573 }
00574 
00575 /*
00576  * ffit fgen interface.
00577  */
00578 
00579 static void ffit_fgen_extract_parameters(const Ffit *fit, const FgenPopulation *pop,
00580 const unsigned char *bitstring, double *param) {
00581         int i;
00582         unsigned char *decoded;
00583         decoded = (unsigned char *)alloca(pop->individual_size_in_bits / 8);
00584         fgen_decode_from_gray(pop, bitstring, decoded);
00585         memcpy(decoded, bitstring, pop->individual_size_in_bits / 8);
00586         for (i = 0; i < fit->nu_params; i++) {
00587                 double f;
00588                 if (fit->nu_bits_per_param == 32) {
00589                         unsigned int x;
00590                         x = *(unsigned int *)&decoded[i * 4];
00591                         f = (double)x / ((double)pow((double)2, 32));   /* Map to [0, 1[ */
00592                 }
00593                 else
00594                 if (fit->nu_bits_per_param == 16) {
00595                         unsigned short x;
00596                         x = *(unsigned short *)&decoded[i * 2];
00597                         f = (double)x / ((double)pow((double)2, 16));   /* Map to [0, 1[ */
00598                 }
00599                 else {  /* nu_bit_per_param = 64 */
00600                         uint64_t x;
00601                         x = *(uint64_t *)&decoded[i * 8];
00602                         f = (double)x / ((double)pow((double)2, 64));   /* Map to [0, 1[. */
00603                 }
00604                 param[i] = ffit_map_parameter(fit, i, f);
00605         }
00606 //      free(decoded);
00607 }
00608 
00609 /* The following three functions are used by both bitstring and real-valued fgen implementations. */
00610 
00611 static void ffit_fgen_generation_callback(FgenPopulation *pop, int generation) { 
00612         FgenIndividual *best;
00613         Ffit *fit = (Ffit *)pop->user_data;
00614         double *best_param;
00615         double error;
00616 //      if (fit->optimization_type & FFIT_OPTIMIZATION_HILL_CLIMB_ELEMENT)
00617 //              ffit_fgen_hill_climb(fit, pop);
00618         best = fgen_best_individual_of_population(pop);
00619         best_param = (double *)alloca(sizeof(double) * fit->nu_params);
00620         if (!(fit->optimization_type & FFIT_OPTIMIZATION_FGEN_REAL_VALUED_ELEMENT))
00621                 ffit_fgen_extract_parameters(fit, pop, best->bitstring, best_param);
00622         else
00623                 for (int i = 0; i < fit->nu_params; i++)
00624                         best_param[i] = ffit_map_parameter(fit, i, ((double *)best->bitstring)[i]);
00625         error = fit->ffit_calculate_error_func(fit, best_param);
00626         fit->ffit_generation_callback_func(fit, generation, best_param, error);
00627 //      free(best_param);
00628         if (fit->stop_signalled)
00629                 fgen_signal_stop(pop);
00630         if (fit->model_change_signalled) {
00631                 fgen_invalidate_population_fitness(pop);
00632                 fit->model_change_signalled = 0;
00633         }
00634 }
00635 
00636 static void ffit_fgen_archipelago_generation_callback(FgenPopulation *pop, int generation) { 
00637         FgenIndividual *best;
00638         Ffit *fit = (Ffit *)pop->user_data;
00639         double *best_param;
00640         double error;
00641         best = fgen_best_individual_of_population(pop);
00642         best_param = (double *)alloca(sizeof(double) * fit->nu_params);
00643         if (!(fit->optimization_type & FFIT_OPTIMIZATION_FGEN_REAL_VALUED_ELEMENT))
00644                 ffit_fgen_extract_parameters(fit, pop, best->bitstring, best_param);
00645         else
00646                 for (int i = 0; i < fit->nu_params; i++)
00647                         best_param[i] = ffit_map_parameter(fit, i, ((double *)best->bitstring)[i]);
00648         error = fit->ffit_calculate_error_func(fit, best_param);
00649         if (pop->island == 0) {
00650                 fit->best_island_error = error;
00651                 memcpy(fit->best_island_params, best_param, sizeof(double) * fit->nu_params);
00652         }
00653         else
00654                 if (error < fit->best_island_error) {
00655                         fit->best_island_error = error;
00656                         memcpy(fit->best_island_params, best_param, sizeof(double) * fit->nu_params);
00657                 }
00658         if (pop->island == fit->nu_islands - 1) {
00659                 fit->ffit_generation_callback_func(fit, generation, fit->best_island_params,
00660                         fit->best_island_error);
00661                 if (fit->stop_signalled)
00662                         fgen_signal_stop(pop);
00663                 if (fit->model_change_signalled) {
00664                         FgenPopulation **pops = (FgenPopulation **)fit->population;
00665                         for (int i = 0; i < fit->nu_islands; i++)
00666                                 fgen_invalidate_population_fitness(pops[i]);
00667                         fit->model_change_signalled = 0;
00668                 }
00669         }
00670 //      free(best_param);
00671 }
00672 
00673 static double ffit_fgen_calculate_fitness(const FgenPopulation *pop, const unsigned char *bitstring) {
00674         Ffit *fit = (Ffit *)pop->user_data;;
00675         double *param = (double *)alloca(sizeof(double) * fit->nu_params);
00676         double error;
00677         if (!(fit->optimization_type & FFIT_OPTIMIZATION_FGEN_REAL_VALUED_ELEMENT))
00678                 ffit_fgen_extract_parameters(fit, pop, bitstring, param);
00679         else
00680                 for (int i = 0; i < fit->nu_params; i++)
00681                         param[i] = ffit_map_parameter(fit, i, ((double *)bitstring)[i]);
00682         error = fit->ffit_calculate_error_func(fit, param);
00683 //      free(param);
00684         return 1000000 / error;
00685 }
00686 
00687 #if 0
00688 
00689 /*
00690  * ffit hill climbing in normalized parameter space (every parameter has the range [0, 1[).
00691  */
00692 
00693 static void ffit_fgen_extract_normalized_parameters(Ffit *fit, FgenPopulation *pop, unsigned char *bitstring,
00694 double *param) {
00695         int i;
00696         unsigned char *decoded;
00697         decoded = (unsigned char *)malloc(pop->individual_size_in_bits / 8);
00698         fgen_decode_from_gray(pop, bitstring, decoded);
00699         for (i = 0; i < fit->nu_params; i++) {
00700                 if (fit->nu_bits_per_param == 32) {
00701                         unsigned int x;
00702                         x = *(unsigned int *)&decoded[i * 4];
00703                         param[i] = (double)x / ((double)pow(2, 32));    /* Map to [0, 1[ */
00704                 }
00705                 else
00706                 if (fit->nu_bits_per_param == 16) {
00707                         unsigned short x;
00708                         x = *(unsigned short *)&decoded[i * 2];
00709                         param[i] = (double)x / ((double)pow(2, 16));   /* Map to [0, 1[ */
00710                 }
00711                 else {  /* nu_bit_per_param = 64 */
00712                         uint64_t x;
00713                         x = *(uint64_t *)&decoded[i * 8];
00714                         param[i] = (double)x / ((double)pow(2, 64));    /* Map to [0, 1[. */
00715                 }
00716         }
00717         free(decoded);
00718 }
00719 
00720 static void ffit_fgen_encode_normalized_parameters(Ffit *fit, FgenPopulation *pop, double *param, unsigned char *bitstring) {
00721         int i;
00722         unsigned char *decoded;
00723         decoded = (unsigned char *)malloc(pop->individual_size_in_bits / 8);
00724         for (i = 0; i < fit->nu_params; i++) {
00725                 if (fit->nu_bits_per_param == 32) {
00726                         unsigned int x;
00727                         x = param[i] * ((double)pow(2, 32));
00728                         *(unsigned int *)&decoded[i * 4] = x;
00729                 }
00730                 else
00731                 if (fit->nu_bits_per_param == 16) {
00732                         unsigned short x;
00733                         x = param[i] * ((double)pow(2, 16));
00734                         *(unsigned short *)&decoded[i * 2] = x;
00735                 }
00736                 else {  /* nu_bit_per_param = 64 */
00737                         uint64_t x;
00738                         x = param[i] * ((double)pow(2, 64));
00739                         *(uint64_t *)&decoded[i * 8] = x;
00740                 }
00741         }
00742         fgen_encode_to_gray(pop, decoded, bitstring);
00743         free(decoded);
00744 }
00745 
00746 /* Calculate error based on given normalized parameters. */
00747 
00748 static double ffit_hill_climb_calculate_error(Ffit *fit, double *normalized_param) {
00749         double *param;
00750         int i;
00751         double error;
00752         param = (double *)malloc(sizeof(double) * fit->nu_params);
00753         for (i = 0; i < fit->nu_params; i++)
00754                 param[i] = ffit_map_parameter(fit, i, normalized_param[i]);
00755         error = fit->ffit_calculate_error_func(fit, param); 
00756         free(param);
00757         return error;
00758 }
00759 
00760 /* Do a hill-climb with given normalized parameters. */
00761 
00762 static void ffit_do_hill_climb(Ffit *fit, double *normalized_param) {
00763         int i;
00764         double max_step_size;
00765         double error;
00766         double *param;
00767         /* Try five random steps in the parameter space. */
00768         max_step_size = 0.0001; /* Very arbitrary value. */
00769         error = ffit_hill_climb_calculate_error(fit, normalized_param);
00770         param = (double *)malloc(sizeof(double) * fit->nu_params);
00771         for (i = 0; i < 5; i++) {
00772                 int param_index;
00773                 double step;
00774                 double new_error;
00775                 /* Make a working copy of the old parameters. */
00776                 memcpy(param, normalized_param, sizeof(double) * fit->nu_params);
00777                 /* Choose a random parameter. */
00778                 param_index = fgen_random_n(fit->nu_params);
00779                 /* Choose a random small step, positive or negative. */
00780                 step = fgen_random_d(max_step_size * 2) - max_step_size;
00781                 param[param_index] += step;
00782                 if (param[param_index] < 0)
00783                         param[param_index] = 0;
00784                 if (param[param_index] > 1.0)
00785                         param[param_index] = 0.99999999999999;
00786                 new_error = ffit_hill_climb_calculate_error(fit, param);
00787                 if (new_error < error) {
00788                         /* The new parameters are better, replace the old parameters. */
00789                         normalized_param[param_index] = param[param_index];
00790                         error = new_error;
00791 // printf("+");
00792                 }
00793         }
00794         free(param);
00795 }
00796 
00797 static void print_params(Ffit *fit, double *param) {
00798         int i;
00799         printf("params: ");
00800         for (i = 0; i < fit->nu_params; i++)
00801                 printf("%lf ", param[i]);
00802         printf("\n");
00803 }
00804 
00805 static void ffit_fgen_hill_climb(Ffit *fit, FgenPopulation *pop) {
00806         int i;
00807         double *normalized_param;
00808         normalized_param = (double *)malloc(sizeof(double) * fit->nu_params);
00809         for (i = 0; i < pop->size; i++) {
00810                 ffit_fgen_extract_normalized_parameters(fit, pop, pop->ind[i]->bitstring, normalized_param);
00811 // printf("Before hill-climb: ");
00812 // print_params(fit, normalized_param);
00813                 ffit_do_hill_climb(fit, normalized_param);
00814 // printf("After hill-climb: ");
00815 // print_params(fit, normalized_param);
00816                 ffit_fgen_encode_normalized_parameters(fit, pop, normalized_param, pop->ind[i]->bitstring);
00817         }
00818         free(normalized_param);
00819 }
00820 
00821 #endif
00822 
00823 /*
00824  * ffit fgen real-valued interface.
00825  */
00826 
00827 /* The parameters are normalized to the range [0, 1]. */
00828 
00829 #define DOMAIN_MIN 0
00830 #define DOMAIN_MAX 1.0
00831 
00832 /* Custom seeding function that assigns parameters with random double floating point values within the range. */
00833 
00834 static void ffit_fgen_real_valued_seed(FgenPopulation *pop, unsigned char *bitstring) {
00835         double *params = (double *)bitstring;
00836         int i;
00837         FgenRNG *rng;
00838         Ffit *fit = (Ffit *)pop->user_data;
00839         rng = fgen_get_rng(pop);
00840         for (i = 0; i < fit->nu_params; i++)
00841                 params[i] = fgen_random_from_range_d(rng, DOMAIN_MIN, DOMAIN_MAX); 
00842 }
00843 
00844 /* Custom mutation function that assigns random values within the range to parameters with a mutation */
00845 /* probability. When the function is called child already contains a copy of parent */
00846 
00847 static void ffit_fgen_real_valued_mutation_large(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) {
00848         double *params_child = (double *)child;
00849         int i;
00850         Ffit *fit = (Ffit *)pop->user_data; 
00851         /* Mutate each parameter with the given probability. */
00852         for (i = 0; i < fit->nu_params; i++)
00853                 if (fgen_random_f(pop->rng, 1.0) < pop->macro_mutation_probability_float)
00854                         params_child[i] = fgen_random_from_range_d(pop->rng, DOMAIN_MIN, DOMAIN_MAX);
00855 }
00856 
00857 /* Custom mutation function that tweaks the parameter by a maximum of 1/20th of the range. */
00858 
00859 static void ffit_fgen_real_valued_mutation_small(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) {
00860         double *params_parent = (double *)parent;
00861         double *params_child = (double *)child;
00862         int i;
00863         Ffit *fit = (Ffit *)pop->user_data;
00864         /* Mutate each parameter with the given probability. */
00865         for (i = 0; i < fit->nu_params; i++)
00866                 if (fgen_random_f(pop->rng, 1.0) < pop->mutation_probability_float) {
00867                         double tweak = fgen_random_from_range_d(pop->rng, - (DOMAIN_MAX - DOMAIN_MIN) / 20,
00868                                 (DOMAIN_MAX - DOMAIN_MIN) / 20);
00869                         params_child[i] = params_parent[i] + tweak;
00870                         /* Clamp to range. */
00871                         if (params_child[i] < DOMAIN_MIN)
00872                                 params_child[i] = DOMAIN_MIN;
00873                         if (params_child[i] > DOMAIN_MAX)
00874                                 params_child[i] = DOMAIN_MAX;
00875                 }
00876 }
00877 
00878 /* Custom mutation function that is a combination of small and large mutations. */
00879 
00880 static void ffit_fgen_real_valued_mutation(FgenPopulation *pop, const unsigned char *parent, unsigned char *child) {
00881         ffit_fgen_real_valued_mutation_small(pop, parent, child);
00882         ffit_fgen_real_valued_mutation_large(pop, parent, child);
00883 }
00884 
00885 /* Custom real-valued crossover function. Intermediate recombination. */
00886 
00887 static void ffit_fgen_real_valued_crossover(FgenPopulation *pop, const unsigned char *parent1, const unsigned char *parent2,
00888 unsigned char *child1, unsigned char *child2) {
00889         double *params_parent1 = (double *)parent1;
00890         double *params_parent2 = (double *)parent2;
00891         double *params_child1 = (double *)child1;
00892         double *params_child2 = (double *)child2;
00893         int i;
00894         Ffit *fit = (Ffit *)pop->user_data;
00895         for (i = 0; i < fit->nu_params; i++) {
00896                 double alpha;
00897                 /* First offspring. */
00898                 alpha = fgen_random_from_range_d(pop->rng, - 0.25, 1.25);
00899                 params_child1[i] = params_parent1[i] + alpha * (params_parent2[i] - params_parent1[i]);
00900                 /* Clamp to range. */
00901                 if (params_child1[i] < DOMAIN_MIN)
00902                         params_child1[i] = DOMAIN_MIN;
00903                 if (params_child1[i] > DOMAIN_MAX)
00904                         params_child1[i] = DOMAIN_MAX;
00905                 /* Second offspring. */
00906                 alpha = fgen_random_from_range_d(pop->rng, - 0.25, 1.25);
00907                 params_child2[i] = params_parent2[i] + alpha * (params_parent1[i] - params_parent2[i]);
00908                 /* Clamp to range. */
00909                 if (params_child2[i] < DOMAIN_MIN)
00910                         params_child2[i] = DOMAIN_MIN;
00911                 if (params_child2[i] > DOMAIN_MAX)
00912                         params_child2[i] = DOMAIN_MAX;
00913         }
00914 }
00915 
00916 /*
00917  * ffit fpso interface.
00918  */
00919 
00920 static void ffit_fpso_generation_callback(FpsoPopulation *pop, int generation) {
00921         Ffit *fit = (Ffit *)pop->user_data;
00922         if (generation % fit->generation_callback_interval != 0)
00923                 return;
00924         double *best_param;
00925         double *best_normalized_param;
00926         int i;
00927         best_normalized_param = fpso_get_best_known_position(pop);
00928         best_param = (double *)alloca(sizeof(double) * pop->nu_params);
00929         /* Convert from normalized parameters to real parameters. */
00930         for (i = 0; i < pop->nu_params; i++)
00931                 best_param[i] = ffit_map_parameter(fit, i, best_normalized_param[i]); 
00932         fit->ffit_generation_callback_func(fit, generation, best_param, fpso_get_best_known_error(pop));
00933 //      free(best_param);
00934         if (fit->stop_signalled)
00935                 fpso_signal_stop(pop);
00936 }
00937 
00938 static double ffit_fpso_calculate_error(const FpsoPopulation *pop, const double *params_in) {
00939         Ffit *fit = (Ffit *)pop->user_data;
00940         double *param = (double *)alloca(sizeof(double) * pop->nu_params);
00941         double error;
00942         int i;
00943         /* Convert from normalized parameters to real parameters. */
00944         for (i = 0; i < pop->nu_params; i++)
00945                 param[i] = ffit_map_parameter(fit, i, params_in[i]); 
00946         error = fit->ffit_calculate_error_func(fit, param);
00947 //      free(param);
00948         return error;
00949 }
00950 
 All Data Structures Functions Variables