#include #include #include "ga_random.h" #include "gene.h" #include "op_edge_recomb.h" #define ABS(x) (x<0 ? 0-x : x) /****************************************************** NumberFailures is global, but local to this file. Use get and set functions to access its value elsewhere. ******************************************************/ int NumberFailures=0; int get_number_failures() { return (NumberFailures); }; void set_number_failures(val) int val; { NumberFailures = val; }; /*************************************************************************** * FUNCTION: get_edge_table * * DESCRIBE: Allocates space for an array of edge nodes. * * INPUT PARAMETERS: number of points * * RETURN VALUE: pointer to an array of EDGE_NODEs (i.e., an edge table) ****************************************************************************/ EDGE_NODE * get_edge_table(num_points) int num_points; { EDGE_NODE *edge_table; /************************************************* malloc one extra location so that nodes numbered 1 - N can be indexed directly; 0 will not be used *************************************************/ if (!(edge_table = (EDGE_NODE *) malloc ((num_points+1)*sizeof(EDGE_NODE)))) fatal_error ("get_edge_table: Malloc failure.\n"); return (edge_table); } /*************************************************************************** * FUNCTION: free_edge_table * * DESCRIBE: deallocates space for integer distance * * NOTE: use this function only when the EDGE_NODE * array was Allocated using get_edge_table * * INPUT PARAMETERS: arrary of edge nodes to free * * RETURN VALUE: none ****************************************************************************/ void free_edge_table(edge_table) EDGE_NODE edge_table[]; { free (edge_table); } /*************************************************************************** * FUNCTION: maketour * * DESCRIBE: 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. * * INPUT PARAMETERS: an empty tour, number of points per tour * * RETURN VALUE: none * * RESULT: fills input tour ****************************************************************************/ void maketour(gene, num_points) GENE_DATA gene[]; int num_points; { static int first_time = 1; static GENE_DATAPTR temp; int remainder; int next, i; if (first_time) { if (!(temp = (GENE_DATAPTR) malloc (num_points*sizeof(GENE_DATA)))) fatal_error ("maketour: malloc failure\n"); first_time = 0; } for(i = 0; i < num_points; i++) temp[i] = (GENE_DATA) i+1; remainder = num_points - 1; for(i = 0; i < num_points; i++) { next = randomain(remainder, 0); gene[i] = temp[next]; temp[next] = temp[remainder]; remainder--; } } /*************************************************************************** * FUNCTION: build_edge_table * * DESCRIBE: fills a data structure which represents the set of explicit * edges between points in the (2) input genes. * * NOTE: Assumes circular tours and bidirectional edges. * * NOTE: add_edge() will set "shared" edges to negative values * * INPUT PARAMETERS: 2 genes; * number of points/gene; * data structure representing set of edges of 2 genes * * RETURN VALUE: average number edges/city (in range 2.0 - 4.0 where * 2.0=homogeneous; 4.0=diverse) * * CALLS: add_edge ****************************************************************************/ float build_edge_table (gene1, gene2, num_points, edge_table) GENE_DATA gene1[], gene2[]; int num_points; EDGE_NODE edge_table[]; { int i; int city2; int edge_total; /* total number of unique edges in two genes */ /************************************* * clear out the edge table's old data *************************************/ for (i=1; i<=num_points; i++) { edge_table[i].total_edges = 0; edge_table[i].unused_edges = 0; } /******************************* * fill edge table with new data *******************************/ edge_total = 0; for (i=0; i2, 2->3, 3->1 * this operaton maps N back to 1 **********************************************/ city2 = (i+1) % num_points; /******************************************** * edges are bidirectional; i.e. 1->2; 2->1 * call add_edge twice per edge ********************************************/ edge_total += add_edge(gene1[i], gene1[city2], edge_table); add_edge(gene1[city2], gene1[i], edge_table); edge_total += add_edge(gene2[i], gene2[city2], edge_table); add_edge(gene2[city2], gene2[i], edge_table); } /*************************************** * return average number of edges / city ***************************************/ return (((float) (edge_total * 2)/ (float) num_points)); } /*************************************************************************** * FUNCTION: add_edge * * DESCRIBE: registers edge from point1 to point2 in input edge table. * NOTE: No assumptions about directionality are made. * In other words, it is up to the calling routine to * call add_edge twice to make a bi-directional edge * between point1 and point2. Thus, uni-directional * edges are possible as well (just call add_edge * once with the direction from point1 to point2) * * INPUT PARAMETERS: 2 points, * data structure representing set of edges of 2 genes * * RETURN VALUE: 1 if edge was not already registered and was just added; * 0 if edge was already registered and edge_table is unchanged ****************************************************************************/ int add_edge (point1, point2, edge_table) GENE_DATA point1, point2; EDGE_NODE edge_table[]; { int i; int edges_so_far; /******************************************* does the edge point1->point2 already exist? *******************************************/ edges_so_far = edge_table[point1].total_edges; for (i=0; ipoint2; increment the counter for number of edges from point1 *****************************************************/ edge_table[point1].edge_list[edges_so_far] = point2; edge_table[point1].total_edges++; edge_table[point1].unused_edges++; return (1); } /*************************************************************************** * FUNCTION: build_tour * * DESCRIBE: Creates a new tour using edges from the edge table. * NOTE: priority is given to "shared" edges (i.e. edges which * all parent genes possess and are marked as negative * in the edge table.) * * INPUT PARAMETERS: data structure representing set of edges of 2 genes * empty GENE_DATA array for new tour * number of points/gene; * * RETURN VALUE: 1 upon success; 0 upon failure ****************************************************************************/ int build_tour (edge_table, new_gene, num_points) EDGE_NODE edge_table[]; GENE_DATA new_gene[]; int num_points; { int i,j,k; new_gene[0] = randomain(num_points, 1); for (i=1; i 0) { new_gene[i] = select_point (edge_table[new_gene[i-1]], edge_table); } else { /******************* Failure: handle it! *******************/ new_gene[i] = handle_failure (new_gene, i-1, edge_table, num_points); } /************************** mark this node as consumed **************************/ edge_table[new_gene[i-1]].unused_edges = -1; } return (1); } /************************************************************************* * FUNCTION: select_point * * DESCRIBE: * NOTE: priority is given to "shared" edges (i.e. edges which * both genes possess * * INPUT PARAMETERS: edge_node, edge_table * * RETURN VALUE: point chosen from input edge_node's edge_list *************************************************************************/ int select_point (edge_node, edge_table) EDGE_NODE edge_node; EDGE_NODE edge_table[]; { int i; GENE_DATA candidate_pt; int min_edges; int min_count; int rand_pick; /*********************************************** No point has edges to more than 4 other points. Thus, this contrived minimum will be replaced. ***********************************************/ min_edges = 5; /*********************************************************** Begin considering candidate destination points in edge list ***********************************************************/ for (i=0; i= 0) return (i); warning ("handle_failure(3): Cannot find an edge.\n"); } /***************************** should never reach this point *****************************/ fatal_error ("handle_failure: unexplained failure.\n"); } /************************ Routines below this line Useful for DEBUG ************************/ #define ERR_OUT stderr print_edge_table (edge_table, num_points) EDGE_NODE edge_table[]; int num_points; { int i,j; fprintf (ERR_OUT, "\nEDGE TABLE\n"); for (i=1; i<=num_points; i++) { fprintf (ERR_OUT, "%d :", i); for (j=0; j