From 59464bd6f928ad0da30502cbe9b54baec9ca2c69 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 5 Nov 2015 10:46:14 -0500 Subject: [PATCH] Improve implementation of GEQO's init_tour() function. Rather than filling a temporary array and then copying values to the output array, we can generate the required random permutation in-place using the Fisher-Yates shuffle algorithm. This is shorter as well as more efficient than before. It's pretty unlikely that anyone would notice a speed improvement, but shorter code is better. Nathan Wagner, edited a bit by me --- .../optimizer/geqo/geqo_recombination.c | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c index 652fadc745..ef433e54e5 100644 --- a/src/backend/optimizer/geqo/geqo_recombination.c +++ b/src/backend/optimizer/geqo/geqo_recombination.c @@ -29,39 +29,33 @@ * * Randomly generates a legal "traveling salesman" tour * (i.e. where each point is visited only once.) - * Essentially, this routine fills an array with all possible - * points on the tour and randomly chooses the 'next' city from - * this array. When a city is chosen, the array is shortened - * and the procedure repeated. */ void init_tour(PlannerInfo *root, Gene *tour, int num_gene) { - Gene *tmp; - int remainder; - int next, - i; + int i, + j; - /* Fill a temp array with the IDs of all not-yet-visited cities */ - tmp = (Gene *) palloc(num_gene * sizeof(Gene)); + /* + * We must fill the tour[] array with a random permutation of the numbers + * 1 .. num_gene. We can do that in one pass using the "inside-out" + * variant of the Fisher-Yates shuffle algorithm. Notionally, we append + * each new value to the array and then swap it with a randomly-chosen + * array element (possibly including itself, else we fail to generate + * permutations with the last city last). The swap step can be optimized + * by combining it with the insertion. + */ + if (num_gene > 0) + tour[0] = (Gene) 1; - for (i = 0; i < num_gene; i++) - tmp[i] = (Gene) (i + 1); - - remainder = num_gene - 1; - - for (i = 0; i < num_gene; i++) + for (i = 1; i < num_gene; i++) { - /* choose value between 0 and remainder inclusive */ - next = geqo_randint(root, remainder, 0); - /* output that element of the tmp array */ - tour[i] = tmp[next]; - /* and delete it */ - tmp[next] = tmp[remainder]; - remainder--; + j = geqo_randint(root, i, 0); + /* i != j check avoids fetching uninitialized array element */ + if (i != j) + tour[i] = tour[j]; + tour[j] = (Gene) (i + 1); } - - pfree(tmp); } /* alloc_city_table