Header And Logo

PostgreSQL
| The world's most advanced open source database.

geqo_main.c

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------
00002  *
00003  * geqo_main.c
00004  *    solution to the query optimization problem
00005  *    by means of a Genetic Algorithm (GA)
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  * src/backend/optimizer/geqo/geqo_main.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 
00015 /* contributed by:
00016    =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
00017    *  Martin Utesch              * Institute of Automatic Control      *
00018    =                             = University of Mining and Technology =
00019    *  [email protected]  * Freiberg, Germany                   *
00020    =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
00021  */
00022 
00023 /* -- parts of this are adapted from D. Whitley's Genitor algorithm -- */
00024 
00025 #include "postgres.h"
00026 
00027 #include <math.h>
00028 
00029 #include "optimizer/geqo_misc.h"
00030 #include "optimizer/geqo_mutation.h"
00031 #include "optimizer/geqo_pool.h"
00032 #include "optimizer/geqo_random.h"
00033 #include "optimizer/geqo_selection.h"
00034 
00035 
00036 /*
00037  * Configuration options
00038  */
00039 int         Geqo_effort;
00040 int         Geqo_pool_size;
00041 int         Geqo_generations;
00042 double      Geqo_selection_bias;
00043 double      Geqo_seed;
00044 
00045 
00046 static int  gimme_pool_size(int nr_rel);
00047 static int  gimme_number_generations(int pool_size);
00048 
00049 /* define edge recombination crossover [ERX] per default */
00050 #if !defined(ERX) && \
00051     !defined(PMX) && \
00052     !defined(CX)  && \
00053     !defined(PX)  && \
00054     !defined(OX1) && \
00055     !defined(OX2)
00056 #define ERX
00057 #endif
00058 
00059 
00060 /*
00061  * geqo
00062  *    solution of the query optimization problem
00063  *    similar to a constrained Traveling Salesman Problem (TSP)
00064  */
00065 
00066 RelOptInfo *
00067 geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
00068 {
00069     GeqoPrivateData private;
00070     int         generation;
00071     Chromosome *momma;
00072     Chromosome *daddy;
00073     Chromosome *kid;
00074     Pool       *pool;
00075     int         pool_size,
00076                 number_generations;
00077 
00078 #ifdef GEQO_DEBUG
00079     int         status_interval;
00080 #endif
00081     Gene       *best_tour;
00082     RelOptInfo *best_rel;
00083 
00084 #if defined(ERX)
00085     Edge       *edge_table;     /* list of edges */
00086     int         edge_failures = 0;
00087 #endif
00088 #if defined(CX) || defined(PX) || defined(OX1) || defined(OX2)
00089     City       *city_table;     /* list of cities */
00090 #endif
00091 #if defined(CX)
00092     int         cycle_diffs = 0;
00093     int         mutations = 0;
00094 #endif
00095 
00096 /* set up private information */
00097     root->join_search_private = (void *) &private;
00098     private.initial_rels = initial_rels;
00099 
00100 /* initialize private number generator */
00101     geqo_set_seed(root, Geqo_seed);
00102 
00103 /* set GA parameters */
00104     pool_size = gimme_pool_size(number_of_rels);
00105     number_generations = gimme_number_generations(pool_size);
00106 #ifdef GEQO_DEBUG
00107     status_interval = 10;
00108 #endif
00109 
00110 /* allocate genetic pool memory */
00111     pool = alloc_pool(root, pool_size, number_of_rels);
00112 
00113 /* random initialization of the pool */
00114     random_init_pool(root, pool);
00115 
00116 /* sort the pool according to cheapest path as fitness */
00117     sort_pool(root, pool);      /* we have to do it only one time, since all
00118                                  * kids replace the worst individuals in
00119                                  * future (-> geqo_pool.c:spread_chromo ) */
00120 
00121 #ifdef GEQO_DEBUG
00122     elog(DEBUG1, "GEQO selected %d pool entries, best %.2f, worst %.2f",
00123          pool_size,
00124          pool->data[0].worth,
00125          pool->data[pool_size - 1].worth);
00126 #endif
00127 
00128 /* allocate chromosome momma and daddy memory */
00129     momma = alloc_chromo(root, pool->string_length);
00130     daddy = alloc_chromo(root, pool->string_length);
00131 
00132 #if defined (ERX)
00133 #ifdef GEQO_DEBUG
00134     elog(DEBUG2, "using edge recombination crossover [ERX]");
00135 #endif
00136 /* allocate edge table memory */
00137     edge_table = alloc_edge_table(root, pool->string_length);
00138 #elif defined(PMX)
00139 #ifdef GEQO_DEBUG
00140     elog(DEBUG2, "using partially matched crossover [PMX]");
00141 #endif
00142 /* allocate chromosome kid memory */
00143     kid = alloc_chromo(root, pool->string_length);
00144 #elif defined(CX)
00145 #ifdef GEQO_DEBUG
00146     elog(DEBUG2, "using cycle crossover [CX]");
00147 #endif
00148 /* allocate city table memory */
00149     kid = alloc_chromo(root, pool->string_length);
00150     city_table = alloc_city_table(root, pool->string_length);
00151 #elif defined(PX)
00152 #ifdef GEQO_DEBUG
00153     elog(DEBUG2, "using position crossover [PX]");
00154 #endif
00155 /* allocate city table memory */
00156     kid = alloc_chromo(root, pool->string_length);
00157     city_table = alloc_city_table(root, pool->string_length);
00158 #elif defined(OX1)
00159 #ifdef GEQO_DEBUG
00160     elog(DEBUG2, "using order crossover [OX1]");
00161 #endif
00162 /* allocate city table memory */
00163     kid = alloc_chromo(root, pool->string_length);
00164     city_table = alloc_city_table(root, pool->string_length);
00165 #elif defined(OX2)
00166 #ifdef GEQO_DEBUG
00167     elog(DEBUG2, "using order crossover [OX2]");
00168 #endif
00169 /* allocate city table memory */
00170     kid = alloc_chromo(root, pool->string_length);
00171     city_table = alloc_city_table(root, pool->string_length);
00172 #endif
00173 
00174 
00175 /* my pain main part: */
00176 /* iterative optimization */
00177 
00178     for (generation = 0; generation < number_generations; generation++)
00179     {
00180         /* SELECTION: using linear bias function */
00181         geqo_selection(root, momma, daddy, pool, Geqo_selection_bias);
00182 
00183 #if defined (ERX)
00184         /* EDGE RECOMBINATION CROSSOVER */
00185         gimme_edge_table(root, momma->string, daddy->string, pool->string_length, edge_table);
00186 
00187         kid = momma;
00188 
00189         /* are there any edge failures ? */
00190         edge_failures += gimme_tour(root, edge_table, kid->string, pool->string_length);
00191 #elif defined(PMX)
00192         /* PARTIALLY MATCHED CROSSOVER */
00193         pmx(root, momma->string, daddy->string, kid->string, pool->string_length);
00194 #elif defined(CX)
00195         /* CYCLE CROSSOVER */
00196         cycle_diffs = cx(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
00197         /* mutate the child */
00198         if (cycle_diffs == 0)
00199         {
00200             mutations++;
00201             geqo_mutation(root, kid->string, pool->string_length);
00202         }
00203 #elif defined(PX)
00204         /* POSITION CROSSOVER */
00205         px(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
00206 #elif defined(OX1)
00207         /* ORDER CROSSOVER */
00208         ox1(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
00209 #elif defined(OX2)
00210         /* ORDER CROSSOVER */
00211         ox2(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
00212 #endif
00213 
00214 
00215         /* EVALUATE FITNESS */
00216         kid->worth = geqo_eval(root, kid->string, pool->string_length);
00217 
00218         /* push the kid into the wilderness of life according to its worth */
00219         spread_chromo(root, kid, pool);
00220 
00221 
00222 #ifdef GEQO_DEBUG
00223         if (status_interval && !(generation % status_interval))
00224             print_gen(stdout, pool, generation);
00225 #endif
00226 
00227     }
00228 
00229 
00230 #if defined(ERX) && defined(GEQO_DEBUG)
00231     if (edge_failures != 0)
00232         elog(LOG, "[GEQO] failures: %d, average: %d",
00233              edge_failures, (int) number_generations / edge_failures);
00234     else
00235         elog(LOG, "[GEQO] no edge failures detected");
00236 #endif
00237 
00238 #if defined(CX) && defined(GEQO_DEBUG)
00239     if (mutations != 0)
00240         elog(LOG, "[GEQO] mutations: %d, generations: %d",
00241              mutations, number_generations);
00242     else
00243         elog(LOG, "[GEQO] no mutations processed");
00244 #endif
00245 
00246 #ifdef GEQO_DEBUG
00247     print_pool(stdout, pool, 0, pool_size - 1);
00248 #endif
00249 
00250 #ifdef GEQO_DEBUG
00251     elog(DEBUG1, "GEQO best is %.2f after %d generations",
00252          pool->data[0].worth, number_generations);
00253 #endif
00254 
00255 
00256     /*
00257      * got the cheapest query tree processed by geqo; first element of the
00258      * population indicates the best query tree
00259      */
00260     best_tour = (Gene *) pool->data[0].string;
00261 
00262     best_rel = gimme_tree(root, best_tour, pool->string_length);
00263 
00264     /* DBG: show the query plan */
00265 #ifdef NOT_USED
00266     print_plan(best_plan, root);
00267 #endif
00268 
00269     /* ... free memory stuff */
00270     free_chromo(root, momma);
00271     free_chromo(root, daddy);
00272 
00273 #if defined (ERX)
00274     free_edge_table(root, edge_table);
00275 #elif defined(PMX)
00276     free_chromo(root, kid);
00277 #elif defined(CX)
00278     free_chromo(root, kid);
00279     free_city_table(root, city_table);
00280 #elif defined(PX)
00281     free_chromo(root, kid);
00282     free_city_table(root, city_table);
00283 #elif defined(OX1)
00284     free_chromo(root, kid);
00285     free_city_table(root, city_table);
00286 #elif defined(OX2)
00287     free_chromo(root, kid);
00288     free_city_table(root, city_table);
00289 #endif
00290 
00291     free_pool(root, pool);
00292 
00293     /* ... clear root pointer to our private storage */
00294     root->join_search_private = NULL;
00295 
00296     return best_rel;
00297 }
00298 
00299 
00300 /*
00301  * Return either configured pool size or a good default
00302  *
00303  * The default is based on query size (no. of relations) = 2^(QS+1),
00304  * but constrained to a range based on the effort value.
00305  */
00306 static int
00307 gimme_pool_size(int nr_rel)
00308 {
00309     double      size;
00310     int         minsize;
00311     int         maxsize;
00312 
00313     /* Legal pool size *must* be at least 2, so ignore attempt to select 1 */
00314     if (Geqo_pool_size >= 2)
00315         return Geqo_pool_size;
00316 
00317     size = pow(2.0, nr_rel + 1.0);
00318 
00319     maxsize = 50 * Geqo_effort; /* 50 to 500 individuals */
00320     if (size > maxsize)
00321         return maxsize;
00322 
00323     minsize = 10 * Geqo_effort; /* 10 to 100 individuals */
00324     if (size < minsize)
00325         return minsize;
00326 
00327     return (int) ceil(size);
00328 }
00329 
00330 
00331 /*
00332  * Return either configured number of generations or a good default
00333  *
00334  * The default is the same as the pool size, which allows us to be
00335  * sure that less-fit individuals get pushed out of the breeding
00336  * population before the run finishes.
00337  */
00338 static int
00339 gimme_number_generations(int pool_size)
00340 {
00341     if (Geqo_generations > 0)
00342         return Geqo_generations;
00343 
00344     return pool_size;
00345 }