/* ---------------------------------------------------------------------------- ex10.C mbwall 10apr95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Sample program that illustrates how to use a distance function to do speciation. This example does both gene-based and phenotype-based distance calculations. The differences are quite interesting. Also, the length of the bit string (i.e. the size of the search space) is also a significant factor in the performance of the speciation methods. Notice that Goldberg describes fitness scaling speciation in the context of a simple genetic algorithm. You can try using it with a steady-state algorithm, but you'll get bogus results unless you modify the algorithm. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #define USE_RAW_SINE #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define NBITS 8 #ifdef USE_RAW_SINE #define FUNCTION Function1 #define MIN_VALUE 0 #define MAX_VALUE 5 #else #define FUNCTION Function2 #define MIN_VALUE -100 #define MAX_VALUE 100 #endif float Function1(float); float Function2(float); float Objective(GAGenome &); float BitDistance(const GAGenome & a, const GAGenome & b); float PhenotypeDistance(const GAGenome & a, const GAGenome & b); int main(int argc, char **argv) { cout << "Example 10\n\n"; cout << "This program uses sharing to do speciation. The objective\n"; cout << "function has more than one optimum, so different genomes\n"; cout << "may have equally high scores. Speciation keeps the population\n"; cout << "from clustering at one optimum.\n"; cout << " Both gene-wise and phenotype-wise distance functions are used.\n"; cout << " Populations from all three runs are written to the files \n"; cout << "pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The\n"; cout << "function is written to the file sinusoid.dat\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii 100) y = 0; if(y < 0) y = 0; return y+0.00001; } // Here are a couple of possible distance functions for this problem. One of // them uses the genes to determine the same-ness, the other uses the // phenotypes to determine same-ness. If the genomes are the same, then // we return a 0. If they are completely different then we return a 1. // In either case, you should be sure that the distance function will return // values only between 0 and 1 inclusive. If your function returns values // outside these limits, the GA will produce bogus results and it WILL NOT warn // you that your distance function is brain-dead! // This distance function uses the genes to determine same-ness. All we do // is check to see if the bit strings are identical. float BitDistance(const GAGenome & c1, const GAGenome & c2){ GABin2DecGenome & a = (GABin2DecGenome &)c1; GABin2DecGenome & b = (GABin2DecGenome &)c2; float x=0; for(int i=a.length()-1; i>=0; i--) x += (a[i] != b[i] ? 1 : 0); return x/a.length(); } // This distance function looks at the phenotypes rather than the genes of the // genome. This distance function will try to drive them to extremes. float PhenotypeDistance(const GAGenome & c1, const GAGenome & c2){ GABin2DecGenome & a = (GABin2DecGenome &)c1; GABin2DecGenome & b = (GABin2DecGenome &)c2; return fabs(a.phenotype(0) - b.phenotype(0)) / (MAX_VALUE-MIN_VALUE); }