libfgen  0.1.15
Library for optimization using a genetic algorithm or particle swarm optimization
cache.c
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 
 All Data Structures Functions Variables