Thread: Make planning via GEQO repeatable

Make planning via GEQO repeatable

From
Andres Freund
Date:
Hi,

Query planning via GEQO currently can yield a different plan on every
invokation of the planner due to its non-exhaustive nature.

This often can be inconvenient because at times there may be a very
bad plan. It also makes it very hard to reproduce a problem with GEQO.


[PATCH 1/3] Add erand48() implementation for non-unixoid systems.

I could not find any suitable PRNG with a visible/changeable state for
windows. Currently random() on windows is mapped to drand48() copied
out of FreeBSD. I copied erand48(state) from there as well.
As I have no windows with a buildsystem available at the moment this
is untested on windows!

[PATCH 2/3] Support a 'geqo_seed' GUC to make planning via GEQO repeatable.

This patch adds a GUC geqo_seed to control whether the PRNG should be
repeatable or not. If geqo_seed = 0 a global/per-backend state is
used, thus the planning is not repeatable.
If set to a value in (0,1] that number is used to initialize the
generator on every planning.

It adds a "void *join_search_private" variable to PlannerInfo to hold
the random number generator. This variable could also be used by a
join_order plugin.
Alternatively it would be possible to start passing GeqoEvalData
around everywhere, but the suggestion to extend PlannerInfo came from
Tom...

"PlannerInfo *root" is now passed to all non-static geqo related
functions. It seems cleaner to do this for all functions than only
functions internally using the random generator.

GeqoEvalData, which is sparsely used, is replaced GeqoPrivateData
which is passed via join_search_private.

[PATCH 3/3] Document geqo_seed variable.

I will submit this to the commitfest. I guess thats OK?

Andres


[PATCH 3/3] Document geqo_seed variable.

From
Andres Freund
Date:
---doc/src/sgml/config.sgml |   16 ++++++++++++++++1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 99d25d7..5d8eca9 100644
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** archive_command = 'copy "%p" "C:\\server
*** 2150,2155 ****
--- 2150,2171 ----       </listitem>      </varlistentry>      
+      <varlistentry id="guc-geqo-seed" xreflabel="geqo_seed">
+       <term><varname>geqo_seed</varname>
+       (<type>floating point</type>)</term>
+       <indexterm>
+        <primary><varname>geqo_seed</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Controls the initialization of the random number generator used
+         by GEQO to select random paths through the join order search space.
+         With the default setting of zero the join order planning is not repeatable.
+         For repeatable planning set a value between 0 (exclusive) and 1 (inclusive).
+        </para>
+       </listitem>
+      </varlistentry>
+       </variablelist>     </sect2>      <sect2 id="runtime-config-query-other">
-- 
1.6.3.3.335.ge09a8



[PATCH 2/3] Support a 'geqo_seed' GUC to make planning via GEQO repeatable.

From
Andres Freund
Date:
---src/backend/optimizer/geqo/Makefile             |    1 +src/backend/optimizer/geqo/geqo_copy.c          |    4
+-src/backend/optimizer/geqo/geqo_cx.c           |    6 +-src/backend/optimizer/geqo/geqo_erx.c           |   47
++++++------src/backend/optimizer/geqo/geqo_eval.c         |   28 ++++----src/backend/optimizer/geqo/geqo_main.c
 |   90 ++++++++++++-----------src/backend/optimizer/geqo/geqo_mutation.c      |   10
+-src/backend/optimizer/geqo/geqo_ox1.c          |    8 +-src/backend/optimizer/geqo/geqo_ox2.c           |    7
+-src/backend/optimizer/geqo/geqo_pmx.c          |    7 +-src/backend/optimizer/geqo/geqo_pool.c          |   23
+++---src/backend/optimizer/geqo/geqo_px.c           |    8 +-src/backend/optimizer/geqo/geqo_random.c        |   42
+++++++++++src/backend/optimizer/geqo/geqo_recombination.c|    9 +-src/backend/optimizer/geqo/geqo_selection.c     |
19+++--src/backend/optimizer/path/allpaths.c           |    2 +src/backend/utils/misc/guc.c                    |    9
++src/include/nodes/relation.h                   |    3 +src/include/optimizer/geqo.h                    |   17
++---src/include/optimizer/geqo_copy.h              |    3 +-src/include/optimizer/geqo_mutation.h           |    3
+-src/include/optimizer/geqo_pool.h              |   14 ++--src/include/optimizer/geqo_random.h             |    9
+-src/include/optimizer/geqo_recombination.h     |   33 +++++---src/include/optimizer/geqo_selection.h          |    4
+-25files changed, 244 insertions(+), 162 deletions(-)create mode 100644 src/backend/optimizer/geqo/geqo_random.c
 

diff --git a/src/backend/optimizer/geqo/Makefile b/src/backend/optimizer/geqo/Makefile
index dbc6c28..e5a01d7 100644
*** a/src/backend/optimizer/geqo/Makefile
--- b/src/backend/optimizer/geqo/Makefile
*************** top_builddir = ../../../..
*** 14,19 ****
--- 14,20 ---- include $(top_builddir)/src/Makefile.global  OBJS =    geqo_copy.o geqo_eval.o geqo_main.o geqo_misc.o
\
+     geqo_random.o \     geqo_mutation.o geqo_pool.o geqo_recombination.o \     geqo_selection.o \     geqo_erx.o
geqo_pmx.ogeqo_cx.o geqo_px.o geqo_ox1.o geqo_ox2.o
 
diff --git a/src/backend/optimizer/geqo/geqo_copy.c b/src/backend/optimizer/geqo/geqo_copy.c
index 83af33a..373a924 100644
*** a/src/backend/optimizer/geqo/geqo_copy.c
--- b/src/backend/optimizer/geqo/geqo_copy.c
***************
*** 35,40 ****
--- 35,41 ----  #include "postgres.h" #include "optimizer/geqo_copy.h"
+ #include "optimizer/geqo_copy.h"  /* geqo_copy  *
***************
*** 42,48 ****  *  */ void
! geqo_copy(Chromosome *chromo1, Chromosome *chromo2, int string_length) {     int            i; 
--- 43,50 ----  *  */ void
! geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2,
!           int string_length) {     int            i; 
diff --git a/src/backend/optimizer/geqo/geqo_cx.c b/src/backend/optimizer/geqo/geqo_cx.c
index 3d5102f..ad861ce 100644
*** a/src/backend/optimizer/geqo/geqo_cx.c
--- b/src/backend/optimizer/geqo/geqo_cx.c
***************
*** 35,40 ****
--- 35,41 ----   #include "postgres.h"
+ #include "optimizer/geqo.h" #include "optimizer/geqo_recombination.h" #include "optimizer/geqo_random.h" 
***************
*** 44,50 ****  *     cycle crossover  */ int
! cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) {      int            i,
--- 45,52 ----  *     cycle crossover  */ int
! cx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
!    int num_gene, City *city_table) {      int            i,
*************** cx(Gene *tour1, Gene *tour2, Gene *offsp
*** 62,68 ****     }      /* choose random cycle starting position */
!     start_pos = geqo_randint(num_gene - 1, 0);      /* child inherits first city  */     offspring[start_pos] =
tour1[start_pos];
--- 64,70 ----     }      /* choose random cycle starting position */
!     start_pos = geqo_randint(root, num_gene - 1, 0);      /* child inherits first city  */     offspring[start_pos] =
tour1[start_pos];
diff --git a/src/backend/optimizer/geqo/geqo_erx.c b/src/backend/optimizer/geqo/geqo_erx.c
index 35e1a28..5bae059 100644
*** a/src/backend/optimizer/geqo/geqo_erx.c
--- b/src/backend/optimizer/geqo/geqo_erx.c
***************
*** 36,46 **** #include "optimizer/geqo_random.h"  
! static int    gimme_edge(Gene gene1, Gene gene2, Edge *edge_table);
! static void remove_gene(Gene gene, Edge edge, Edge *edge_table);
! static Gene gimme_gene(Edge edge, Edge *edge_table); 
! static Gene edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene);   /* alloc_edge_table
--- 36,46 ---- #include "optimizer/geqo_random.h"  
! static int    gimme_edge(PlannerInfo *root, Gene gene1, Gene gene2, Edge *edge_table);
! static void remove_gene(PlannerInfo *root, Gene gene, Edge edge, Edge *edge_table);
! static Gene gimme_gene(PlannerInfo *root, Edge edge, Edge *edge_table); 
! static Gene edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num_gene);   /*
alloc_edge_table
*************** static Gene edge_failure(Gene *gene, int
*** 50,56 ****  */  Edge *
! alloc_edge_table(int num_gene) {     Edge       *edge_table; 
--- 50,56 ----  */  Edge *
! alloc_edge_table(PlannerInfo *root, int num_gene) {     Edge       *edge_table; 
*************** alloc_edge_table(int num_gene)
*** 70,76 ****  *  */ void
! free_edge_table(Edge *edge_table) {     pfree(edge_table); }
--- 70,76 ----  *  */ void
! free_edge_table(PlannerInfo *root, Edge *edge_table) {     pfree(edge_table); }
*************** free_edge_table(Edge *edge_table)
*** 89,95 ****  *  */ float
! gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table) {     int            i,
index1,
--- 89,96 ----  *  */ float
! gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2,
!                  int num_gene, Edge *edge_table) {     int            i,                 index1,
*************** gimme_edge_table(Gene *tour1, Gene *tour
*** 121,131 ****          * twice per edge          */ 
!         edge_total += gimme_edge(tour1[index1], tour1[index2], edge_table);
!         gimme_edge(tour1[index2], tour1[index1], edge_table); 
!         edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table);
!         gimme_edge(tour2[index2], tour2[index1], edge_table);     }      /* return average number of edges per index
*/
--- 122,132 ----          * twice per edge          */ 
!         edge_total += gimme_edge(root, tour1[index1], tour1[index2], edge_table);
!         gimme_edge(root, tour1[index2], tour1[index1], edge_table); 
!         edge_total += gimme_edge(root, tour2[index1], tour2[index2], edge_table);
!         gimme_edge(root, tour2[index2], tour2[index1], edge_table);     }      /* return average number of edges per
index*/
 
