1997-02-19 13:59:07 +01:00
|
|
|
/*------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* geqo_main.c--
|
1997-09-07 07:04:48 +02:00
|
|
|
* solution of the query optimization problem
|
|
|
|
* by means of a Genetic Algorithm (GA)
|
1997-02-19 13:59:07 +01:00
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
1998-07-18 06:22:52 +02:00
|
|
|
* $Id: geqo_main.c,v 1.8 1998/07/18 04:22:27 momjian Exp $
|
1997-02-19 13:59:07 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* contributed by:
|
|
|
|
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
1997-09-07 07:04:48 +02:00
|
|
|
* Martin Utesch * Institute of Automatic Control *
|
|
|
|
= = University of Mining and Technology =
|
|
|
|
* utesch@aut.tu-freiberg.de * Freiberg, Germany *
|
1997-02-19 13:59:07 +01:00
|
|
|
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* -- parts of this are adapted from D. Whitley's Genitor algorithm -- */
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "nodes/pg_list.h"
|
|
|
|
#include "nodes/relation.h"
|
|
|
|
#include "nodes/plannodes.h"
|
|
|
|
#include "nodes/primnodes.h"
|
|
|
|
|
|
|
|
#include "utils/palloc.h"
|
|
|
|
#include "utils/elog.h"
|
|
|
|
|
|
|
|
#include "optimizer/internal.h"
|
|
|
|
#include "optimizer/paths.h"
|
|
|
|
#include "optimizer/pathnode.h"
|
|
|
|
#include "optimizer/clauses.h"
|
|
|
|
#include "optimizer/cost.h"
|
|
|
|
|
|
|
|
#include "optimizer/geqo_gene.h"
|
|
|
|
#include "optimizer/geqo.h"
|
|
|
|
#include "optimizer/geqo_pool.h"
|
|
|
|
#include "optimizer/geqo_selection.h"
|
|
|
|
#include "optimizer/geqo_recombination.h"
|
|
|
|
#include "optimizer/geqo_mutation.h"
|
|
|
|
#include "optimizer/geqo_misc.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* define edge recombination crossover [ERX] per default */
|
|
|
|
#if !defined(ERX) && \
|
1997-09-07 07:04:48 +02:00
|
|
|
!defined(PMX) && \
|
|
|
|
!defined(CX) && \
|
|
|
|
!defined(PX) && \
|
|
|
|
!defined(OX1) && \
|
|
|
|
!defined(OX2)
|
1997-02-19 13:59:07 +01:00
|
|
|
#define ERX
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* geqo--
|
1997-09-07 07:04:48 +02:00
|
|
|
* solution of the query optimization problem
|
|
|
|
* similar to a constrained Traveling Salesman Problem (TSP)
|
1997-02-19 13:59:07 +01:00
|
|
|
*/
|
|
|
|
|
1998-07-18 06:22:52 +02:00
|
|
|
RelOptInfo *
|
1997-09-08 23:56:23 +02:00
|
|
|
geqo(Query *root)
|
1997-02-19 13:59:07 +01:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int generation;
|
|
|
|
Chromosome *momma;
|
|
|
|
Chromosome *daddy;
|
|
|
|
Chromosome *kid;
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-03-14 17:03:02 +01:00
|
|
|
#if defined(ERX)
|
1997-09-08 04:41:22 +02:00
|
|
|
Edge *edge_table; /* list of edges */
|
|
|
|
int edge_failures = 0;
|
|
|
|
float difference;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
#endif
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-03-14 17:03:02 +01:00
|
|
|
#if defined(CX) || defined(PX) || defined(OX1) || defined(OX2)
|
1997-09-08 04:41:22 +02:00
|
|
|
City *city_table; /* list of cities */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-02-19 15:52:06 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CX)
|
1997-09-08 04:41:22 +02:00
|
|
|
int cycle_diffs = 0;
|
|
|
|
int mutations = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-02-19 15:52:06 +01:00
|
|
|
#endif
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-03-14 17:03:02 +01:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
int number_of_rels;
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
Pool *pool;
|
|
|
|
int pool_size,
|
|
|
|
number_generations,
|
|
|
|
status_interval;
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
Gene *best_tour;
|
1998-07-18 06:22:52 +02:00
|
|
|
RelOptInfo *best_rel;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* Plan *best_plan; */
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* set tour size */
|
1997-09-07 07:04:48 +02:00
|
|
|
number_of_rels = length(root->base_relation_list_);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* set GA parameters */
|
1997-09-07 07:04:48 +02:00
|
|
|
geqo_params(number_of_rels);/* out of "$PGDATA/pg_geqo" file */
|
|
|
|
pool_size = PoolSize;
|
|
|
|
number_generations = Generations;
|
|
|
|
status_interval = 10;
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* seed random number generator */
|
1997-09-07 07:04:48 +02:00
|
|
|
srandom(RandomSeed);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* allocate genetic pool memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
pool = alloc_pool(pool_size, number_of_rels);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* random initialization of the pool */
|
1997-09-07 07:04:48 +02:00
|
|
|
random_init_pool(root, pool, 0, pool->size);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* sort the pool according to cheapest path as fitness */
|
1997-09-07 07:04:48 +02:00
|
|
|
sort_pool(pool); /* we have to do it only one time, since
|
|
|
|
* all kids replace the worst individuals
|
|
|
|
* in future (-> geqo_pool.c:spread_chromo
|
|
|
|
* ) */
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* allocate chromosome momma and daddy memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
momma = alloc_chromo(pool->string_length);
|
|
|
|
daddy = alloc_chromo(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
#if defined (ERX)
|
1997-09-07 07:04:48 +02:00
|
|
|
elog(DEBUG, "geqo_main: using edge recombination crossover [ERX]");
|
1997-02-19 13:59:07 +01:00
|
|
|
/* allocate edge table memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
edge_table = alloc_edge_table(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(PMX)
|
1997-09-07 07:04:48 +02:00
|
|
|
elog(DEBUG, "geqo_main: using partially matched crossover [PMX]");
|
1997-02-19 13:59:07 +01:00
|
|
|
/* allocate chromosome kid memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
kid = alloc_chromo(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(CX)
|
1997-09-07 07:04:48 +02:00
|
|
|
elog(DEBUG, "geqo_main: using cycle crossover [CX]");
|
1997-02-19 13:59:07 +01:00
|
|
|
/* allocate city table memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
kid = alloc_chromo(pool->string_length);
|
|
|
|
city_table = alloc_city_table(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(PX)
|
1997-09-07 07:04:48 +02:00
|
|
|
elog(DEBUG, "geqo_main: using position crossover [PX]");
|
1997-02-19 13:59:07 +01:00
|
|
|
/* allocate city table memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
kid = alloc_chromo(pool->string_length);
|
|
|
|
city_table = alloc_city_table(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(OX1)
|
1997-09-07 07:04:48 +02:00
|
|
|
elog(DEBUG, "geqo_main: using order crossover [OX1]");
|
1997-02-19 13:59:07 +01:00
|
|
|
/* allocate city table memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
kid = alloc_chromo(pool->string_length);
|
|
|
|
city_table = alloc_city_table(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(OX2)
|
1997-09-07 07:04:48 +02:00
|
|
|
elog(DEBUG, "geqo_main: using order crossover [OX2]");
|
1997-02-19 13:59:07 +01:00
|
|
|
/* allocate city table memory */
|
1997-09-07 07:04:48 +02:00
|
|
|
kid = alloc_chromo(pool->string_length);
|
|
|
|
city_table = alloc_city_table(pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* my pain main part: */
|
|
|
|
/* iterative optimization */
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
for (generation = 0; generation < number_generations; generation++)
|
|
|
|
{
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* SELECTION */
|
|
|
|
geqo_selection(momma, daddy, pool, SelectionBias); /* using linear bias
|
|
|
|
* function */
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined (ERX)
|
1997-09-07 07:04:48 +02:00
|
|
|
/* EDGE RECOMBINATION CROSSOVER */
|
|
|
|
difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* let the kid grow in momma's womb (storage) for nine months ;-) */
|
|
|
|
/* sleep(23328000) -- har har har */
|
|
|
|
kid = momma;
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* are there any edge failures ? */
|
|
|
|
edge_failures += gimme_tour(edge_table, kid->string, pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(PMX)
|
1997-09-07 07:04:48 +02:00
|
|
|
/* PARTIALLY MATCHED CROSSOVER */
|
|
|
|
pmx(momma->string, daddy->string, kid->string, pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(CX)
|
1997-09-07 07:04:48 +02:00
|
|
|
/* CYCLE CROSSOVER */
|
|
|
|
cycle_diffs =
|
|
|
|
cx(momma->string, daddy->string, kid->string, pool->string_length, city_table);
|
|
|
|
/* mutate the child */
|
|
|
|
if (cycle_diffs == 0)
|
|
|
|
{
|
|
|
|
mutations++;
|
|
|
|
geqo_mutation(kid->string, pool->string_length);
|
|
|
|
}
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(PX)
|
1997-09-07 07:04:48 +02:00
|
|
|
/* POSITION CROSSOVER */
|
|
|
|
px(momma->string, daddy->string, kid->string, pool->string_length, city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(OX1)
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ORDER CROSSOVER */
|
|
|
|
ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(OX2)
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ORDER CROSSOVER */
|
|
|
|
ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* EVALUATE FITNESS */
|
|
|
|
kid->worth = geqo_eval(root, kid->string, pool->string_length);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* push the kid into the wilderness of life according to its worth */
|
|
|
|
spread_chromo(kid, pool);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef GEQO_DEBUG
|
1997-09-07 07:04:48 +02:00
|
|
|
if (status_interval && !(generation % status_interval))
|
|
|
|
print_gen(stdout, pool, generation);
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
} /* end of iterative optimization */
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
#if defined(ERX) && defined(GEQO_DEBUG)
|
1997-09-07 07:04:48 +02:00
|
|
|
if (edge_failures != 0)
|
|
|
|
fprintf(stdout, "\nFailures: %d Avg: %d\n", edge_failures, (int) generation / edge_failures);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
fprintf(stdout, "No edge failures detected.\n");
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(CX) && defined(GEQO_DEBUG)
|
1997-09-07 07:04:48 +02:00
|
|
|
if (mutations != 0)
|
|
|
|
fprintf(stdout, "\nMutations: %d Generations: %d\n", mutations, generation);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
fprintf(stdout, "No mutations processed.\n");
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-02-19 13:59:07 +01:00
|
|
|
#ifdef GEQO_DEBUG
|
1997-09-07 07:04:48 +02:00
|
|
|
fprintf(stdout, "\n");
|
|
|
|
print_pool(stdout, pool, 0, pool_size - 1);
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* got the cheapest query tree processed by geqo;
|
|
|
|
first element of the population indicates the best query tree */
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
best_tour = (Gene *) pool->data[0].string;
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* root->join_relation_list_ will be modified during this ! */
|
1998-07-18 06:22:52 +02:00
|
|
|
best_rel = (RelOptInfo *) gimme_tree(root, best_tour, 0, pool->string_length, NULL);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
/* DBG: show the query plan
|
|
|
|
print_plan(best_plan, root);
|
|
|
|
DBG */
|
|
|
|
|
|
|
|
/* ... free memory stuff */
|
1997-09-07 07:04:48 +02:00
|
|
|
free_chromo(momma);
|
|
|
|
free_chromo(daddy);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
|
|
|
#if defined (ERX)
|
1997-09-07 07:04:48 +02:00
|
|
|
free_edge_table(edge_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(PMX)
|
1997-09-07 07:04:48 +02:00
|
|
|
free_chromo(kid);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(CX)
|
1997-09-07 07:04:48 +02:00
|
|
|
free_chromo(kid);
|
|
|
|
free_city_table(city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(PX)
|
1997-09-07 07:04:48 +02:00
|
|
|
free_chromo(kid);
|
|
|
|
free_city_table(city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(OX1)
|
1997-09-07 07:04:48 +02:00
|
|
|
free_chromo(kid);
|
|
|
|
free_city_table(city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#elif defined(OX2)
|
1997-09-07 07:04:48 +02:00
|
|
|
free_chromo(kid);
|
|
|
|
free_city_table(city_table);
|
1997-02-19 13:59:07 +01:00
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
free_pool(pool);
|
1997-02-19 13:59:07 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return (best_rel);
|
1997-02-19 13:59:07 +01:00
|
|
|
}
|