libfgen
0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
|
00001 /* 00002 cache.c -- fitness cache implementation. 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 #include <stdlib.h> 00025 #include <stdio.h> 00026 #include <string.h> 00027 #include <limits.h> 00028 #include <math.h> 00029 #include "fgen.h" 00030 #include "parameters.h" 00031 #include "bitstring.h" 00032 #include "error.h" 00033 #include "population.h" 00034 #include "cache.h" 00035 00036 #define CACHE_LOOK_AHEAD 4 00037 00038 /* 00039 * Test result, TSP problem: 00040 * 00041 * Cache size = 2MB entries: 00042 * 00043 * Look-ahead 8: 0.280483 (hit-rate) 00044 * Look-ahead 4: 0.279863 00045 * Look-ahead 2: 0.278402 00046 * Look-ahead 1: 0.275419 00047 * 00048 * Cache size = 16K entries: 00049 * 00050 * Look-ahead 32: 0.213105 00051 * Look-ahead 8: 0.213153 00052 * Look-ahead 4: 0.213110 00053 * Look-ahead 2: 0.212984 00054 * Look-ahead 1: 0.210340 00055 * 00056 * Cache size = 1K entries: 00057 * 00058 * Look-ahead 32: 0.182706 00059 * Look-ahead 4: 0.179864 00060 * Look-ahead 1: 0.155287 00061 */ 00062 00070 void fgen_enable_cache(FgenPopulation *pop, int size) { 00071 int i; 00072 pop->cache = (FgenCache *)malloc(sizeof(FgenCache)); 00073 pop->cache->size = size; 00074 pop->cache->nu_accesses = 0; 00075 pop->cache->nu_hits = 0; 00076 pop->cache->entry = (FgenCacheEntry **)malloc(sizeof(FgenCacheEntry *) * size); 00077 for (i = 0; i < size; i++) { 00078 pop->cache->entry[i] = (FgenCacheEntry *)malloc(sizeof(FgenCacheEntry)); 00079 pop->cache->entry[i]->bitstring = (unsigned char *)malloc(INDIVIDUAL_SIZE_IN_BYTES(pop)); 00080 pop->cache->entry[i]->date_mru = - 1; 00081 } 00082 pop->cache->refcount = 1; 00083 } 00084 00089 void fgen_enable_cache_on_archipelago(int nu_pops, FgenPopulation **pops, int size) { 00090 int i; 00091 fgen_enable_cache(pops[0], size); 00092 for (i = 1; i < nu_pops; i++) { 00093 pops[i]->cache = pops[0]->cache; 00094 pops[0]->cache->refcount++; 00095 } 00096 } 00097 00102 double fgen_get_cache_hit_rate(const FgenPopulation *pop) { 00103 return pop->cache->hit_rate; 00104 } 00105 00112 void fgen_invalidate_cache(FgenPopulation *pop) { 00113 for (int i = 0; i < pop->cache->size; i++) 00114 pop->cache->entry[i]->date_mru = - 1; 00115 } 00116 00117 void DestroyCache(FgenPopulation *pop) { 00118 int i; 00119 pop->cache->refcount--; 00120 if (pop->cache->refcount > 0) 00121 return; 00122 for (i = 0; i < pop->cache->size; i++) { 00123 free(pop->cache->entry[i]->bitstring); 00124 free(pop->cache->entry[i]); 00125 } 00126 free(pop->cache->entry); 00127 free(pop->cache); 00128 } 00129 00130 static unsigned int jenkins_one_at_a_time_hash(unsigned char *key, size_t len) 00131 { 00132 unsigned int hash, i; 00133 for (hash = i = 0; i < len; ++i) 00134 { 00135 hash += key[i]; 00136 hash += (hash << 10); 00137 hash ^= (hash >> 6); 00138 } 00139 hash += (hash << 3); 00140 hash ^= (hash >> 11); 00141 hash += (hash << 15); 00142 return hash; 00143 } 00144 00145 static int Hash(FgenPopulation *pop, FgenIndividual *ind) { 00146 return jenkins_one_at_a_time_hash(ind->bitstring, INDIVIDUAL_SIZE_IN_BYTES(pop)) % pop->cache->size; 00147 } 00148 00149 int CacheLookup(FgenPopulation *pop, FgenIndividual *ind, int *hash_out, double *fitness_out) { 00150 int j; 00151 int i = Hash(pop, ind); 00152 *hash_out = i; 00153 for (j = 0; j < CACHE_LOOK_AHEAD; j++) { 00154 int index = (i + j) % pop->cache->size; 00155 if (pop->cache->entry[index]->date_mru == -1) 00156 return 0; 00157 if (memcmp(ind->bitstring, pop->cache->entry[index]->bitstring, INDIVIDUAL_SIZE_IN_BYTES(pop)) == 0) { 00158 *fitness_out = pop->cache->entry[index]->fitness; 00159 return 1; 00160 } 00161 } 00162 return 0; 00163 } 00164 00165 int CacheHit(FgenPopulation *pop, FgenIndividual *ind, double *cache_fitness, int *hash_out) { 00166 int hash; 00167 double fitness; 00168 pop->cache->nu_accesses++; 00169 if (CacheLookup(pop, ind, &hash, &fitness)) { 00170 *cache_fitness = fitness; 00171 *hash_out = hash; 00172 pop->cache->nu_hits++; 00173 return 1; 00174 } 00175 *hash_out = hash; 00176 return 0; 00177 } 00178 00179 void AddToCache(FgenPopulation *pop, FgenIndividual *ind, int hash) { 00180 int i; 00181 int cache_index; 00182 int oldest_index; 00183 int oldest_mru = INT_MAX; 00184 for (i = 0; i < CACHE_LOOK_AHEAD; i++) { 00185 cache_index = (hash + i) % pop->cache->size; 00186 if (pop->cache->entry[cache_index]->date_mru == -1) 00187 goto skip; 00188 if (pop->cache->entry[cache_index]->date_mru < oldest_mru) { 00189 oldest_mru = pop->cache->entry[cache_index]->date_mru; 00190 oldest_index = cache_index; 00191 } 00192 } 00193 cache_index = oldest_index; 00194 skip: 00195 memcpy(pop->cache->entry[cache_index]->bitstring, ind->bitstring, 00196 INDIVIDUAL_SIZE_IN_BYTES(pop)); 00197 pop->cache->entry[cache_index]->fitness = ind->fitness; 00198 pop->cache->entry[cache_index]->date_mru = pop->generation; 00199 if (pop->cache->nu_accesses == 0) 00200 pop->cache->hit_rate = 0; 00201 else 00202 pop->cache->hit_rate = (double)pop->cache->nu_hits / pop->cache->nu_accesses; 00203 } 00204 00205