*************** gimme_edge_table(Gene *tour1, Gene *tour
*** 147,153 ****  *              0 if edge was already registered and edge_table is unchanged  */ static int
! gimme_edge(Gene gene1, Gene gene2, Edge *edge_table) {     int            i;     int            edges;
--- 148,154 ----  *              0 if edge was already registered and edge_table is unchanged  */ static int
! gimme_edge(PlannerInfo *root, Gene gene1, Gene gene2, Edge *edge_table) {     int            i;     int
edges;
*************** gimme_edge(Gene gene1, Gene gene2, Edge 
*** 189,200 ****  *  */ int
! gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene) {     int            i;     int            edge_failures =
0;
 
!     new_gene[0] = (Gene) geqo_randint(num_gene, 1);        /* choose int between 1
                     * and num_gene */      for (i = 1; i < num_gene; i++)
 
--- 190,201 ----  *  */ int
! gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene, int num_gene) {     int            i;     int
  edge_failures = 0; 
 
!     new_gene[0] = (Gene) geqo_randint(root, num_gene, 1);        /* choose int between 1
                           * and num_gene */      for (i = 1; i < num_gene; i++) 
*************** gimme_tour(Edge *edge_table, Gene *new_g
*** 204,221 ****          * table          */ 
!         remove_gene(new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);          /* find destination for
thenewly entered point */          if (edge_table[new_gene[i - 1]].unused_edges > 0)
 
!             new_gene[i] = gimme_gene(edge_table[(int) new_gene[i - 1]], edge_table);          else         {
             /* cope with fault */             edge_failures++; 
 
!             new_gene[i] = edge_failure(new_gene, i - 1, edge_table, num_gene);         }          /* mark this node
asincorporated */
 
--- 205,222 ----          * table          */ 
!         remove_gene(root, new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);          /* find
destinationfor the newly entered point */          if (edge_table[new_gene[i - 1]].unused_edges > 0)
 
!             new_gene[i] = gimme_gene(root, edge_table[(int) new_gene[i - 1]], edge_table);          else         {
                   /* cope with fault */             edge_failures++; 
 
!             new_gene[i] = edge_failure(root, new_gene, i - 1, edge_table, num_gene);         }          /* mark this
nodeas incorporated */
 
*************** gimme_tour(Edge *edge_table, Gene *new_g
*** 235,241 ****  *  */ static void
! remove_gene(Gene gene, Edge edge, Edge *edge_table) {     int            i,                 j;
--- 236,242 ----  *  */ static void
! remove_gene(PlannerInfo *root, Gene gene, Edge edge, Edge *edge_table) {     int            i,                 j;
*************** remove_gene(Gene gene, Edge edge, Edge *
*** 277,283 ****  *  */ static Gene
! gimme_gene(Edge edge, Edge *edge_table) {     int            i;     Gene        friend;
--- 278,284 ----  *  */ static Gene
! gimme_gene(PlannerInfo *root, Edge edge, Edge *edge_table) {     int            i;     Gene        friend;
*************** gimme_gene(Edge edge, Edge *edge_table)
*** 340,346 ****       /* random decision of the possible candidates to use */
!     rand_decision = (int) geqo_randint(minimum_count - 1, 0);       for (i = 0; i < edge.unused_edges; i++)
--- 341,347 ----       /* random decision of the possible candidates to use */
!     rand_decision = geqo_randint(root, minimum_count - 1, 0);       for (i = 0; i < edge.unused_edges; i++)
*************** gimme_gene(Edge edge, Edge *edge_table)
*** 368,374 ****  *  */ static Gene
! edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene) {     int            i;     Gene        fail_gene
=gene[index];
 
--- 369,375 ----  *  */ static Gene
! edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num_gene) {     int            i;
Gene       fail_gene = gene[index];
 
*************** edge_failure(Gene *gene, int index, Edge
*** 401,407 ****     if (four_count != 0)     { 
!         rand_decision = (int) geqo_randint(four_count - 1, 0);          for (i = 1; i <= num_gene; i++)         {
--- 402,408 ----     if (four_count != 0)     { 
!         rand_decision = geqo_randint(root, four_count - 1, 0);          for (i = 1; i <= num_gene; i++)         {
*************** edge_failure(Gene *gene, int index, Edge
*** 423,429 ****     else if (remaining_edges != 0)     {         /* random decision of the gene with remaining edges
*/
!         rand_decision = (int) geqo_randint(remaining_edges - 1, 0);          for (i = 1; i <= num_gene; i++)
{
--- 424,430 ----     else if (remaining_edges != 0)     {         /* random decision of the gene with remaining edges
*/
!         rand_decision = geqo_randint(root, remaining_edges - 1, 0);          for (i = 1; i <= num_gene; i++)
{
diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
index 04b3bfe..11903a5 100644
*** a/src/backend/optimizer/geqo/geqo_eval.c
--- b/src/backend/optimizer/geqo/geqo_eval.c
*************** static bool desirable_join(PlannerInfo *
*** 42,48 ****  * Returns cost of a query tree as an individual of the population.  */ Cost
! geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata) {     MemoryContext mycontext;     MemoryContext oldcxt;
--- 42,48 ----  * Returns cost of a query tree as an individual of the population.  */ Cost
! geqo_eval(PlannerInfo *root, Gene *tour, int num_gene) {     MemoryContext mycontext;     MemoryContext oldcxt;
*************** geqo_eval(Gene *tour, int num_gene, Geqo
*** 94,106 ****      * (If we are dealing with enough join rels, which we very likely are, a      * new hash table will
getbuilt and used locally.)      */
 
!     savelength = list_length(evaldata->root->join_rel_list);
!     savehash = evaldata->root->join_rel_hash; 
!     evaldata->root->join_rel_hash = NULL;      /* construct the best path for the given combination of relations */
!     joinrel = gimme_tree(tour, num_gene, evaldata);      /*      * compute fitness
--- 94,106 ----      * (If we are dealing with enough join rels, which we very likely are, a      * new hash table will
getbuilt and used locally.)      */
 
!     savelength = list_length(root->join_rel_list);
!     savehash = root->join_rel_hash; 
!     root->join_rel_hash = NULL;      /* construct the best path for the given combination of relations */
!     joinrel = gimme_tree(root, tour, num_gene);      /*      * compute fitness
*************** geqo_eval(Gene *tour, int num_gene, Geqo
*** 117,125 ****      * Restore join_rel_list to its former state, and put back original      * hashtable if any.
*/
!     evaldata->root->join_rel_list = list_truncate(evaldata->root->join_rel_list,
!                                                   savelength);
!     evaldata->root->join_rel_hash = savehash;      /* release all the memory acquired within gimme_tree */
MemoryContextSwitchTo(oldcxt);
--- 117,125 ----      * Restore join_rel_list to its former state, and put back original      * hashtable if any.
*/
!     root->join_rel_list = list_truncate(root->join_rel_list,
!                                         savelength);
!     root->join_rel_hash = savehash;      /* release all the memory acquired within gimme_tree */
MemoryContextSwitchTo(oldcxt);
*************** geqo_eval(Gene *tour, int num_gene, Geqo
*** 134,140 ****  *      order.  *  *     'tour' is the proposed join order, of length 'num_gene'
-  *     'evaldata' contains the context we need  *  * Returns a new join relation whose cheapest path is the best plan
for * this join order.  NB: will return NULL if join order is invalid.
 
--- 134,139 ----
*************** geqo_eval(Gene *tour, int num_gene, Geqo
*** 153,159 ****  * plans.  */ RelOptInfo *
! gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata) {     RelOptInfo **stack;     int
stack_depth;
--- 152,158 ----  * plans.  */ RelOptInfo *
! gimme_tree(PlannerInfo *root, Gene *tour, int num_gene) {     RelOptInfo **stack;     int            stack_depth;
*************** gimme_tree(Gene *tour, int num_gene, Geq
*** 193,200 ****          /* Get the next input relation and push it */         cur_rel_index = (int) tour[rel_count];
!         stack[stack_depth] = (RelOptInfo *) list_nth(evaldata->initial_rels,
!                                                      cur_rel_index - 1);         stack_depth++;          /*
--- 192,200 ----          /* Get the next input relation and push it */         cur_rel_index = (int) tour[rel_count];
!         stack[stack_depth] = (RelOptInfo *) list_nth(
!             ((GeqoPrivateData*)root->join_search_private)->initial_rels,
!             cur_rel_index - 1);         stack_depth++;          /*
*************** gimme_tree(Gene *tour, int num_gene, Geq
*** 211,217 ****              * have exhausted the input, the heuristics can't prevent popping.              */
   if (rel_count < num_gene - 1 &&
 
!                 !desirable_join(evaldata->root, outer_rel, inner_rel))                 break;              /*
--- 211,217 ----              * have exhausted the input, the heuristics can't prevent popping.              */
   if (rel_count < num_gene - 1 &&
 
!                 !desirable_join(root, outer_rel, inner_rel))                 break;              /*
*************** gimme_tree(Gene *tour, int num_gene, Geq
*** 220,226 ****              * root->join_rel_list yet, and so the paths constructed for it              * will only
includethe ones we want.              */
 
!             joinrel = make_join_rel(evaldata->root, outer_rel, inner_rel);              /* Can't pop stack here if
joinorder is not valid */             if (!joinrel)
 
--- 220,226 ----              * root->join_rel_list yet, and so the paths constructed for it              * will only
includethe ones we want.              */
 
!             joinrel = make_join_rel(root, outer_rel, inner_rel);              /* Can't pop stack here if join order
isnot valid */             if (!joinrel)
 
diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c
index 72b0b57..10f64f4 100644
*** a/src/backend/optimizer/geqo/geqo_main.c
--- b/src/backend/optimizer/geqo/geqo_main.c
***************
*** 29,34 ****
--- 29,35 ---- #include "optimizer/geqo_misc.h" #include "optimizer/geqo_pool.h" #include "optimizer/geqo_selection.h"
+ #include "optimizer/geqo_random.h"   /*
*************** int            Geqo_effort;
*** 38,43 ****
--- 39,45 ---- int            Geqo_pool_size; int            Geqo_generations; double        Geqo_selection_bias;
+ double        Geqo_seed;   static int    gimme_pool_size(int nr_rel);
*************** static int    gimme_number_generations(int 
*** 63,69 **** RelOptInfo * geqo(PlannerInfo *root, int number_of_rels, List *initial_rels) {
-     GeqoEvalData evaldata;     int            generation;     Chromosome *momma;     Chromosome *daddy;
--- 65,70 ----
*************** geqo(PlannerInfo *root, int number_of_re
*** 88,96 ****     int            mutations = 0; #endif 
! /* set up evaldata */
!     evaldata.root = root;
!     evaldata.initial_rels = initial_rels;  /* set GA parameters */     pool_size = gimme_pool_size(number_of_rels);
--- 89,102 ----     int            mutations = 0; #endif 
! /* setup private information */
!     root->join_search_private = (GeqoPrivateData*)palloc0(sizeof(GeqoPrivateData));
!     ((GeqoPrivateData*)root->join_search_private)->initial_rels = initial_rels;
! 
! /* initialize private number generator */
!     if(Geqo_seed != 0){
!         geqo_seed(root, Geqo_seed);
!     }  /* set GA parameters */     pool_size = gimme_pool_size(number_of_rels);
*************** geqo(PlannerInfo *root, int number_of_re
*** 98,110 ****     status_interval = 10;  /* allocate genetic pool memory */
!     pool = alloc_pool(pool_size, number_of_rels);  /* random initialization of the pool */
!     random_init_pool(pool, &evaldata);  /* sort the pool according to cheapest path as fitness */
!     sort_pool(pool);            /* we have to do it only one time, since all                                  * kids
replacethe worst individuals in                                  * future (-> geqo_pool.c:spread_chromo ) */ 
 
--- 104,116 ----     status_interval = 10;  /* allocate genetic pool memory */
!     pool = alloc_pool(root, pool_size, number_of_rels);  /* random initialization of the pool */
!     random_init_pool(root, pool);  /* sort the pool according to cheapest path as fitness */
!     sort_pool(root, pool);            /* we have to do it only one time, since all                                  *
kidsreplace the worst individuals in                                  * future (-> geqo_pool.c:spread_chromo ) */ 
 
*************** geqo(PlannerInfo *root, int number_of_re
*** 116,164 **** #endif  /* allocate chromosome momma and daddy memory */
!     momma = alloc_chromo(pool->string_length);
!     daddy = alloc_chromo(pool->string_length);  #if defined (ERX) #ifdef GEQO_DEBUG     elog(DEBUG2, "using edge
recombinationcrossover [ERX]"); #endif /* allocate edge table memory */
 
!     edge_table = alloc_edge_table(pool->string_length); #elif defined(PMX) #ifdef GEQO_DEBUG     elog(DEBUG2, "using
partiallymatched crossover [PMX]"); #endif /* allocate chromosome kid memory */
 
!     kid = alloc_chromo(pool->string_length); #elif defined(CX) #ifdef GEQO_DEBUG     elog(DEBUG2, "using cycle
crossover[CX]"); #endif /* allocate city table memory */
 
!     kid = alloc_chromo(pool->string_length);
!     city_table = alloc_city_table(pool->string_length); #elif defined(PX) #ifdef GEQO_DEBUG     elog(DEBUG2, "using
positioncrossover [PX]"); #endif /* allocate city table memory */
 
!     kid = alloc_chromo(pool->string_length);
!     city_table = alloc_city_table(pool->string_length); #elif defined(OX1) #ifdef GEQO_DEBUG     elog(DEBUG2, "using
ordercrossover [OX1]"); #endif /* allocate city table memory */     kid = alloc_chromo(pool->string_length);
 
!     city_table = alloc_city_table(pool->string_length); #elif defined(OX2) #ifdef GEQO_DEBUG     elog(DEBUG2, "using
ordercrossover [OX2]"); #endif /* allocate city table memory */     kid = alloc_chromo(pool->string_length);
 
!     city_table = alloc_city_table(pool->string_length); #endif  
--- 122,170 ---- #endif  /* allocate chromosome momma and daddy memory */
!     momma = alloc_chromo(root, pool->string_length);
!     daddy = alloc_chromo(root, pool->string_length);  #if defined (ERX) #ifdef GEQO_DEBUG     elog(DEBUG2, "using
edgerecombination crossover [ERX]"); #endif /* allocate edge table memory */
 
!     edge_table = alloc_edge_table(root, pool->string_length); #elif defined(PMX) #ifdef GEQO_DEBUG     elog(DEBUG2,
"usingpartially matched crossover [PMX]"); #endif /* allocate chromosome kid memory */
 
!     kid = alloc_chromo(root, pool->string_length); #elif defined(CX) #ifdef GEQO_DEBUG     elog(DEBUG2, "using cycle
crossover[CX]"); #endif /* allocate city table memory */
 
!     kid = alloc_chromo(root, pool->string_length);
!     city_table = alloc_city_table(root, pool->string_length); #elif defined(PX) #ifdef GEQO_DEBUG     elog(DEBUG2,
"usingposition crossover [PX]"); #endif /* allocate city table memory */
 
!     kid = alloc_chromo(root, pool->string_length);
!     city_table = alloc_city_table(root, pool->string_length); #elif defined(OX1) #ifdef GEQO_DEBUG     elog(DEBUG2,
"usingorder crossover [OX1]"); #endif /* allocate city table memory */     kid = alloc_chromo(pool->string_length);
 
!     city_table = alloc_city_table(root, pool->string_length); #elif defined(OX2) #ifdef GEQO_DEBUG     elog(DEBUG2,
"usingorder crossover [OX2]"); #endif /* allocate city table memory */     kid = alloc_chromo(pool->string_length);
 
!     city_table = alloc_city_table(root, pool->string_length); #endif  
*************** geqo(PlannerInfo *root, int number_of_re
*** 168,212 ****     for (generation = 0; generation < number_generations; generation++)     {         /* SELECTION:
usinglinear bias function */
 
!         geqo_selection(momma, daddy, pool, Geqo_selection_bias);  #if defined (ERX)         /* EDGE RECOMBINATION
CROSSOVER*/
 
!         difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table);          kid =
momma;         /* are there any edge failures ? */
 
!         edge_failures += gimme_tour(edge_table, kid->string, pool->string_length); #elif defined(PMX)         /*
PARTIALLYMATCHED CROSSOVER */
 
!         pmx(momma->string, daddy->string, kid->string, pool->string_length); #elif defined(CX)         /* CYCLE
CROSSOVER*/
 
!         cycle_diffs = cx(momma->string, daddy->string, kid->string, pool->string_length, city_table);         /*
mutatethe child */         if (cycle_diffs == 0)         {             mutations++;
 
!             geqo_mutation(kid->string, pool->string_length);         } #elif defined(PX)         /* POSITION
CROSSOVER*/
 
!         px(momma->string, daddy->string, kid->string, pool->string_length, city_table); #elif defined(OX1)         /*
ORDERCROSSOVER */
 
!         ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table); #elif defined(OX2)
/*ORDER CROSSOVER */
 
!         ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table); #endif           /* EVALUATE
FITNESS*/
 
!         kid->worth = geqo_eval(kid->string, pool->string_length, &evaldata);          /* push the kid into the
wildernessof life according to its worth */
 
!         spread_chromo(kid, pool);   #ifdef GEQO_DEBUG
--- 174,218 ----     for (generation = 0; generation < number_generations; generation++)     {         /* SELECTION:
usinglinear bias function */
 
!         geqo_selection(root, momma, daddy, pool, Geqo_selection_bias);  #if defined (ERX)         /* EDGE
RECOMBINATIONCROSSOVER */ 
!         difference = gimme_edge_table(root, momma->string, daddy->string, pool->string_length, edge_table);
kid= momma;          /* are there any edge failures ? */
 
!         edge_failures += gimme_tour(root, edge_table, kid->string, pool->string_length); #elif defined(PMX)
/*PARTIALLY MATCHED CROSSOVER */
 
!         pmx(root, momma->string, daddy->string, kid->string, pool->string_length); #elif defined(CX)         /* CYCLE
CROSSOVER*/
 
!         cycle_diffs = cx(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
/*mutate the child */         if (cycle_diffs == 0)         {             mutations++;
 
!             geqo_mutation(root, kid->string, pool->string_length);         } #elif defined(PX)         /* POSITION
CROSSOVER*/
 
!         px(root, momma->string, daddy->string, kid->string, pool->string_length, city_table); #elif defined(OX1)
  /* ORDER CROSSOVER */
 
!         ox1(root, momma->string, daddy->string, kid->string, pool->string_length, city_table); #elif defined(OX2)
   /* ORDER CROSSOVER */
 
!         ox2(root, momma->string, daddy->string, kid->string, pool->string_length, city_table); #endif           /*
EVALUATEFITNESS */
 
!         kid->worth = geqo_eval(root, kid->string, pool->string_length);          /* push the kid into the wilderness
oflife according to its worth */
 
!         spread_chromo(root, kid, pool);   #ifdef GEQO_DEBUG
*************** geqo(PlannerInfo *root, int number_of_re
*** 249,255 ****      */     best_tour = (Gene *) pool->data[0].string; 
!     best_rel = gimme_tree(best_tour, pool->string_length, &evaldata);      if (best_rel == NULL)         elog(ERROR,
"failedto make a valid plan");
 
--- 255,261 ----      */     best_tour = (Gene *) pool->data[0].string; 
!     best_rel = gimme_tree(root, best_tour, pool->string_length);      if (best_rel == NULL)         elog(ERROR,
"failedto make a valid plan");
 
*************** geqo(PlannerInfo *root, int number_of_re
*** 260,287 **** #endif      /* ... free memory stuff */
!     free_chromo(momma);
!     free_chromo(daddy);  #if defined (ERX)
!     free_edge_table(edge_table); #elif defined(PMX)
!     free_chromo(kid); #elif defined(CX)
!     free_chromo(kid);
!     free_city_table(city_table); #elif defined(PX)
!     free_chromo(kid);
!     free_city_table(city_table); #elif defined(OX1)
!     free_chromo(kid);
!     free_city_table(city_table); #elif defined(OX2)
!     free_chromo(kid);
!     free_city_table(city_table); #endif 
!     free_pool(pool);      return best_rel; }
--- 266,293 ---- #endif      /* ... free memory stuff */
!     free_chromo(root, momma);
!     free_chromo(root, daddy);  #if defined (ERX)
!     free_edge_table(root, edge_table); #elif defined(PMX)
!     free_chromo(root, kid); #elif defined(CX)
!     free_chromo(root, kid);
!     free_city_table(root, city_table); #elif defined(PX)
!     free_chromo(root, kid);
!     free_city_table(root, city_table); #elif defined(OX1)
!     free_chromo(root, kid);
!     free_city_table(root, city_table); #elif defined(OX2)
!     free_chromo(root, kid);
!     free_city_table(root, city_table); #endif 
!     free_pool(root, pool);      return best_rel; }
diff --git a/src/backend/optimizer/geqo/geqo_mutation.c b/src/backend/optimizer/geqo/geqo_mutation.c
index 899410c..acf3b34 100644
*** a/src/backend/optimizer/geqo/geqo_mutation.c
--- b/src/backend/optimizer/geqo/geqo_mutation.c
***************
*** 36,56 **** #include "optimizer/geqo_random.h"  void
! geqo_mutation(Gene *tour, int num_gene) {     int            swap1;     int            swap2;
!     int            num_swaps = geqo_randint(num_gene / 3, 0);     Gene        temp;       while (num_swaps > 0)
{
!         swap1 = geqo_randint(num_gene - 1, 0);
!         swap2 = geqo_randint(num_gene - 1, 0);          while (swap1 == swap2)
!             swap2 = geqo_randint(num_gene - 1, 0);          temp = tour[swap1];         tour[swap1] = tour[swap2];
--- 36,56 ---- #include "optimizer/geqo_random.h"  void
! geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene) {     int            swap1;     int            swap2;
!     int            num_swaps = geqo_randint(root, num_gene / 3, 0);     Gene        temp;       while (num_swaps > 0)
   {
 
!         swap1 = geqo_randint(root, num_gene - 1, 0);
!         swap2 = geqo_randint(root, num_gene - 1, 0);          while (swap1 == swap2)
!             swap2 = geqo_randint(root, num_gene - 1, 0);          temp = tour[swap1];         tour[swap1] =
tour[swap2];
diff --git a/src/backend/optimizer/geqo/geqo_ox1.c b/src/backend/optimizer/geqo/geqo_ox1.c
index cd979df..d292e98 100644
*** a/src/backend/optimizer/geqo/geqo_ox1.c
--- b/src/backend/optimizer/geqo/geqo_ox1.c
***************
*** 34,39 ****
--- 34,40 ---- /*************************************************************/  #include "postgres.h"
+ #include "optimizer/geqo.h" #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" 
***************
*** 43,49 ****  *     position crossover  */ void
! ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) {     int            left,
   right,
 
--- 44,51 ----  *     position crossover  */ void
! ox1(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
!     City *city_table) {     int            left,                 right,
*************** ox1(Gene *tour1, Gene *tour2, Gene *offs
*** 56,63 ****         city_table[k].used = 0;      /* select portion to copy from tour1 */
!     left = geqo_randint(num_gene - 1, 0);
!     right = geqo_randint(num_gene - 1, 0);      if (left > right)     {
--- 58,65 ----         city_table[k].used = 0;      /* select portion to copy from tour1 */
!     left = geqo_randint(root, num_gene - 1, 0);
!     right = geqo_randint(root, num_gene - 1, 0);      if (left > right)     {
diff --git a/src/backend/optimizer/geqo/geqo_ox2.c b/src/backend/optimizer/geqo/geqo_ox2.c
index 0d2e0de..a2fdfe8 100644
*** a/src/backend/optimizer/geqo/geqo_ox2.c
--- b/src/backend/optimizer/geqo/geqo_ox2.c
***************
*** 34,39 ****
--- 34,40 ---- /*************************************************************/  #include "postgres.h"
+ #include "optimizer/geqo.h" #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" 
***************
*** 43,49 ****  *     position crossover  */ void
! ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) {     int            k,
j,
 
--- 44,50 ----  *     position crossover  */ void
! ox2(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) {     int
k,                 j,
 
*************** ox2(Gene *tour1, Gene *tour2, Gene *offs
*** 60,71 ****     }      /* determine the number of positions to be inherited from tour1  */
!     num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);      /* make a list of selected cities */     for
(k= 0; k < num_positions; k++)     {
 
!         pos = geqo_randint(num_gene - 1, 0);         city_table[pos].select_list = (int) tour1[pos];
city_table[(int)tour1[pos]].used = 1;    /* mark used */     }
 
--- 61,72 ----     }      /* determine the number of positions to be inherited from tour1  */
!     num_positions = geqo_randint(root, 2 * num_gene / 3, num_gene / 3);      /* make a list of selected cities */
for(k = 0; k < num_positions; k++)     {
 
!         pos = geqo_randint(root, num_gene - 1, 0);         city_table[pos].select_list = (int) tour1[pos];
city_table[(int)tour1[pos]].used = 1;    /* mark used */     }
 
diff --git a/src/backend/optimizer/geqo/geqo_pmx.c b/src/backend/optimizer/geqo/geqo_pmx.c
index fe9d4b4..a8d18c5 100644
*** a/src/backend/optimizer/geqo/geqo_pmx.c
--- b/src/backend/optimizer/geqo/geqo_pmx.c
***************
*** 34,39 ****
--- 34,40 ---- /*************************************************************/  #include "postgres.h"
+ #include "optimizer/geqo.h" #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" 
***************
*** 43,49 ****  *     partially matched crossover  */ void
! pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene) {     int           *failed = (int *) palloc((num_gene +
1)* sizeof(int));     int           *from = (int *) palloc((num_gene + 1) * sizeof(int));
 
--- 44,50 ----  *     partially matched crossover  */ void
! pmx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene) {     int           *failed = (int *)
palloc((num_gene+ 1) * sizeof(int));     int           *from = (int *) palloc((num_gene + 1) * sizeof(int));
 
*************** pmx(Gene *tour1, Gene *tour2, Gene *offs
*** 71,78 ****     }  /* locate crossover points */
!     left = geqo_randint(num_gene - 1, 0);
!     right = geqo_randint(num_gene - 1, 0);      if (left > right)     {
--- 72,79 ----     }  /* locate crossover points */
!     left = geqo_randint(root, num_gene - 1, 0);
!     right = geqo_randint(root, num_gene - 1, 0);      if (left > right)     {
diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c
index 72eb34f..64e23ba 100644
*** a/src/backend/optimizer/geqo/geqo_pool.c
--- b/src/backend/optimizer/geqo/geqo_pool.c
*************** static int    compare(const void *arg1, con
*** 39,45 ****  *        allocates memory for GA pool  */ Pool *
! alloc_pool(int pool_size, int string_length) {     Pool       *new_pool;     Chromosome *chromo;
--- 39,45 ----  *        allocates memory for GA pool  */ Pool *
! alloc_pool(PlannerInfo *root, int pool_size, int string_length) {     Pool       *new_pool;     Chromosome *chromo;
*************** alloc_pool(int pool_size, int string_len
*** 66,72 ****  *        deallocates memory for GA pool  */ void
! free_pool(Pool *pool) {     Chromosome *chromo;     int            i;
--- 66,72 ----  *        deallocates memory for GA pool  */ void
! free_pool(PlannerInfo *root, Pool *pool) {     Chromosome *chromo;     int            i;
*************** free_pool(Pool *pool)
*** 88,94 ****  *        initialize genetic pool  */ void
! random_init_pool(Pool *pool, GeqoEvalData *evaldata) {     Chromosome *chromo = (Chromosome *) pool->data;     int
       i;
 
--- 88,94 ----  *        initialize genetic pool  */ void
! random_init_pool(PlannerInfo *root, Pool *pool) {     Chromosome *chromo = (Chromosome *) pool->data;     int
  i;
 
*************** random_init_pool(Pool *pool, GeqoEvalDat
*** 105,114 ****     i = 0;     while (i < pool->size)     {
!         init_tour(chromo[i].string, pool->string_length);
!         pool->data[i].worth = geqo_eval(chromo[i].string,
!                                         pool->string_length,
!                                         evaldata);         if (pool->data[i].worth < DBL_MAX)             i++;
else
 
--- 105,113 ----     i = 0;     while (i < pool->size)     {
!         init_tour(root, chromo[i].string, pool->string_length);
!         pool->data[i].worth = geqo_eval(root, chromo[i].string,
!                                         pool->string_length);         if (pool->data[i].worth < DBL_MAX)
i++;        else
 
*************** random_init_pool(Pool *pool, GeqoEvalDat
*** 133,139 ****  *     maybe you have to change compare() for different ordering ...  */ void
! sort_pool(Pool *pool) {     qsort(pool->data, pool->size, sizeof(Chromosome), compare); }
--- 132,138 ----  *     maybe you have to change compare() for different ordering ...  */ void
! sort_pool(PlannerInfo *root, Pool *pool) {     qsort(pool->data, pool->size, sizeof(Chromosome), compare); }
*************** compare(const void *arg1, const void *ar
*** 160,166 ****  *      allocates a chromosome and string space  */ Chromosome *
! alloc_chromo(int string_length) {     Chromosome *chromo; 
--- 159,165 ----  *      allocates a chromosome and string space  */ Chromosome *
! alloc_chromo(PlannerInfo *root, int string_length) {     Chromosome *chromo; 
*************** alloc_chromo(int string_length)
*** 174,180 ****  *      deallocates a chromosome and string space  */ void
! free_chromo(Chromosome *chromo) {     pfree(chromo->string);     pfree(chromo);
--- 173,179 ----  *      deallocates a chromosome and string space  */ void
! free_chromo(PlannerInfo *root, Chromosome *chromo) {     pfree(chromo->string);     pfree(chromo);
*************** free_chromo(Chromosome *chromo)
*** 185,191 ****  *     assumes best->worst = smallest->largest  */ void
! spread_chromo(Chromosome *chromo, Pool *pool) {     int            top,                 mid,
--- 184,190 ----  *     assumes best->worst = smallest->largest  */ void
! spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool) {     int            top,                 mid,
*************** spread_chromo(Chromosome *chromo, Pool *
*** 247,253 ****      * copy new gene into pool storage; always replace worst gene in pool      */ 
!     geqo_copy(&pool->data[pool->size - 1], chromo, pool->string_length);      swap_chromo.string =
pool->data[pool->size- 1].string;     swap_chromo.worth = pool->data[pool->size - 1].worth;
 
--- 246,252 ----      * copy new gene into pool storage; always replace worst gene in pool      */ 
!     geqo_copy(root, &pool->data[pool->size - 1], chromo, pool->string_length);      swap_chromo.string =
pool->data[pool->size- 1].string;     swap_chromo.worth = pool->data[pool->size - 1].worth;
 
diff --git a/src/backend/optimizer/geqo/geqo_px.c b/src/backend/optimizer/geqo/geqo_px.c
index 07f41cd..9e9cee2 100644
*** a/src/backend/optimizer/geqo/geqo_px.c
--- b/src/backend/optimizer/geqo/geqo_px.c
***************
*** 34,39 ****
--- 34,40 ---- /*************************************************************/  #include "postgres.h"
+ #include "optimizer/geqo.h" #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" 
***************
*** 43,49 ****  *     position crossover  */ void
! px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) {      int            num_positions;
--- 44,51 ----  *     position crossover  */ void
! px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
!    City *city_table) {      int            num_positions;
*************** px(Gene *tour1, Gene *tour2, Gene *offsp
*** 57,68 ****         city_table[i].used = 0;      /* choose random positions that will be inherited directly from
parent*/
 
!     num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);      /* choose random position */     for (i = 0; i
<num_positions; i++)     {
 
!         pos = geqo_randint(num_gene - 1, 0);          offspring[pos] = tour1[pos];    /* transfer cities to child */
      city_table[(int) tour1[pos]].used = 1;    /* mark city used */
 
--- 59,70 ----         city_table[i].used = 0;      /* choose random positions that will be inherited directly from
parent*/
 
!     num_positions = geqo_randint(root, 2 * num_gene / 3, num_gene / 3);      /* choose random position */     for (i
=0; i < num_positions; i++)     {
 
!         pos = geqo_randint(root, num_gene - 1, 0);          offspring[pos] = tour1[pos];    /* transfer cities to
child*/         city_table[(int) tour1[pos]].used = 1;    /* mark city used */
 
diff --git a/src/backend/optimizer/geqo/geqo_random.c b/src/backend/optimizer/geqo/geqo_random.c
index ...59d5e42 .
*** a/src/backend/optimizer/geqo/geqo_random.c
--- b/src/backend/optimizer/geqo/geqo_random.c
***************
*** 0 ****
--- 1,42 ----
+ /*------------------------------------------------------------------------
+  *
+  * geqo_misc.c
+  *       misc. printout and debug stuff
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "optimizer/geqo.h"
+ #include "optimizer/geqo_random.h"
+ 
+ 
+ static unsigned short global_random_state[3];
+ 
+ void geqo_seed(PlannerInfo *root, double seed){
+     GeqoPrivateData *private = (GeqoPrivateData*)root->join_search_private;
+ 
+     private->random_state = palloc(sizeof(global_random_state));
+ 
+     /*
+      * XXX. This seeding algorithm could certainly be improved - but
+      * it is not critical to do so.
+      */
+     memcpy(private->random_state,
+            &seed,
+            Min(sizeof(global_random_state),
+                sizeof(seed))
+         );
+ }
+ 
+ double geqo_rand(PlannerInfo *root){
+     if(!((GeqoPrivateData*)root->join_search_private)->random_state)
+         return erand48(global_random_state);
+     return erand48(((GeqoPrivateData*)root->join_search_private)->random_state);
+ };
diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c
index 3972fb1..e2b69a3 100644
*** a/src/backend/optimizer/geqo/geqo_recombination.c
--- b/src/backend/optimizer/geqo/geqo_recombination.c
***************
*** 20,25 ****
--- 20,26 ----  #include "postgres.h" 
+ #include "optimizer/geqo.h" #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" 
***************
*** 35,41 ****  *     and the procedure repeated.  */ void
! init_tour(Gene *tour, int num_gene) {     Gene       *tmp;     int            remainder;
--- 36,42 ----  *     and the procedure repeated.  */ void
! init_tour(PlannerInfo *root, Gene *tour, int num_gene) {     Gene       *tmp;     int            remainder;
*************** init_tour(Gene *tour, int num_gene)
*** 53,59 ****     for (i = 0; i < num_gene; i++)     {         /* choose value between 0 and remainder inclusive */
!         next = (int) geqo_randint(remainder, 0);         /* output that element of the tmp array */         tour[i] =
tmp[next];        /* and delete it */
 
--- 54,60 ----     for (i = 0; i < num_gene; i++)     {         /* choose value between 0 and remainder inclusive */
!         next = (int) geqo_randint(root, remainder, 0);         /* output that element of the tmp array */
tour[i]= tmp[next];         /* and delete it */
 
*************** init_tour(Gene *tour, int num_gene)
*** 81,87 ****  *     allocate memory for city table  */ City *
! alloc_city_table(int num_gene) {     City       *city_table; 
--- 82,88 ----  *     allocate memory for city table  */ City *
! alloc_city_table(PlannerInfo *root, int num_gene) {     City       *city_table; 
*************** alloc_city_table(int num_gene)
*** 99,105 ****  *      deallocate memory of city table  */ void
! free_city_table(City *city_table) {     pfree(city_table); }
--- 100,106 ----  *      deallocate memory of city table  */ void
! free_city_table(PlannerInfo *root, City *city_table) {     pfree(city_table); }
diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c
index d4f2c4d..2cd7402 100644
*** a/src/backend/optimizer/geqo/geqo_selection.c
--- b/src/backend/optimizer/geqo/geqo_selection.c
***************
*** 42,48 **** #include "optimizer/geqo_random.h" #include "optimizer/geqo_selection.h" 
! static int    linear(int max, double bias);   /*
--- 42,48 ---- #include "optimizer/geqo_random.h" #include "optimizer/geqo_selection.h" 
! static int    linear(PlannerInfo *root, int max, double bias);   /*
*************** static int    linear(int max, double bias);
*** 51,72 ****  *     first and second genes are selected from the pool  */ void
! geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias) {     int            first,
   second; 
 
!     first = linear(pool->size, bias);
!     second = linear(pool->size, bias);      if (pool->size > 1)     {         while (first == second)
!             second = linear(pool->size, bias);     } 
!     geqo_copy(momma, &pool->data[first], pool->string_length);
!     geqo_copy(daddy, &pool->data[second], pool->string_length); }  /*
--- 51,73 ----  *     first and second genes are selected from the pool  */ void
! geqo_selection(PlannerInfo *root, Chromosome *momma, Chromosome *daddy,
!                Pool *pool, double bias) {     int            first,                 second; 
!     first = linear(root, pool->size, bias);
!     second = linear(root, pool->size, bias);      if (pool->size > 1)     {         while (first == second)
!             second = linear(root, pool->size, bias);     } 
!     geqo_copy(root, momma, &pool->data[first], pool->string_length);
!     geqo_copy(root, daddy, &pool->data[second], pool->string_length); }  /*
*************** geqo_selection(Chromosome *momma, Chromo
*** 78,84 ****  *             bias = (prob of first rule) / (prob of middle rule)  */ static int
! linear(int pool_size, double bias)        /* bias is y-intercept of linear                                          *
distribution*/ {     double        index;            /* index between 0 and pop_size */
 
--- 79,85 ----  *             bias = (prob of first rule) / (prob of middle rule)  */ static int
! linear(PlannerInfo *root, int pool_size, double bias)        /* bias is y-intercept of linear
                * distribution */ {     double        index;            /* index between 0 and pop_size */
 
*************** linear(int pool_size, double bias)        /* b
*** 95,101 ****     {         double        sqrtval; 
!         sqrtval = (bias * bias) - 4.0 * (bias - 1.0) * geqo_rand();         if (sqrtval > 0.0)             sqrtval =
sqrt(sqrtval);        index = max * (bias - sqrtval) / 2.0 / (bias - 1.0);
 
--- 96,102 ----     {         double        sqrtval; 
!         sqrtval = (bias * bias) - 4.0 * (bias - 1.0) * geqo_rand(root);         if (sqrtval > 0.0)
sqrtval= sqrt(sqrtval);         index = max * (bias - sqrtval) / 2.0 / (bias - 1.0);
 
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b375902..777d75d 100644
*** a/src/backend/optimizer/path/allpaths.c
--- b/src/backend/optimizer/path/allpaths.c
*************** standard_join_search(PlannerInfo *root, 
*** 901,906 ****
--- 901,908 ----     int            lev;     RelOptInfo *rel; 
+     Assert(root->join_search_private == 0);
+      /*      * We employ a simple "dynamic programming" algorithm: we first find all      * ways to build joins of
twojointree items, then all ways to build joins
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 2430185..4126516 100644
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** static struct config_real ConfigureNames
*** 2026,2031 ****
--- 2026,2040 ----         DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS,         MAX_GEQO_SELECTION_BIAS, NULL,
NULL    },
 
+     {
+         {"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
+             gettext_noop("GEQO: seed for random path selection for repeatable plan generation."),
+             gettext_noop("If zero planning will not be repeatable"),
+             GUC_NOT_IN_SAMPLE
+         },
+         &Geqo_seed,
+         0, 0, 1, NULL, NULL
+     },      {         {"bgwriter_lru_multiplier", PGC_SIGHUP, RESOURCES,
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index ea48889..8f82d71 100644
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
*************** typedef struct PlannerInfo
*** 192,197 ****
--- 192,200 ----     /* These fields are used only when hasRecursion is true: */     int            wt_param_id;    /*
PARAM_EXECID for the work table */     struct Plan *non_recursive_plan;    /* plan for non-recursive term */
 
+ 
+     /* private data for join-order implementation, i.e. GEQO */
+     void        *join_search_private; } PlannerInfo;  
diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h
index ea4c812..7a9b6a4 100644
*** a/src/include/optimizer/geqo.h
--- b/src/include/optimizer/geqo.h
*************** extern int    Geqo_pool_size;        /* 2 .. inf,
*** 59,88 **** extern int    Geqo_generations;    /* 1 .. inf, or 0 to use default */  extern double
Geqo_selection_bias; #define DEFAULT_GEQO_SELECTION_BIAS 2.0 #define MIN_GEQO_SELECTION_BIAS 1.5 #define
MAX_GEQO_SELECTION_BIAS2.0  
 
- /*
-  * Data structure to encapsulate information needed for building plan trees
-  * (i.e., geqo_eval and gimme_tree).
-  */ typedef struct {
!     PlannerInfo *root;            /* the query we are planning */
!     List       *initial_rels;    /* the base relations */
! } GeqoEvalData;
!   /* routines in geqo_main.c */ extern RelOptInfo *geqo(PlannerInfo *root,      int number_of_rels, List
*initial_rels); /* routines in geqo_eval.c */
 
! extern Cost geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata);
! extern RelOptInfo *gimme_tree(Gene *tour, int num_gene,
!            GeqoEvalData *evaldata);  #endif   /* GEQO_H */
--- 59,83 ---- extern int    Geqo_generations;    /* 1 .. inf, or 0 to use default */  extern double
Geqo_selection_bias;
+ extern double Geqo_seed;  #define DEFAULT_GEQO_SELECTION_BIAS 2.0 #define MIN_GEQO_SELECTION_BIAS 1.5 #define
MAX_GEQO_SELECTION_BIAS2.0   typedef struct {
 
!     List *initial_rels;
!     unsigned short *random_state;
! } GeqoPrivateData;  /* routines in geqo_main.c */ extern RelOptInfo *geqo(PlannerInfo *root,      int number_of_rels,
List*initial_rels);  /* routines in geqo_eval.c */
 
! extern Cost geqo_eval(PlannerInfo *root, Gene *tour, int num_geneo);
! extern RelOptInfo *gimme_tree(PlannerInfo *root, Gene *tour, int num_gene);  #endif   /* GEQO_H */
diff --git a/src/include/optimizer/geqo_copy.h b/src/include/optimizer/geqo_copy.h
index ae13059..63b7c83 100644
*** a/src/include/optimizer/geqo_copy.h
--- b/src/include/optimizer/geqo_copy.h
***************
*** 22,29 **** #ifndef GEQO_COPY_H #define GEQO_COPY_H  #include "optimizer/geqo_gene.h" 
! extern void geqo_copy(Chromosome *chromo1, Chromosome *chromo2, int string_length);  #endif   /* GEQO_COPY_H */
--- 22,30 ---- #ifndef GEQO_COPY_H #define GEQO_COPY_H 
+ #include "optimizer/geqo.h" #include "optimizer/geqo_gene.h" 
! extern void geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2, int string_length);  #endif   /*
GEQO_COPY_H*/
 
diff --git a/src/include/optimizer/geqo_mutation.h b/src/include/optimizer/geqo_mutation.h
index 0384de8..3ada430 100644
*** a/src/include/optimizer/geqo_mutation.h
--- b/src/include/optimizer/geqo_mutation.h
***************
*** 22,29 **** #ifndef GEQO_MUTATION_H #define GEQO_MUTATION_H  #include "optimizer/geqo_gene.h" 
! extern void geqo_mutation(Gene *tour, int num_gene);  #endif   /* GEQO_MUTATION_H */
--- 22,30 ---- #ifndef GEQO_MUTATION_H #define GEQO_MUTATION_H 
+ #include "optimizer/geqo.h" #include "optimizer/geqo_gene.h" 
! extern void geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene);  #endif   /* GEQO_MUTATION_H */
diff --git a/src/include/optimizer/geqo_pool.h b/src/include/optimizer/geqo_pool.h
index 950e667..dbc6a01 100644
*** a/src/include/optimizer/geqo_pool.h
--- b/src/include/optimizer/geqo_pool.h
***************
*** 26,40 **** #include "optimizer/geqo.h"  
! extern Pool *alloc_pool(int pool_size, int string_length);
! extern void free_pool(Pool *pool); 
! extern void random_init_pool(Pool *pool, GeqoEvalData *evaldata);
! extern Chromosome *alloc_chromo(int string_length);
! extern void free_chromo(Chromosome *chromo); 
! extern void spread_chromo(Chromosome *chromo, Pool *pool); 
! extern void sort_pool(Pool *pool);  #endif   /* GEQO_POOL_H */
--- 26,40 ---- #include "optimizer/geqo.h"  
! extern Pool *alloc_pool(PlannerInfo *root, int pool_size, int string_length);
! extern void free_pool(PlannerInfo *root, Pool *pool); 
! extern void random_init_pool(PlannerInfo *root, Pool *pool);
! extern Chromosome *alloc_chromo(PlannerInfo *root, int string_length);
! extern void free_chromo(PlannerInfo *root, Chromosome *chromo); 
! extern void spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool); 
! extern void sort_pool(PlannerInfo *root, Pool *pool);  #endif   /* GEQO_POOL_H */
diff --git a/src/include/optimizer/geqo_random.h b/src/include/optimizer/geqo_random.h
index fab0728..6fcfa7f 100644
*** a/src/include/optimizer/geqo_random.h
--- b/src/include/optimizer/geqo_random.h
***************
*** 27,38 **** #include <math.h>  /* geqo_rand returns a random float value between 0 and 1 inclusive */
! 
! #define geqo_rand() ((double) random() / (double) MAX_RANDOM_VALUE)  /* geqo_randint returns integer value between
lowerand upper inclusive */
 
! 
! #define geqo_randint(upper,lower) \
!     ( (int) floor( geqo_rand()*(((upper)-(lower))+0.999999) ) + (lower) )  #endif   /* GEQO_RANDOM_H */
--- 27,37 ---- #include <math.h>  /* geqo_rand returns a random float value between 0 and 1 inclusive */
! double geqo_rand(PlannerInfo *root);
! void geqo_seed(PlannerInfo *root, double);  /* geqo_randint returns integer value between lower and upper inclusive
*/
! #define geqo_randint(root, upper,lower)                        \
!     ( (int) floor( geqo_rand(root)*(((upper)-(lower))+0.999999) ) + (lower) )  #endif   /* GEQO_RANDOM_H */
diff --git a/src/include/optimizer/geqo_recombination.h b/src/include/optimizer/geqo_recombination.h
index 2c4a338..2484259 100644
*** a/src/include/optimizer/geqo_recombination.h
--- b/src/include/optimizer/geqo_recombination.h
***************
*** 24,32 **** #ifndef GEQO_RECOMBINATION_H #define GEQO_RECOMBINATION_H  #include "optimizer/geqo_gene.h" 
! extern void init_tour(Gene *tour, int num_gene);   /* edge recombination crossover [ERX] */
--- 24,33 ---- #ifndef GEQO_RECOMBINATION_H #define GEQO_RECOMBINATION_H 
+ #include "optimizer/geqo.h" #include "optimizer/geqo_gene.h" 
! extern void init_tour(PlannerInfo *root, Gene *tour, int num_gene);   /* edge recombination crossover [ERX] */
*************** typedef struct Edge
*** 38,49 ****     int            unused_edges; } Edge; 
! extern Edge *alloc_edge_table(int num_gene);
! extern void free_edge_table(Edge *edge_table); 
! extern float gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table); 
! extern int    gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene);   /* partially matched crossover [PMX] */
--- 39,52 ----     int            unused_edges; } Edge; 
! extern Edge *alloc_edge_table(PlannerInfo *root, int num_gene);
! extern void free_edge_table(PlannerInfo *root, Edge *edge_table); 
! extern float gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2,
!                               int num_gene, Edge *edge_table); 
! extern int    gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene,
!                        int num_gene);   /* partially matched crossover [PMX] */
*************** extern int    gimme_tour(Edge *edge_table, 
*** 51,57 **** #define DAD 1                    /* indicator for gene from dad */ #define MOM 0                    /*
indicatorfor gene from mom */ 
 
! extern void pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene);   typedef struct City
--- 54,62 ---- #define DAD 1                    /* indicator for gene from dad */ #define MOM 0                    /*
indicatorfor gene from mom */ 
 
! extern void pmx(PlannerInfo *root,
!                 Gene *tour1, Gene *tour2,
!                 Gene *offspring, int num_gene);   typedef struct City
*************** typedef struct City
*** 62,80 ****     int            select_list; } City; 
! extern City *alloc_city_table(int num_gene);
! extern void free_city_table(City *city_table);  /* cycle crossover [CX] */
! extern int    cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table);  /* position crossover
[PX]*/
 
! extern void px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table);  /* order crossover [OX1]
accordingto Davis */
 
! extern void ox1(Gene *mom, Gene *dad, Gene *offspring, int num_gene, City *city_table);  /* order crossover [OX2]
accordingto Syswerda */
 
! extern void ox2(Gene *mom, Gene *dad, Gene *offspring, int num_gene, City *city_table);  #endif   /*
GEQO_RECOMBINATION_H*/
 
--- 67,89 ----     int            select_list; } City; 
! extern City *alloc_city_table(PlannerInfo *root, int num_gene);
! extern void free_city_table(PlannerInfo *root, City *city_table);  /* cycle crossover [CX] */
! extern int    cx(PlannerInfo *root, Gene *tour1, Gene *tour2,
!                Gene *offspring, int num_gene, City *city_table);  /* position crossover [PX] */
! extern void px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
!                int num_gene, City *city_table);  /* order crossover [OX1] according to Davis */
! extern void ox1(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring,
!                 int num_gene, City *city_table);  /* order crossover [OX2] according to Syswerda */
! extern void ox2(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring,
!                 int num_gene, City *city_table);  #endif   /* GEQO_RECOMBINATION_H */
diff --git a/src/include/optimizer/geqo_selection.h b/src/include/optimizer/geqo_selection.h
index 4b336d1..7e93cb4 100644
*** a/src/include/optimizer/geqo_selection.h
--- b/src/include/optimizer/geqo_selection.h
***************
*** 25,30 ****  #include "optimizer/geqo_gene.h" 
! extern void geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias);  #endif   /*
GEQO_SELECTION_H*/
 
--- 25,32 ----  #include "optimizer/geqo_gene.h" 
! extern void geqo_selection(PlannerInfo *root,
!                            Chromosome *momma, Chromosome *daddy,
!                            Pool *pool, double bias);  #endif   /* GEQO_SELECTION_H */
-- 
1.6.3.3.335.ge09a8



Re: [PATCH 3/3] Document geqo_seed variable.

From
Robert Haas
Date:
On Tue, Jul 14, 2009 at 6:34 PM, Andres Freund<andres@anarazel.de> wrote:
> ---
>  doc/src/sgml/config.sgml |   16 ++++++++++++++++
>  1 files changed, 16 insertions(+), 0 deletions(-)
>
> diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
> index 99d25d7..5d8eca9 100644
> *** a/doc/src/sgml/config.sgml
> --- b/doc/src/sgml/config.sgml
> *************** archive_command = 'copy "%p" "C:\\server
> *** 2150,2155 ****
> --- 2150,2171 ----
>        </listitem>
>       </varlistentry>
>
> +      <varlistentry id="guc-geqo-seed" xreflabel="geqo_seed">
> +       <term><varname>geqo_seed</varname>
> +       (<type>floating point</type>)</term>
> +       <indexterm>
> +        <primary><varname>geqo_seed</> configuration parameter</primary>
> +       </indexterm>
> +       <listitem>
> +        <para>
> +         Controls the initialization of the random number generator used
> +         by GEQO to select random paths through the join order search space.
> +         With the default setting of zero the join order planning is not repeatable.
> +         For repeatable planning set a value between 0 (exclusive) and 1 (inclusive).
> +        </para>
> +       </listitem>
> +      </varlistentry>
> +
>       </variablelist>
>      </sect2>
>       <sect2 id="runtime-config-query-other">
> --
> 1.6.3.3.335.ge09a8

I don't understand why people (including yourself, but you're not the
only one) have begun submitting relatively trivial patches in multiple
parts.  This just creates multiple threads on the mailing list without
adding any value.  The doc changes are part of the patch; one email
containing all the changes seems vastly preferable to me.

IMHO, the only reason for submitting multiple patches if it there are
pieces that are separately commitable.

...Robert


Re: [PATCH 3/3] Document geqo_seed variable.

From
Andres Freund
Date:
Hi,

On Wednesday 15 July 2009 04:14:16 Robert Haas wrote:
> On Tue, Jul 14, 2009 at 6:34 PM, Andres Freund<andres@anarazel.de> wrote:
> > ---
> >  doc/src/sgml/config.sgml |   16 ++++++++++++++++
> >  1 files changed, 16 insertions(+), 0 deletions(-)
> >
> > diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
> > index 99d25d7..5d8eca9 100644
> > *** a/doc/src/sgml/config.sgml
> > --- b/doc/src/sgml/config.sgml
> > *************** archive_command = 'copy "%p" "C:\\server
> > *** 2150,2155 ****
> > --- 2150,2171 ----
> >        </listitem>
> >       </varlistentry>
> >
> > +      <varlistentry id="guc-geqo-seed" xreflabel="geqo_seed">
> > +       <term><varname>geqo_seed</varname>
> > +       (<type>floating point</type>)</term>
> > +       <indexterm>
> > +        <primary><varname>geqo_seed</> configuration parameter</primary>
> > +       </indexterm>
> > +       <listitem>
> > +        <para>
> > +         Controls the initialization of the random number generator used
> > +         by GEQO to select random paths through the join order search
> > space. +         With the default setting of zero the join order planning
> > is not repeatable. +         For repeatable planning set a value between
> > 0 (exclusive) and 1 (inclusive). +        </para>
> > +       </listitem>
> > +      </varlistentry>
> > +
> >       </variablelist>
> >      </sect2>
> >       <sect2 id="runtime-config-query-other">
> > --
> > 1.6.3.3.335.ge09a8
>
> I don't understand why people (including yourself, but you're not the
> only one) have begun submitting relatively trivial patches in multiple
> parts.  This just creates multiple threads on the mailing list without
> adding any value.  The doc changes are part of the patch; one email
> containing all the changes seems vastly preferable to me.
For one reason it got easy. For another doing so - except the doc patch 
admittedly - makes it potentially easier to bisect changes (Spent to much time 
bisecting kernel problems I guess).
I also find it easier to read a patch when I know what kind of issues to 
expect.
For example the patch adding erand48 should definitely be looked at on by 
somebody with windows whereas the repetitious changes to GEQO itself do not 
necessarily be tested on windows.

It should not create multiple threads I think as all messages were a response 
the first mail?

> IMHO, the only reason for submitting multiple patches if it there are
> pieces that are separately commitable.
PG has rather coarse grained commits. I guess some people are not used to that 
from their own experience anymore....

Andres


Re: [PATCH 3/3] Document geqo_seed variable.

From
Bernd Helmle
Date:

--On 15. Juli 2009 08:06:48 +0200 Andres Freund <andres@anarazel.de> wrote:

> It should not create multiple threads I think as all messages were a
> response  the first mail?

It does (at least my MUA understood that correctly), but since many people 
are reading in a "backlog"-style manner, i have to agree with Robert. It 
makes it a little bit harder to track all changes which are intended by a 
specific discussion.

-- 
Thanks
Bernd


Re: [PATCH 3/3] Document geqo_seed variable.

From
Robert Haas
Date:
On Wed, Jul 15, 2009 at 10:13 AM, Bernd Helmle<mailings@oopsware.de> wrote:
> --On 15. Juli 2009 08:06:48 +0200 Andres Freund <andres@anarazel.de> wrote:
>
>> It should not create multiple threads I think as all messages were a
>> response  the first mail?
>
> It does (at least my MUA understood that correctly), but since many people
> are reading in a "backlog"-style manner, i have to agree with Robert. It
> makes it a little bit harder to track all changes which are intended by a
> specific discussion.

Gmail starts a new thread if the subject line is changed, but I'm not
going to hold the entire world hostage to my preferred email client.
There are other problems, too, like if I want to apply this patch I
have to download multiple emails to do it, and multiple links have to
be added to the CommitFest app to reference the different parts.

...Robert


Re: [PATCH 3/3] Document geqo_seed variable.

From
Andres Freund
Date:
On Wednesday 15 July 2009 19:01:05 Robert Haas wrote:
> On Wed, Jul 15, 2009 at 10:13 AM, Bernd Helmle<mailings@oopsware.de> wrote:
> > --On 15. Juli 2009 08:06:48 +0200 Andres Freund <andres@anarazel.de> 
wrote:
> >> It should not create multiple threads I think as all messages were a
> >> response  the first mail?
> > It does (at least my MUA understood that correctly), but since many
> > people are reading in a "backlog"-style manner, i have to agree with
> > Robert. It makes it a little bit harder to track all changes which are
> > intended by a specific discussion.
For me its easier, as the different discussions are kept separate...

> Gmail starts a new thread if the subject line is changed, but I'm not
> going to hold the entire world hostage to my preferred email client.
> There are other problems, too, like if I want to apply this patch I
> have to download multiple emails to do it, and multiple links have to
> be added to the CommitFest app to reference the different parts.
Referencing the top Mail seems enough for me. To apply patches from mail I 
have setup a filter which can apply an mbox directly...

But as patches I send are not intended to be consumed by me, I will stop 
sending patches like that ;-)

Andres

PS: Gmail is a strange beast.


Re: Make planning via GEQO repeatable

From
Tom Lane
Date:
Andres Freund <andres@anarazel.de> writes:
> Query planning via GEQO currently can yield a different plan on every
> invokation of the planner due to its non-exhaustive nature.
> This often can be inconvenient because at times there may be a very
> bad plan. It also makes it very hard to reproduce a problem with GEQO.

Applied with some editorialization.  Mainly, I didn't see the point of
preserving the ability to have nondeterministic planning, and I
especially didn't care for having that still be the default behavior.
So I just made it unconditionally initialize the seed.  It would of
course take only minor tweaking to do things differently.
        regards, tom lane


Re: Make planning via GEQO repeatable

From
Andres Freund
Date:
On Thursday 16 July 2009 23:04:58 Tom Lane wrote:
> Andres Freund <andres@anarazel.de> writes:
> > Query planning via GEQO currently can yield a different plan on every
> > invokation of the planner due to its non-exhaustive nature.
> > This often can be inconvenient because at times there may be a very
> > bad plan. It also makes it very hard to reproduce a problem with GEQO.
>
> Applied with some editorialization.  Mainly, I didn't see the point of
> preserving the ability to have nondeterministic planning, and I
> especially didn't care for having that still be the default behavior.
> So I just made it unconditionally initialize the seed.  It would of
> course take only minor tweaking to do things differently.
Nice. 
Mainly I did not have the guts to change the behaviour completely...

archive.org has a copy of the dead link to the comp.ai.genetic FAQ linked at
http://web.archive.org/web/20051226001402/http://www.cs.bham.ac.uk/Mirrors/ftp.de.uu.net/EC/clife/www/location.htm
which is the same as the one referenced by alvaro in
http://archives.postgresql.org/pgsql-docs/2009-07/msg00004.php

If considerered relevant enough, you can update the link...


Andres