Make GEQO's planning deterministic by having it start from a predictable
authorTom Lane <[email protected]>
Thu, 16 Jul 2009 20:55:44 +0000 (20:55 +0000)
committerTom Lane <[email protected]>
Thu, 16 Jul 2009 20:55:44 +0000 (20:55 +0000)
random number seed each time.  This is how it used to work years ago, but
we got rid of the seed reset because it was resetting the main random()
sequence and thus having undesirable effects on the rest of the system.
To fix, establish a private random number state for each execution of
geqo(), and initialize the state using the new GUC variable geqo_seed.
People who want to experiment with different random searches can do so
by changing geqo_seed, but you'll always get the same plan for the same
value of geqo_seed (if holding all other planner inputs constant, of course).

The new state is kept in PlannerInfo by adding a "void *" field reserved
for use by join_search hooks.  Most of the rather bulky code changes in
this commit are just arranging to pass PlannerInfo around to all the GEQO
functions (many of which formerly didn't receive it).

Andres Freund, with some editorialization by Tom

27 files changed:
doc/src/sgml/config.sgml
doc/src/sgml/geqo.sgml
src/backend/optimizer/geqo/Makefile
src/backend/optimizer/geqo/geqo_copy.c
src/backend/optimizer/geqo/geqo_cx.c
src/backend/optimizer/geqo/geqo_erx.c
src/backend/optimizer/geqo/geqo_eval.c
src/backend/optimizer/geqo/geqo_main.c
src/backend/optimizer/geqo/geqo_mutation.c
src/backend/optimizer/geqo/geqo_ox1.c
src/backend/optimizer/geqo/geqo_ox2.c
src/backend/optimizer/geqo/geqo_pmx.c
src/backend/optimizer/geqo/geqo_pool.c
src/backend/optimizer/geqo/geqo_px.c
src/backend/optimizer/geqo/geqo_random.c [new file with mode: 0644]
src/backend/optimizer/geqo/geqo_recombination.c
src/backend/optimizer/geqo/geqo_selection.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/nodes/relation.h
src/include/optimizer/geqo.h
src/include/optimizer/geqo_copy.h
src/include/optimizer/geqo_mutation.h
src/include/optimizer/geqo_pool.h
src/include/optimizer/geqo_random.h
src/include/optimizer/geqo_recombination.h
src/include/optimizer/geqo_selection.h

index 3b527a7ecbd51f034a927b74d70387e85d296264..a86ba6089a49395d072dc5fb99fddfd78569512a 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.221 2009/07/03 19:14:25 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.222 2009/07/16 20:55:44 tgl Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -2149,7 +2149,23 @@ archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"'  # Windows
        </para>
       </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 initial value of the random number generator used
+        by GEQO to select random paths through the join order search space.
+        The value can range from zero (the default) to one.  Varying the
+        value changes the set of join paths explored, and may result in a
+        better or worse best path being found.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
      <sect2 id="runtime-config-query-other">
index 2f680762c13bb45c3b85bbba5c43011de112eb4b..97961272a4ae97150f6d1518b34d40523cf25a04 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/geqo.sgml,v 1.40 2007/07/21 04:02:41 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/geqo.sgml,v 1.41 2009/07/16 20:55:44 tgl Exp $ -->
 
  <chapter id="geqo">
   <chapterinfo>
@@ -49,7 +49,7 @@
     methods</firstterm> (e.g., nested loop, hash join, merge join in
     <productname>PostgreSQL</productname>) to process individual joins
     and a diversity of <firstterm>indexes</firstterm> (e.g.,
-    B-tree, hash, GiST and GIN in <productname>PostgreSQL</productname>) as 
+    B-tree, hash, GiST and GIN in <productname>PostgreSQL</productname>) as
     access paths for relations.
    </para>
 
@@ -88,8 +88,7 @@
 
    <para>
     The genetic algorithm (<acronym>GA</acronym>) is a heuristic optimization method which
-    operates through
-    nondeterministic, randomized search. The set of possible solutions for the
+    operates through randomized search. The set of possible solutions for the
     optimization problem is considered as a
     <firstterm>population</firstterm> of <firstterm>individuals</firstterm>.
     The degree of adaptation of an individual to its environment is specified
     According to the <systemitem class="resource">comp.ai.genetic</> <acronym>FAQ</acronym> it cannot be stressed too
     strongly that a <acronym>GA</acronym> is not a pure random search for a solution to a
     problem. A <acronym>GA</acronym> uses stochastic processes, but the result is distinctly
-    non-random (better than random). 
+    non-random (better than random).
    </para>
 
    <figure id="geqo-diagram">
    <para>
     This process is inherently nondeterministic, because of the randomized
     choices made during both the initial population selection and subsequent
-    <quote>mutation</> of the best candidates.  Hence different plans may
-    be selected from one run to the next, resulting in varying run time
-    and varying output row order.
+    <quote>mutation</> of the best candidates.  To avoid surprising changes
+    of the selected plan, each run of the GEQO algorithm restarts its
+    random number generator with the current <xref linkend="guc-geqo-seed">
+    parameter setting.  As long as <varname>geqo_seed</> and the other
+    GEQO parameters are kept fixed, the same plan will be generated for a
+    given query (and other planner inputs such as statistics).  To experiment
+    with different search paths, try changing <varname>geqo_seed</>.
    </para>
 
   </sect2>
       url="news://comp.ai.genetic"></ulink>)
      </para>
     </listitem>
