/*------------------------------------------------------------------------ * * geqo_erx.c * edge recombination crossover [ER] * * src/backend/optimizer/geqo/geqo_erx.c * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= * Martin Utesch * Institute of Automatic Control * = = University of Mining and Technology = * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the edge recombination algorithm is adopted from Genitor : */ /*************************************************************/ /* */ /* Copyright (c) 1990 */ /* Darrell L. Whitley */ /* Computer Science Department */ /* Colorado State University */ /* */ /* Permission is hereby granted to copy all or any part of */ /* this program for free distribution. The author's name */ /* and this copyright notice must be included in any copy. */ /* */ /*************************************************************/ #include "postgres.h" #include "optimizer/geqo_random.h" #include "optimizer/geqo_recombination.h" #if defined(ERX) 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 * * allocate memory for edge table * */ Edge * alloc_edge_table(PlannerInfo *root, int num_gene) { Edge *edge_table; /* * palloc one extra location so that nodes numbered 1..n can be indexed * directly; 0 will not be used */ edge_table = (Edge *) palloc((num_gene + 1) * sizeof(Edge)); return edge_table; } /* free_edge_table * * deallocate memory of edge table * */ void free_edge_table(PlannerInfo *root, Edge *edge_table) { pfree(edge_table); } /* gimme_edge_table * * fills a data structure which represents the set of explicit * edges between points in the (2) input genes * * assumes circular tours and bidirectional edges * * gimme_edge() will set "shared" edges to negative values * * returns average number edges/city in range 2.0 - 4.0 * where 2.0=homogeneous; 4.0=diverse * */ float gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table) { int i, index1, index2; int edge_total; /* total number of unique edges in two genes */ /* at first clear the edge table's old data */ for (i = 1; i <= num_gene; i++) { edge_table[i].total_edges = 0; edge_table[i].unused_edges = 0; } /* fill edge table with new data */ edge_total = 0; for (index1 = 0; index1 < num_gene; index1++) { /* * presume the tour is circular, i.e. 1->2, 2->3, 3->1 this operation * maps n back to 1 */ index2 = (index1 + 1) % num_gene; /* * edges are bidirectional, i.e. 1->2 is same as 2->1 call gimme_edge * 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 */ return ((float) (edge_total * 2) / (float) num_gene); } /* gimme_edge * * registers edge from city1 to city2 in input edge table * * no assumptions about directionality are made; * therefore it is up to the calling routine to * call gimme_edge twice to make a bi-directional edge * between city1 and city2; * uni-directional edges are possible as well (just call gimme_edge * once with the direction from city1 to city2) * * returns 1 if edge was not already registered and was just added; * 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; int city1 = (int) gene1; int city2 = (int) gene2; /* check whether edge city1->city2 already exists */ edges = edge_table[city1].total_edges; for (i = 0; i < edges; i++) { if ((Gene) Abs(edge_table[city1].edge_list[i]) == city2) { /* mark shared edges as negative */ edge_table[city1].edge_list[i] = 0 - city2; return 0; } } /* add city1->city2; */ edge_table[city1].edge_list[edges] = city2; /* increment the number of edges from city1 */ edge_table[city1].total_edges++; edge_table[city1].unused_edges++; return 1; } /* gimme_tour * * creates a new tour using edges from the edge table. * priority is given to "shared" edges (i.e. edges which * all parent genes possess and are marked as negative * in the edge table.) * */ int gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene, int num_gene) { int i; int edge_failures = 0; /* choose int between 1 and num_gene */ new_gene[0] = (Gene) geqo_randint(root, num_gene, 1); for (i = 1; i < num_gene; i++) { /* * as each point is entered into the tour, remove it from the 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(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 node as incorporated */ edge_table[(int) new_gene[i - 1]].unused_edges = -1; } /* for (i=1; i= 0) return (Gene) i; elog(LOG, "no edge found via looking for the last unused point"); } /* ... should never be reached */ elog(ERROR, "no edge found"); return 0; /* to keep the compiler quiet */ } #endif /* defined(ERX) */