libfgen
0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
|
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