-   
+
     <listitem>
      <para>
       <ulink url="http://www.red3d.com/cwr/evolve.html">
index becc95f2ef4378b6fb2bd4f7d231a18c8debfc93..9ccfd9e60c85934e5c1da1494f6cc0864770912d 100644 (file)
@@ -5,7 +5,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/backend/optimizer/geqo/Makefile,v 1.20 2008/02/19 10:30:07 petere Exp $
+# $PostgreSQL: pgsql/src/backend/optimizer/geqo/Makefile,v 1.21 2009/07/16 20:55:44 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,7 +14,7 @@ top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = geqo_copy.o geqo_eval.o geqo_main.o geqo_misc.o \
-   geqo_mutation.o geqo_pool.o geqo_recombination.o \
+   geqo_mutation.o geqo_pool.o geqo_random.o geqo_recombination.o \
    geqo_selection.o \
    geqo_erx.o geqo_pmx.o geqo_cx.o geqo_px.o geqo_ox1.o geqo_ox2.o
 
index 8e4aab214d6af73e3dbed04d36afca00de2d247f..1c7498c959ca0b851c036be47f83f7ce9fecd485 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_copy.c,v 1.19 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_copy.c,v 1.20 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,8 @@
  *
  */
 void
-geqo_copy(Chromosome *chromo1, Chromosome *chromo2, int string_length)
+geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2,
+         int string_length)
 {
    int         i;
 
index 616ff41fb9734fe7a37c419adc943713b37675f0..9f3dfe216e0c49686e9086a3102c21cd25f1fc82 100644 (file)
@@ -6,7 +6,7 @@
 *   CX operator according to Oliver et al
 *   (Proc 2nd Int'l Conf on GA's)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_cx.c,v 1.10 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_cx.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -44,7 +44,8 @@
  *  cycle crossover
  */
 int
-cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+cx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
+   int num_gene, City *city_table)
 {
 
    int         i,
@@ -62,7 +63,7 @@ cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
    }
 
    /* choose random cycle starting position */
-   start_pos = geqo_randint(num_gene - 1, 0);
+   start_pos = geqo_randint(root, num_gene - 1, 0);
 
    /* child inherits first city  */
    offspring[start_pos] = tour1[start_pos];
index 9c7a34258582d08f421780c7e9ca72bd1de95ff8..45effbdad95c93cc1ddf6800860ee9ddcc15cfec 100644 (file)
@@ -3,7 +3,7 @@
 * geqo_erx.c
 *   edge recombination crossover [ER]
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_erx.c,v 1.20 2005/10/15 02:49:19 momjian Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_erx.c,v 1.21 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
 #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 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(Gene *gene, int index, Edge *edge_table, int num_gene);
+static Gene edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num_gene);
 
 
 /* alloc_edge_table
@@ -50,7 +50,7 @@ static Gene edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene);
  */
 
 Edge *
