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
This commit is contained in:
Tom Lane 2015-11-05 10:46:14 -05:00
parent 7bd099d511
commit 59464bd6f9
1 changed files with 19 additions and 25 deletions

View File

@ -29,39 +29,33 @@
* *
* Randomly generates a legal "traveling salesman" tour * Randomly generates a legal "traveling salesman" tour
* (i.e. where each point is visited only once.) * (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 void
init_tour(PlannerInfo *root, Gene *tour, int num_gene) init_tour(PlannerInfo *root, Gene *tour, int num_gene)
{ {
Gene *tmp; int i,
int remainder; j;
int next,
i;
/* 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++) for (i = 1; i < num_gene; i++)
tmp[i] = (Gene) (i + 1);
remainder = num_gene - 1;
for (i = 0; i < num_gene; i++)
{ {
/* choose value between 0 and remainder inclusive */ j = geqo_randint(root, i, 0);
next = geqo_randint(root, remainder, 0); /* i != j check avoids fetching uninitialized array element */
/* output that element of the tmp array */ if (i != j)
tour[i] = tmp[next]; tour[i] = tour[j];
/* and delete it */ tour[j] = (Gene) (i + 1);
tmp[next] = tmp[remainder];
remainder--;
} }
pfree(tmp);
} }
/* alloc_city_table /* alloc_city_table