1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
/* ----------------------------------------------------------------------------
ex15.C
mbwall 28jul94
Copyright (c) 1995-1996 Massachusetts Institute of Technology
DESCRIPTION:
This example nearly identical to example 2, but it uses convergence as the
stopping criterion for the GA rather than number-of-generations.
---------------------------------------------------------------------------- */
#include <stdio.h>
#include <math.h>
#include <ga/ga.h>
#include <ga/std_stream.h>
#define cout STD_COUT
float objective(GAGenome &);
int
main(int argc, char **argv)
{
cout << "Example 15\n\n";
cout << "This program generates a sequence of random numbers then uses\n";
cout << "a simple GA and binary-to-decimal genome to match the\n";
cout << "sequence. It uses the convergence of the best-of-generation\n";
cout << "as the criterion for when to stop.\n\n";
// 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.
unsigned int seed = 0;
for(int ii=1; ii<argc; ii++) {
if(strcmp(argv[ii++],"seed") == 0) {
seed = atoi(argv[ii]);
}
}
// Declare variables for the GA parameters and set them to some default values.
// When we use convergence as the completion measure we have to specify both
// a convergence value (larger means more converged) and a number-of-gen
// which specifies how many generations back to look to calculate the
// convergence. The number of generations back defaults to 20, so you do not
// have to set that if you don't want to.
int popsize = 30;
float pmut = 0.01;
float pcross = 0.6;
float pconv = 0.99; // threshhold for when we have converged
int nconv = 50; // how many generations back to look
// Generate a sequence of random numbers using the values in the min and max
// arrays. We also set one of them to integer value to show how you can get
// explicit integer representations by choosing your number of bits
// appropriately.
GARandomSeed(seed);
int i;
int n=7;
float *target = new float[n];
float min[] = {0, 0, 3, -5, 100, 0.001, 0};
float max[] = {1, 100, 3, -2, 100000, 0.010, 7};
for(i=0; i<n; i++)
target[i] = GARandomFloat(min[i], max[i]);
target[6] = GARandomInt((int)min[6], (int)max[6]);
// Print out the sequence to be sure we got the right one.
cout << "input sequence:\n";
for(i=0; i<n; i++){
cout.width(10);
cout << target[i] << " ";
}
cout << "\n"; cout.flush();
// Create a phenotype then fill it with the phenotypes we will need to map to
// the values we read from the file. The arguments to the add() method of a
// Bin2Dec phenotype are (1) number of bits, (2) min value, and (3) max value.
// The phenotype maps a floating-point number onto the number of bits that
// you designate. Here we just make everything use 8 bits and use the max and
// min that were used to generate the target values. You can experiment with
// the number of bits and max/min values in order to make the GA work better
// or worse.
GABin2DecPhenotype map;
for(i=0; i<n; i++)
map.add(8, min[i], max[i]);
// Create the template genome using the phenotype map we just made. The
// GA will use this genome to clone the population that it uses to do the
// evolution.
GABin2DecGenome genome(map, objective, (void *)target);
// Now create the GA using the genome and run it.
GASteadyStateGA ga(genome);
ga.scoreFrequency(1);
ga.flushFrequency(50);
ga.scoreFilename("bog.dat");
ga.populationSize(popsize);
ga.pMutation(pmut);
ga.pCrossover(pcross);
ga.pConvergence(pconv);
ga.nConvergence(nconv);
ga.terminator(GAGeneticAlgorithm::TerminateUponConvergence);
ga.evolve();
// Dump the results of the GA to the screen.
genome.initialize();
cout << "random values in the genome:\n";;
unsigned int jj=0;
for(jj=0; jj<map.nPhenotypes(); jj++){
cout.width(10); cout << genome.phenotype(jj) << " ";
}
cout << "\n";
genome = ga.statistics().bestIndividual();
cout << "the ga generated:\n";
for(jj=0; jj<map.nPhenotypes(); jj++){
cout.width(10); cout << genome.phenotype(jj) << " ";
}
cout << "\n\n"; cout.flush();
// Clean up by freeing the memory we allocated.
delete [] target;
return 0;
}
// For this objective function we try to match the values in the array of float
// that is passed to us as userData. If the values in the genome map to
// values that are close, we return a better score. We are limited to positive
// values for the objective value (because we're using linear scaling), so we
// take the reciprocal of the absolute value of the difference between the
// value from the phenotype and the value in the sequence.
float
objective(GAGenome & c)
{
GABin2DecGenome & genome = (GABin2DecGenome &)c;
float *sequence = (float *)c.userData();
float value=genome.nPhenotypes();
for(int i=0; i<genome.nPhenotypes(); i++)
value += 1.0 / (1.0 + fabs(genome.phenotype(i) - sequence[i]));
return(value);
}
|