-alloc_edge_table(int num_gene)
+alloc_edge_table(PlannerInfo *root, int num_gene)
 {
    Edge       *edge_table;
 
@@ -70,7 +70,7 @@ alloc_edge_table(int num_gene)
  *
  */
 void
-free_edge_table(Edge *edge_table)
+free_edge_table(PlannerInfo *root, Edge *edge_table)
 {
    pfree(edge_table);
 }
@@ -89,7 +89,8 @@ free_edge_table(Edge *edge_table)
  *
  */
 float
-gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
+gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2,
+                int num_gene, Edge *edge_table)
 {
    int         i,
                index1,
@@ -121,11 +122,11 @@ gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
         * 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(root, tour1[index1], tour1[index2], edge_table);
+       gimme_edge(root, tour1[index2], tour1[index1], edge_table);
 
-       edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table);
-       gimme_edge(tour2[index2], tour2[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 */
@@ -147,7 +148,7 @@ gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
  *           0 if edge was already registered and edge_table is unchanged
  */
 static int
-gimme_edge(Gene gene1, Gene gene2, Edge *edge_table)
+gimme_edge(PlannerInfo *root, Gene gene1, Gene gene2, Edge *edge_table)
 {
    int         i;
    int         edges;
@@ -189,13 +190,13 @@ gimme_edge(Gene gene1, Gene gene2, Edge *edge_table)
  *
  */
 int
-gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene)
+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(num_gene, 1);     /* choose int between 1
-                                                        * and num_gene */
+   /* choose int between 1 and num_gene */
+   new_gene[0] = (Gene) geqo_randint(root, num_gene, 1);
 
    for (i = 1; i < num_gene; i++)
    {
@@ -204,18 +205,18 @@ gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene)
         * table
         */
 
-       remove_gene(new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);
+       remove_gene(root, new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);
 
        /* find destination for the newly 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);
+           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(new_gene, i - 1, edge_table, num_gene);
+           new_gene[i] = edge_failure(root, new_gene, i - 1, edge_table, num_gene);
        }
 
        /* mark this node as incorporated */
@@ -235,7 +236,7 @@ gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene)
  *
  */
 static void
-remove_gene(Gene gene, Edge edge, Edge *edge_table)
+remove_gene(PlannerInfo *root, Gene gene, Edge edge, Edge *edge_table)
 {
    int         i,
                j;
@@ -277,7 +278,7 @@ remove_gene(Gene gene, Edge edge, Edge *edge_table)
  *
  */
 static Gene
-gimme_gene(Edge edge, Edge *edge_table)
+gimme_gene(PlannerInfo *root, Edge edge, Edge *edge_table)
 {
    int         i;
    Gene        friend;
@@ -340,7 +341,7 @@ gimme_gene(Edge edge, Edge *edge_table)
 
 
    /* random decision of the possible candidates to use */
-   rand_decision = (int) geqo_randint(minimum_count - 1, 0);
+   rand_decision = geqo_randint(root, minimum_count - 1, 0);
 
 
    for (i = 0; i < edge.unused_edges; i++)
@@ -368,7 +369,7 @@ gimme_gene(Edge edge, Edge *edge_table)
  *
  */
 static Gene
-edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene)
+edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num_gene)
 {
    int         i;
    Gene        fail_gene = gene[index];
@@ -401,7 +402,7 @@ edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene)
    if (four_count != 0)
    {
 
-       rand_decision = (int) geqo_randint(four_count - 1, 0);
+       rand_decision = geqo_randint(root, four_count - 1, 0);
 
        for (i = 1; i <= num_gene; i++)
        {
@@ -423,7 +424,7 @@ edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene)
    else if (remaining_edges != 0)
    {
        /* random decision of the gene with remaining edges */
-       rand_decision = (int) geqo_randint(remaining_edges - 1, 0);
+       rand_decision = geqo_randint(root, remaining_edges - 1, 0);
 
        for (i = 1; i <= num_gene; i++)
        {
index 392cfc5aa318c399077866a9512701a1330fa168..226d64a94d96a7b36ed6f3ea53ff43159ecf50c6 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.88 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.89 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,7 @@ static bool desirable_join(PlannerInfo *root,
  * Returns cost of a query tree as an individual of the population.
  */
 Cost
-geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
+geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
 {
    MemoryContext mycontext;
    MemoryContext oldcxt;
@@ -94,13 +94,13 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
     * (If we are dealing with enough join rels, which we very likely are, a
     * new hash table will get built and used locally.)
     */
-   savelength = list_length(evaldata->root->join_rel_list);
-   savehash = evaldata->root->join_rel_hash;
+   savelength = list_length(root->join_rel_list);
+   savehash = root->join_rel_hash;
 
-   evaldata->root->join_rel_hash = NULL;
+   root->join_rel_hash = NULL;
 
    /* construct the best path for the given combination of relations */
-   joinrel = gimme_tree(tour, num_gene, evaldata);
+   joinrel = gimme_tree(root, tour, num_gene);
 
    /*
     * compute fitness
@@ -117,9 +117,9 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
     * 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;
+   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);
@@ -134,7 +134,6 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
  *   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.
@@ -153,8 +152,9 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
  * plans.
  */
 RelOptInfo *
-gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
+gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
 {
+   GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
    RelOptInfo **stack;
    int         stack_depth;
    RelOptInfo *joinrel;
@@ -193,7 +193,7 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
 
        /* Get the next input relation and push it */
        cur_rel_index = (int) tour[rel_count];
-       stack[stack_depth] = (RelOptInfo *) list_nth(evaldata->initial_rels,
+       stack[stack_depth] = (RelOptInfo *) list_nth(private->initial_rels,
                                                     cur_rel_index - 1);
        stack_depth++;
 
@@ -211,7 +211,7 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
             * have exhausted the input, the heuristics can't prevent popping.
             */
            if (rel_count < num_gene - 1 &&
-               !desirable_join(evaldata->root, outer_rel, inner_rel))
+               !desirable_join(root, outer_rel, inner_rel))
                break;
 
            /*
@@ -220,7 +220,7 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
             * root->join_rel_list yet, and so the paths constructed for it
             * will only include the ones we want.
             */
-           joinrel = make_join_rel(evaldata->root, outer_rel, inner_rel);
+           joinrel = make_join_rel(root, outer_rel, inner_rel);
 
            /* Can't pop stack here if join order is not valid */
            if (!joinrel)
index 08b5b1a44db23dfc235bce0ceab21d5f459bb3b7..824ae7b610817bc96e73aac1e14049ceb1fb4bc8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.56 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.57 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,9 @@
 #include <math.h>
 
 #include "optimizer/geqo_misc.h"
+#include "optimizer/geqo_mutation.h"
 #include "optimizer/geqo_pool.h"
+#include "optimizer/geqo_random.h"
 #include "optimizer/geqo_selection.h"
 
 
@@ -38,6 +40,7 @@ int           Geqo_effort;
 int            Geqo_pool_size;
 int            Geqo_generations;
 double     Geqo_selection_bias;
+double     Geqo_seed;
 
 
 static int gimme_pool_size(int nr_rel);
@@ -63,7 +66,7 @@ static int    gimme_number_generations(int pool_size);
 RelOptInfo *
 geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 {
-   GeqoEvalData evaldata;
+   GeqoPrivateData private;
    int         generation;
    Chromosome *momma;
    Chromosome *daddy;
@@ -88,9 +91,12 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
    int         mutations = 0;
 #endif
 
-/* set up evaldata */
-   evaldata.root = root;
-   evaldata.initial_rels = initial_rels;
+/* set up private information */
+   root->join_search_private = (void *) &private;
+   private.initial_rels = initial_rels;
+
+/* initialize private number generator */
+   geqo_set_seed(root, Geqo_seed);
 
 /* set GA parameters */
    pool_size = gimme_pool_size(number_of_rels);
@@ -98,13 +104,13 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
    status_interval = 10;
 
 /* allocate genetic pool memory */
-   pool = alloc_pool(pool_size, number_of_rels);
+   pool = alloc_pool(root, pool_size, number_of_rels);
 
 /* random initialization of the pool */
-   random_init_pool(pool, &evaldata);
+   random_init_pool(root, pool);
 
 /* sort the pool according to cheapest path as fitness */
-   sort_pool(pool);            /* we have to do it only one time, since all
+   sort_pool(root, pool);      /* we have to do it only one time, since all
                                 * kids replace the worst individuals in
                                 * future (-> geqo_pool.c:spread_chromo ) */
 
@@ -116,49 +122,49 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 #endif
 
 /* allocate chromosome momma and daddy memory */
-   momma = alloc_chromo(pool->string_length);
-   daddy = alloc_chromo(pool->string_length);
+   momma = alloc_chromo(root, pool->string_length);
+   daddy = alloc_chromo(root, pool->string_length);
 
 #if defined (ERX)
 #ifdef GEQO_DEBUG
    elog(DEBUG2, "using edge recombination crossover [ERX]");
 #endif
 /* allocate edge table memory */
-   edge_table = alloc_edge_table(pool->string_length);
+   edge_table = alloc_edge_table(root, pool->string_length);
 #elif defined(PMX)
 #ifdef GEQO_DEBUG
    elog(DEBUG2, "using partially matched crossover [PMX]");
 #endif
 /* allocate chromosome kid memory */
-   kid = alloc_chromo(pool->string_length);
+   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(pool->string_length);
-   city_table = alloc_city_table(pool->string_length);
+   kid = alloc_chromo(root, pool->string_length);
+   city_table = alloc_city_table(root, pool->string_length);
 #elif defined(PX)
 #ifdef GEQO_DEBUG
    elog(DEBUG2, "using position crossover [PX]");
 #endif
 /* allocate city table memory */
-   kid = alloc_chromo(pool->string_length);
-   city_table = alloc_city_table(pool->string_length);
+   kid = alloc_chromo(root, pool->string_length);
+   city_table = alloc_city_table(root, pool->string_length);
 #elif defined(OX1)
 #ifdef GEQO_DEBUG
    elog(DEBUG2, "using order crossover [OX1]");
 #endif
 /* allocate city table memory */
-   kid = alloc_chromo(pool->string_length);
-   city_table = alloc_city_table(pool->string_length);
+   kid = alloc_chromo(root, pool->string_length);
+   city_table = alloc_city_table(root, pool->string_length);
 #elif defined(OX2)
 #ifdef GEQO_DEBUG
    elog(DEBUG2, "using order crossover [OX2]");
 #endif
 /* allocate city table memory */
-   kid = alloc_chromo(pool->string_length);
-   city_table = alloc_city_table(pool->string_length);
+   kid = alloc_chromo(root, pool->string_length);
+   city_table = alloc_city_table(root, pool->string_length);
 #endif
 
 
@@ -168,45 +174,45 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
    for (generation = 0; generation < number_generations; generation++)
    {
        /* SELECTION: using linear bias function */
-       geqo_selection(momma, daddy, pool, Geqo_selection_bias);
+       geqo_selection(root, 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);
+       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(edge_table, kid->string, pool->string_length);
+       edge_failures += gimme_tour(root, edge_table, kid->string, pool->string_length);
 #elif defined(PMX)
        /* PARTIALLY MATCHED CROSSOVER */
-       pmx(momma->string, daddy->string, kid->string, pool->string_length);
+       pmx(root, 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);
+       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(kid->string, pool->string_length);
+           geqo_mutation(root, kid->string, pool->string_length);
        }
 #elif defined(PX)
        /* POSITION CROSSOVER */
-       px(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+       px(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
 #elif defined(OX1)
        /* ORDER CROSSOVER */
-       ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+       ox1(root, 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);
+       ox2(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
 #endif
 
 
        /* EVALUATE FITNESS */
-       kid->worth = geqo_eval(kid->string, pool->string_length, &evaldata);
+       kid->worth = geqo_eval(root, kid->string, pool->string_length);
 
        /* push the kid into the wilderness of life according to its worth */
-       spread_chromo(kid, pool);
+       spread_chromo(root, kid, pool);
 
 
 #ifdef GEQO_DEBUG
@@ -249,7 +255,7 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
     */
    best_tour = (Gene *) pool->data[0].string;
 
-   best_rel = gimme_tree(best_tour, pool->string_length, &evaldata);
+   best_rel = gimme_tree(root, best_tour, pool->string_length);
 
    if (best_rel == NULL)
        elog(ERROR, "failed to make a valid plan");
@@ -260,28 +266,31 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 #endif
 
    /* ... free memory stuff */
-   free_chromo(momma);
-   free_chromo(daddy);
+   free_chromo(root, momma);
+   free_chromo(root, daddy);
 
 #if defined (ERX)
-   free_edge_table(edge_table);
+   free_edge_table(root, edge_table);
 #elif defined(PMX)
-   free_chromo(kid);
+   free_chromo(root, kid);
 #elif defined(CX)
-   free_chromo(kid);
-   free_city_table(city_table);
+   free_chromo(root, kid);
+   free_city_table(root, city_table);
 #elif defined(PX)
-   free_chromo(kid);
-   free_city_table(city_table);
+   free_chromo(root, kid);
+   free_city_table(root, city_table);
 #elif defined(OX1)
-   free_chromo(kid);
-   free_city_table(city_table);
+   free_chromo(root, kid);
+   free_city_table(root, city_table);
 #elif defined(OX2)
-   free_chromo(kid);
-   free_city_table(city_table);
+   free_chromo(root, kid);
+   free_city_table(root, city_table);
 #endif
 
-   free_pool(pool);
+   free_pool(root, pool);
+
+   /* ... clear root pointer to our private storage */
+   root->join_search_private = NULL;
 
    return best_rel;
 }
index 946eb117e3dd3c6653ff4bbae82be822e1a334ed..bd527324f5ac1cd0f688c95b4f220f8d5fc8c5f1 100644 (file)
@@ -4,7 +4,7 @@
 *
 *   TSP mutation routines
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_mutation.c,v 1.9 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_mutation.c,v 1.10 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
 #include "optimizer/geqo_random.h"
 
 void
-geqo_mutation(Gene *tour, int num_gene)
+geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene)
 {
    int         swap1;
    int         swap2;
-   int         num_swaps = geqo_randint(num_gene / 3, 0);
+   int         num_swaps = geqo_randint(root, num_gene / 3, 0);
    Gene        temp;
 
 
    while (num_swaps > 0)
    {
-       swap1 = geqo_randint(num_gene - 1, 0);
-       swap2 = geqo_randint(num_gene - 1, 0);
+       swap1 = geqo_randint(root, num_gene - 1, 0);
+       swap2 = geqo_randint(root, num_gene - 1, 0);
 
        while (swap1 == swap2)
-           swap2 = geqo_randint(num_gene - 1, 0);
+           swap2 = geqo_randint(root, num_gene - 1, 0);
 
        temp = tour[swap1];
        tour[swap1] = tour[swap2];
index 268194e295cbfd888a1ef7f759c45beb943aa8a8..d11d3cd9c396b966094dff7dbc74b7d6705d7c7f 100644 (file)
@@ -6,7 +6,7 @@
 *   OX1 operator according to Davis
 *   (Proc Int'l Joint Conf on AI)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox1.c,v 1.9 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox1.c,v 1.10 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,8 @@
  *  position crossover
  */
 void
-ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+ox1(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
+   City *city_table)
 {
    int         left,
                right,
@@ -56,8 +57,8 @@ ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
        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);
+   left = geqo_randint(root, num_gene - 1, 0);
+   right = geqo_randint(root, num_gene - 1, 0);
 
    if (left > right)
    {
index 0c31cccae52ba01b07b4c75ac85b9cdbb3edba21..48ed359a630a62f3eb881856fb3e84b28debd92f 100644 (file)
@@ -6,7 +6,7 @@
 *   OX2 operator according to Syswerda
 *   (The Genetic Algorithms Handbook, ed L Davis)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox2.c,v 1.10 2004/10/07 15:21:52 momjian Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox2.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,7 @@
  *  position crossover
  */
 void
-ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+ox2(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
 {
    int         k,
                j,
@@ -60,12 +60,12 @@ ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
    }
 
    /* determine the number of positions to be inherited from tour1  */
-   num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);
+   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(num_gene - 1, 0);
+       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 */
    }
index dc52b731523e4a8054e4e8bcf5374889829ac9b1..a1f3d1019ec87f1e5e576e63012170b8efc56869 100644 (file)
@@ -6,7 +6,7 @@
 *   PMX operator according to Goldberg & Lingle
 *   (Proc Int'l Conf on GA's)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pmx.c,v 1.10 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pmx.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,7 @@
  *  partially matched crossover
  */
 void
-pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene)
+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));
@@ -71,8 +71,8 @@ pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene)
    }
 
 /* locate crossover points */
-   left = geqo_randint(num_gene - 1, 0);
-   right = geqo_randint(num_gene - 1, 0);
+   left = geqo_randint(root, num_gene - 1, 0);
+   right = geqo_randint(root, num_gene - 1, 0);
 
    if (left > right)
    {
index 7562d2ee0b31aa5fdfcd3440d8ee5eae8e620ff9..26137272f70888556a6ce2643750e74651328f57 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.33 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.34 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,7 @@ static int    compare(const void *arg1, const void *arg2);
  *     allocates memory for GA pool
  */
 Pool *
-alloc_pool(int pool_size, int string_length)
+alloc_pool(PlannerInfo *root, int pool_size, int string_length)
 {
    Pool       *new_pool;
    Chromosome *chromo;
@@ -66,7 +66,7 @@ alloc_pool(int pool_size, int string_length)
  *     deallocates memory for GA pool
  */
 void
-free_pool(Pool *pool)
+free_pool(PlannerInfo *root, Pool *pool)
 {
    Chromosome *chromo;
    int         i;
@@ -88,7 +88,7 @@ free_pool(Pool *pool)
  *     initialize genetic pool
  */
 void
-random_init_pool(Pool *pool, GeqoEvalData *evaldata)
+random_init_pool(PlannerInfo *root, Pool *pool)
 {
    Chromosome *chromo = (Chromosome *) pool->data;
    int         i;
@@ -105,10 +105,9 @@ random_init_pool(Pool *pool, GeqoEvalData *evaldata)
    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);
+       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
@@ -133,7 +132,7 @@ random_init_pool(Pool *pool, GeqoEvalData *evaldata)
  *  maybe you have to change compare() for different ordering ...
  */
 void
-sort_pool(Pool *pool)
+sort_pool(PlannerInfo *root, Pool *pool)
 {
    qsort(pool->data, pool->size, sizeof(Chromosome), compare);
 }
@@ -160,7 +159,7 @@ compare(const void *arg1, const void *arg2)
  *   allocates a chromosome and string space
  */
 Chromosome *
-alloc_chromo(int string_length)
+alloc_chromo(PlannerInfo *root, int string_length)
 {
    Chromosome *chromo;
 
@@ -174,7 +173,7 @@ alloc_chromo(int string_length)
  *   deallocates a chromosome and string space
  */
 void
-free_chromo(Chromosome *chromo)
+free_chromo(PlannerInfo *root, Chromosome *chromo)
 {
    pfree(chromo->string);
    pfree(chromo);
@@ -185,7 +184,7 @@ free_chromo(Chromosome *chromo)
  *  assumes best->worst = smallest->largest
  */
 void
-spread_chromo(Chromosome *chromo, Pool *pool)
+spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool)
 {
    int         top,
                mid,
@@ -247,7 +246,7 @@ spread_chromo(Chromosome *chromo, Pool *pool)
     * copy new gene into pool storage; always replace worst gene in pool
     */
 
-   geqo_copy(&pool->data[pool->size - 1], chromo, pool->string_length);
+   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;
index 8b6732b72247604a8fd1279c9aaa566ceab673ba..674529313a2be378536fed4aa28ed4bfc6c37b20 100644 (file)
@@ -6,7 +6,7 @@
 *   PX operator according to Syswerda
 *   (The Genetic Algorithms Handbook, L Davis, ed)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_px.c,v 1.10 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_px.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,8 @@
  *  position crossover
  */
 void
-px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
+   City *city_table)
 {
 
    int         num_positions;
@@ -57,12 +58,12 @@ px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
        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);
+   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(num_gene - 1, 0);
+       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
new file mode 100644 (file)
index 0000000..025407e
--- /dev/null
@@ -0,0 +1,40 @@
+/*------------------------------------------------------------------------
+ *
+ * geqo_random.c
+ *    random number generator
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_random.c,v 1.1 2009/07/16 20:55:44 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "optimizer/geqo_random.h"
+
+
+void
+geqo_set_seed(PlannerInfo *root, double seed)
+{
+   GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+
+   /*
+    * XXX. This seeding algorithm could certainly be improved - but
+    * it is not critical to do so.
+    */
+   memset(private->random_state, 0, sizeof(private->random_state));
+   memcpy(private->random_state,
+          &seed,
+          Min(sizeof(private->random_state), sizeof(seed)));
+}
+
+double
+geqo_rand(PlannerInfo *root)
+{
+   GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+
+   return erand48(private->random_state);
+}
index c73e5b2a79e4c3b806e56b462b284e510066ff9e..ebdd220383940e5fff8653cfb2af5250a8556397 100644 (file)
@@ -3,7 +3,7 @@
 * geqo_recombination.c
 *   misc recombination procedures
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.15 2005/10/15 02:49:19 momjian Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.16 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -35,7 +35,7 @@
  *  and the procedure repeated.
  */
 void
-init_tour(Gene *tour, int num_gene)
+init_tour(PlannerInfo *root, Gene *tour, int num_gene)
 {
    Gene       *tmp;
    int         remainder;
@@ -53,7 +53,7 @@ init_tour(Gene *tour, int num_gene)
    for (i = 0; i < num_gene; i++)
    {
        /* choose value between 0 and remainder inclusive */
-       next = (int) geqo_randint(remainder, 0);
+       next = geqo_randint(root, remainder, 0);
        /* output that element of the tmp array */
        tour[i] = tmp[next];
        /* and delete it */
@@ -81,7 +81,7 @@ init_tour(Gene *tour, int num_gene)
  *  allocate memory for city table
  */
 City *
-alloc_city_table(int num_gene)
+alloc_city_table(PlannerInfo *root, int num_gene)
 {
    City       *city_table;
 
@@ -99,7 +99,7 @@ alloc_city_table(int num_gene)
  *   deallocate memory of city table
  */
 void
-free_city_table(City *city_table)
+free_city_table(PlannerInfo *root, City *city_table)
 {
    pfree(city_table);
 }
index 3febca3c36fb62c847a96cee5052ca606b411d0d..0ba8941c22e05818bc5c36dc28f18299cf0f2aa3 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_selection.c,v 1.24 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_selection.c,v 1.25 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,7 @@
 #include "optimizer/geqo_random.h"
 #include "optimizer/geqo_selection.h"
 
-static int linear(int max, double bias);
+static int linear(PlannerInfo *root, int max, double bias);
 
 
 /*
@@ -51,22 +51,23 @@ static int  linear(int max, double bias);
  *  first and second genes are selected from the pool
  */
 void
-geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias)
+geqo_selection(PlannerInfo *root, Chromosome *momma, Chromosome *daddy,
+              Pool *pool, double bias)
 {
    int         first,
                second;
 
-   first = linear(pool->size, bias);
-   second = linear(pool->size, bias);
+   first = linear(root, pool->size, bias);
+   second = linear(root, pool->size, bias);
 
    if (pool->size > 1)
    {
        while (first == second)
-           second = linear(pool->size, bias);
+           second = linear(root, pool->size, bias);
    }
 
-   geqo_copy(momma, &pool->data[first], pool->string_length);
-   geqo_copy(daddy, &pool->data[second], pool->string_length);
+   geqo_copy(root, momma, &pool->data[first], pool->string_length);
+   geqo_copy(root, daddy, &pool->data[second], pool->string_length);
 }
 
 /*
@@ -74,12 +75,13 @@ geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias)
  *   generates random integer between 0 and input max number
  *   using input linear bias
  *
+ *   bias is y-intercept of linear distribution
+ *
  *   probability distribution function is: f(x) = bias - 2(bias - 1)x
  *          bias = (prob of first rule) / (prob of middle rule)
  */
 static int
-linear(int pool_size, double bias)     /* bias is y-intercept of linear
-                                        * distribution */
+linear(PlannerInfo *root, int pool_size, double bias)
 {
    double      index;          /* index between 0 and pop_size */
    double      max = (double) pool_size;
@@ -95,7 +97,7 @@ linear(int pool_size, double bias)        /* bias is y-intercept of linear
    {
        double      sqrtval;
 
-       sqrtval = (bias * bias) - 4.0 * (bias - 1.0) * geqo_rand();
+       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);
index 2944249a6924e349f43b2a2b2438bddafc0e9155..f3b42da99b15de7284ec901f1835ad437d64aba2 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <[email protected]>.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.507 2009/07/16 06:33:44 petere Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.508 2009/07/16 20:55:44 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2026,6 +2026,14 @@ static struct config_real ConfigureNamesReal[] =
        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."),
+           NULL
+       },
+       &Geqo_seed,
+       0.0, 0.0, 1.0, NULL, NULL
+   },
 
    {
        {"bgwriter_lru_multiplier", PGC_SIGHUP, RESOURCES,
index c1b888c0d4663088fbd3f40f6949316a5583c13f..e50d7a44f7b839d101ed1384fb1f0ce4972de7d5 100644 (file)
 #geqo_pool_size = 0            # selects default based on effort
 #geqo_generations = 0          # selects default based on effort
 #geqo_selection_bias = 2.0     # range 1.5-2.0
+#geqo_seed = 0.0           # range 0.0-1.0
 
 # - Other Planner Options -
 
index 7eb15dbeecd74b88e94f30c19c649795ca6b610e..4432252a72f3abf47bb3c270e8f259fa830f162a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.173 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.174 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -192,6 +192,9 @@ typedef struct PlannerInfo
    /* These fields are used only when hasRecursion is true: */
    int         wt_param_id;    /* PARAM_EXEC ID for the work table */
    struct Plan *non_recursive_plan;    /* plan for non-recursive term */
+
+   /* optional private data for join_search_hook, e.g., GEQO */
+   void       *join_search_private;
 } PlannerInfo;
 
 
index fc06006fd3b4ec5afffec345d38943ba573ea9c1..39226a7c7c98690037016d6c9d3c800c9a90cfa6 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo.h,v 1.44 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo.h,v 1.45 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,7 +46,7 @@
 /*
  * Configuration options
  *
- * If you change these, update backend/utils/misc/postgresql.sample.conf
+ * If you change these, update backend/utils/misc/postgresql.conf.sample
  */
 extern int Geqo_effort;        /* 1 .. 10, knob for adjustment of defaults */
 
@@ -64,16 +64,17 @@ extern double Geqo_selection_bias;
 #define MIN_GEQO_SELECTION_BIAS 1.5
 #define MAX_GEQO_SELECTION_BIAS 2.0
 
+extern double Geqo_seed;       /* 0 .. 1 */
+
 
 /*
- * Data structure to encapsulate information needed for building plan trees
- * (i.e., geqo_eval and gimme_tree).
+ * Private state for a GEQO run --- accessible via root->join_search_private
  */
 typedef struct
 {
-   PlannerInfo *root;          /* the query we are planning */
-   List       *initial_rels;   /* the base relations */
-} GeqoEvalData;
+   List       *initial_rels;           /* the base relations we are joining */
+   unsigned short random_state[3];     /* state for erand48() */
+} GeqoPrivateData;
 
 
 /* routines in geqo_main.c */
@@ -81,8 +82,7 @@ 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);
+extern Cost geqo_eval(PlannerInfo *root, Gene *tour, int num_gene);
+extern RelOptInfo *gimme_tree(PlannerInfo *root, Gene *tour, int num_gene);
 
 #endif   /* GEQO_H */
index 53293c4916114ee4fc2a77923c01b6c5b0fd47a5..582de22e6c3395487b3ef9296b7480fc1418935d 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_copy.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_copy.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,9 @@
 #ifndef GEQO_COPY_H
 #define GEQO_COPY_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void geqo_copy(Chromosome *chromo1, Chromosome *chromo2, int string_length);
+
+extern void geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2, int string_length);
 
 #endif   /* GEQO_COPY_H */
index 430797c3707cef28c5787afe134dddea1e42afe5..559c35218db8f4608b97d1a0af666eebfd34b4be 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_mutation.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_mutation.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,9 @@
 #ifndef GEQO_MUTATION_H
 #define GEQO_MUTATION_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void geqo_mutation(Gene *tour, int num_gene);
+
+extern void geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene);
 
 #endif   /* GEQO_MUTATION_H */
index 282b2c2c5b73c27992d67a414f64ff2ec45be302..277b144ebd06a1e1da070e28835f1450487713d1 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_pool.h,v 1.25 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_pool.h,v 1.26 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "optimizer/geqo.h"
 
 
-extern Pool *alloc_pool(int pool_size, int string_length);
-extern void free_pool(Pool *pool);
+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(Pool *pool, GeqoEvalData *evaldata);
-extern Chromosome *alloc_chromo(int string_length);
-extern void free_chromo(Chromosome *chromo);
+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(Chromosome *chromo, Pool *pool);
+extern void spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool);
 
-extern void sort_pool(Pool *pool);
+extern void sort_pool(PlannerInfo *root, Pool *pool);
 
 #endif   /* GEQO_POOL_H */
index 327989b5fb8bdba91e22bfd264255833ba4abdf5..cb1f60fa34e9b9706d00d58aac4db850c9169334 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_random.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_random.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include <math.h>
 
-/* geqo_rand returns a random float value between 0 and 1 inclusive */
+#include "optimizer/geqo.h"
 
-#define geqo_rand() ((double) random() / (double) MAX_RANDOM_VALUE)
 
-/* geqo_randint returns integer value between lower and upper inclusive */
+extern void geqo_set_seed(PlannerInfo *root, double seed);
 
-#define geqo_randint(upper,lower) \
-   ( (int) floor( geqo_rand()*(((upper)-(lower))+0.999999) ) + (lower) )
+/* geqo_rand returns a random float value between 0 and 1 inclusive */
+extern double geqo_rand(PlannerInfo *root);
+
+/* 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 */
index 264560f1128f5f1d08f1fd9dfaf039e7f9c0f7df..456783865065d9440577afa458ccfc64c13d37e7 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_recombination.h,v 1.20 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_recombination.h,v 1.21 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEQO_RECOMBINATION_H
 #define GEQO_RECOMBINATION_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void init_tour(Gene *tour, int num_gene);
+
+extern void init_tour(PlannerInfo *root, Gene *tour, int num_gene);
 
 
 /* edge recombination crossover [ERX] */
@@ -38,12 +39,14 @@ typedef struct Edge
    int         unused_edges;
 } Edge;
 
-extern Edge *alloc_edge_table(int num_gene);
-extern void free_edge_table(Edge *edge_table);
+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(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table);
+extern float gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2,
+                             int num_gene, Edge *edge_table);
 
-extern int gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene);
+extern int gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene,
+                      int num_gene);
 
 
 /* partially matched crossover [PMX] */
@@ -51,7 +54,9 @@ extern int    gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene);
 #define DAD 1                  /* indicator for gene from dad */
 #define MOM 0                  /* indicator for gene from mom */
 
-extern void pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene);
+extern void pmx(PlannerInfo *root,
+               Gene *tour1, Gene *tour2,
+               Gene *offspring, int num_gene);
 
 
 typedef struct City
@@ -62,19 +67,23 @@ typedef struct City
    int         select_list;
 } City;
 
-extern City *alloc_city_table(int num_gene);
-extern void free_city_table(City *city_table);
+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(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table);
+extern int cx(PlannerInfo *root, 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);
+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(Gene *mom, Gene *dad, Gene *offspring, int num_gene, City *city_table);
+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(Gene *mom, Gene *dad, Gene *offspring, int num_gene, City *city_table);
+extern void ox2(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring,
+               int num_gene, City *city_table);
 
 #endif   /* GEQO_RECOMBINATION_H */
index e37a92b554efba81b586a94888b3f220957204c1..166ba475350cc1c706c6b7c7d61cb0af0c6b0bc7 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_selection.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_selection.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GEQO_SELECTION_H
 #define GEQO_SELECTION_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias);
+
+extern void geqo_selection(PlannerInfo *root,
+                          Chromosome *momma, Chromosome *daddy,
+                          Pool *pool, double bias);
 
 #endif   /* GEQO_SELECTION_H */