/*------------------------------------------------------------------------------ Project: calculate optimum solutions for the hash definition problem Module: HashDef.c (main program) Purpose: Complete program Date: 1st November 2001 Author: D Cornforth ------------------------------------------------------------------------------*/ /* The author retains all rights to this program. You may copy and edit this program for any non-commercial purpose without permission from the author, as long as you acknowledge the source. Suggested acknowledgement: Cornforth, D. 2002 Evolution in the orange box - A new approach to the sphere- packing problem in CMAC-based neural networks. Proceedings of the 15th Australian Joint Conference on Artificial Intelligence. */ #pragma hdrstop #include #include #include #include #include #include #pragma argsused #define MAX_DIMS 50 #define MAX_LINE 100 enum Boolean {False, True}; // data with module scope int Alleles = 0; int *Coprime = NULL; Boolean Best = False; double *BestFitness = NULL; int **BestVector = NULL; int Dims = 0; int EliteCount; double *Fitness = NULL; int Generations; int **Genotype = NULL; int MutationRange = 200; // prob 1% of being -1, 1% of being +1 int Population = 0; Boolean Prime = True; // use coprime array int Runs = 0; Boolean Verbose = False; // functions with module scope void BestResult (int layers); Boolean checkfile (ifstream* inp); void CreateCoprimes (int layers); void Crossover (int* parent1, int* parent2, int newpop); void Evaluate (char* QuantFile); double GetFitness (int layers, int* vector); void InitialisePop (void); void main (int argc, char *argv[]); void MedianResult (int layers); void Mutation (int layers, int start, int stop); Boolean Reproduce (int layers); int Roulette (double *cumulative); void ShowBest (int layers, int run); void SortIndex (double* item, int* index, int length); /*------------------------------------------------------------------------------ Function: main Purpose: Arguments: none Returns: none ------------------------------------------------------------------------------*/ void main (int argc, char *argv[]) { int gen, pop, layers, min_layers, max_layers, run; time_t t; srand((unsigned) time(&t)); if (argc < 2) { cerr << "Basic operation:\n"; cerr << " hashdef dims pop generations runs -> will produce table for 2 - 50 layers\n"; cerr << " hashdef dims pop generations runs layers -> will do one layer\n"; cerr << " hashdef filename -> will evaluate the grid spacings found in the file\n"; cerr << "Additional flags (must come last):\n"; cerr << " -c -> don't restrict to coprimes.\n"; cerr << " -d or -v -> turn on debug (verbose) mode.\n"; cerr << " -b -> show best result from multiple runs (default: median result).\n"; exit (0); } if (argc < 5) // assume evaluation mode { if (argc == 3) { if ((strcmp (argv[2], "-d") == 0) || (strcmp (argv[2], "-v") == 0)) { Verbose = True; // show debug info cerr << "Verbose mode\n"; } } Prime = False; Evaluate (argv[1]); exit (0); } Dims = atoi (argv[1]); if ((Dims < 2) || (Dims > MAX_DIMS)) { cerr << "Invalid number of dims.\n"; exit (0); } Population = atoi (argv[2]); if (Population < 2) { cerr << "Invalid population size.\n"; exit (0); } Generations = atoi (argv[3]); if (Generations < 2) { cerr << "Invalid number of generations.\n"; exit (0); } Runs = atoi (argv[4]); if (Runs < 1) { cerr << "Invalid number of runs.\n"; exit (0); } min_layers = 2; max_layers = 50; int next_arg = 5; if (argc > 5) { if (*argv[next_arg] != '-') // if this is not a switch { min_layers = atoi (argv[next_arg]); next_arg++; if (min_layers > 1) { max_layers = min_layers; } else { cerr << "Invalid number of layers.\n"; exit (0); } } } Prime = True; // default - use coprimes Verbose = False; Best = False; while (argc > next_arg) // all remaining args are switches { if (strcmp (argv[next_arg], "-b") == 0) { Best = True; // report best result, not median } else if (strcmp (argv[next_arg], "-c") == 0) { Prime = False; // don't restrict to coprimes } else if (strcmp (argv[next_arg], "-d") == 0) { Verbose = True; // show debug info } else if (strcmp (argv[next_arg], "-v") == 0) { Verbose = True; // show debug info } next_arg++; } EliteCount = Population / 10; // number of individuals passed to next generation if (EliteCount < 2) { EliteCount = 2; } if ((Population - EliteCount) % 2) // if remainder is odd { EliteCount++; } Fitness = new double[Population]; Genotype = new int*[Population]; for (pop=0; pop most_fit) { most_fit = BestFitness[run]; best_ndx = run; } } cout << layers; for (dim=0; dimrdbuf (); if (!fb->is_open ()) { success = False; } return (success); } /*------------------------------------------------------------------------------ Function: CreateCoprimes Purpose: create array containing suitable candidates for displacement vector these are coprimes of the number of layers, less than half no of layers Arguments: none Returns: none ------------------------------------------------------------------------------*/ void CreateCoprimes (int layers) { int layer, ndx = 0; Boolean *noprime; Alleles = layers / 2 + 1; noprime = new Boolean[Alleles]; // make a list of all numbers which are not coprimes for (layer=0; layer vector[1][ndx]) // if not in ascending order { temp = vector[1][ndx]; vector[1][ndx] = vector[1][dim]; vector[1][dim] = temp; } } } // set first grid position is at all zeros for (dim=0; dim min_dist) // if dist in a single dimension is greater, Euclid cannot be less { dist = layers - dist; // shift one of the points into an adjacent cube if (dist > min_dist) { found = False; break; // give up, distance between these 2 points cannot be less than min_dist } } sum += (dist * dist); // use squared distance to get Euclidean } if (found) { sum = sqrt (sum); if (sum < min_dist) { min_dist = sum; if (Verbose) { cout << "vectors"; for (dim=0; dim 1) { disturbance = 0; // mostly zero, sometimes can be 1 or -1 } // add disturbance with wrap-around Genotype[pop][dim] = (Genotype[pop][dim] + disturbance) % Alleles; if (Genotype[pop][dim] < 0) { Genotype[pop][dim] += Alleles; // do wrap around } } } } /*------------------------------------------------------------------------------ Function: Reproduce Purpose: controls selection, new generation Arguments: none Returns: none ------------------------------------------------------------------------------*/ Boolean Reproduce (int layers) { int pop, ndx1, ndx2, dim, elitendx; int* fitorder = new int[Population]; double *cumulative = new double[Population]; Boolean Converge; int **oldpop = new int*[Population]; // make a copy of the whole population for (pop=0; pop= Population) || (ndx2 >= Population)) { if (Verbose) { cerr << "Roulette has chosen invalid individuals\n"; } break; } Crossover (oldpop[ndx1], oldpop[ndx2], pop); // produce children } // destroy pop from previous generation for (pop=0; pop fitness) { break; } } return (pop); } /*------------------------------------------------------------------------------ Function: ShowBest Purpose: show best individual for this run Arguments: none Returns: none ------------------------------------------------------------------------------*/ void ShowBest (int layers, int run) { int pop, max_ndx = -1, dim, ndx, temp, coprimendx; // find the fittest individual BestFitness[run] = -1.0e+30; for (pop=0; pop BestFitness[run]) { BestFitness[run] = Fitness[pop]; max_ndx = pop; } } BestVector[run][0] = 1; for (dim=1; dim BestVector[run][ndx]) // if not in ascending order { temp = BestVector[run][ndx]; BestVector[run][ndx] = BestVector[run][dim]; BestVector[run][dim] = temp; } } } if (Verbose) { // display the vector cout << layers; for (dim=0; dim