📄 ex7.c
字号:
/* ----------------------------------------------------------------------------
ex7.C
mbwall 19jan95
Copyright 1995-1996 Massachusetts Institute of Technology
DESCRIPTION:
This example functions the same way as example 3, but this example shows
how to use some of the other member functions in the GA library. We also do
a few more fancy things with the genome (ie use the read/write methods).
---------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <fstream.h>
#include <ga/ga.h>
float objective(GAGenome &);
int
main(int argc, char *argv[])
{
cout << "Example 7\n\n";
cout << "This program reads in a data file then runs a steady-state GA \n";
cout << "whose objective function tries to match the pattern of bits that\n";
cout << "are in the data file.\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.
for(int ii=1; ii<argc; ii++) {
if(strcmp(argv[ii++],"seed") == 0) {
GARandomSeed((unsigned int)atoi(argv[ii]));
}
}
// Set the default values of the parameters.
int i,j;
GAParameterList params;
GASteadyStateGA::registerDefaultParameters(params);
params.set(gaNpopulationSize, 50); // number of individuals in population
params.set(gaNpCrossover, 0.8); // likelihood of doing crossover
params.set(gaNpMutation, 0.001); // probability of mutation
params.set(gaNnGenerations, 200); // number of generations
params.set(gaNscoreFrequency, 20); // how often to record scores
params.set(gaNflushFrequency, 50); // how often to flush scores to file
params.set(gaNscoreFilename, "bog.dat");
params.parse(argc, argv, gaFalse);
char datafile[128] = "smiley.txt";
char parmfile[128] = "";
// Parse the command line for arguments. We look for two possible arguments
// (after the parameter list has grabbed everything it recognizes). One is the
// name of a data file from which to read, the other is the name of a
// parameters file from which to read. Notice that any parameters in the
// parameters file will override the defaults above AND any entered on the
// command line.
for(i=1; i<argc; i++){
if(strcmp("dfile", argv[i]) == 0){
if(++i >= argc){
cerr << argv[0] << ": the data file option needs a filename.\n";
exit(1);
}
else{
sprintf(datafile, argv[i]);
continue;
}
}
else if(strcmp("pfile", argv[i]) == 0){
if(++i >= argc){
cerr << argv[0] << ": the parameters file option needs a filename.\n";
exit(1);
}
else{
sprintf(parmfile, argv[i]);
params.read(parmfile);
continue;
}
}
else if(strcmp("seed", argv[i]) == 0){
if(++i < argc) continue;
continue;
}
else {
cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n";
cerr << "valid arguements include GAlib arguments plus:\n";
cerr << " dfile\tdata file from which to read (" << datafile << ")\n";
cerr << " pfile\tparameters file (" << parmfile << ")\n\n";
cerr << "default parameters are:\n" << params << "\n\n";
exit(1);
}
}
// Read in the pattern from the specified file. File format is pretty simple:
// two integers that give the height then width of the matrix, then the matrix
// of 1's and 0's (with whitespace inbetween).
// Here we use a binary string genome to store the desired pattern. This
// shows how you can read in directly from a stream into a genome. (This can
// be useful in a population initializer when you want to bias your population)
ifstream inStream(datafile, ios :: in);
if(!inStream){
cerr << "Cannot open " << datafile << " for input.\n";
exit(1);
}
int height, width;
inStream >> height >> width;
GA2DBinaryStringGenome target(width, height);
inStream >> target;
inStream.close();
// Print out the pattern to be sure we got the right one.
cout << "input pattern:\n";
for(j=0; j<height; j++){
for(i=0; i<width; i++)
cout << (target.gene(i,j) == 1 ? '*' : ' ') << " ";
cout << "\n";
}
cout << "\n"; cout.flush();
// Now create the first genome and the GA. When we create the genome, we give
// it not only the objective function but also 'user data'. In this case, the
// user data is a pointer to our target pattern. From a C++ point of view it
// would be better to derive a new genome class with its own data, but here we
// just want a quick-and-dirty implementation, so we use the user-data.
GA2DBinaryStringGenome genome(width, height, objective, (void *)&target);
GASteadyStateGA ga(genome);
// When you use a GA with overlapping populations, the default score
// frequency (how often the best of generation score is recorded) defaults
// to 100. We use the parameters member function to change this value (along
// with all of the other parameters we set above). You can also change the
// score frequency using the scoreFrequency member function of the GA. Each of
// the parameters can be set individually if you like.
// Here we just use the values that were set in the parameter list.
ga.parameters(params);
// The default selection method is RouletteWheel. Here we set the selection
// method to TournamentSelection.
GATournamentSelector selector;
ga.selector(selector);
// The following member functions override the values that were set using the
// parameter list. They are commented out here so that you can see how they
// would be used.
// We can control the amount of overlap from generation to generation using the
// pReplacement member function. If we specify a value of 1 (100%) then the
// entire population is replaced each generation. Notice that the percentage
// must be high enough to have at least one individual produced in each
// generation. If not, the GA will post a warning message.
// ga.pReplacement(0.3);
// Often we use the number of generations as the criterion for terminating the
// GA run. Here we override that and tell the GA to use convergence as a
// termination criterion. Note that you can pass ANY function as the stopping
// criterion (as long as it has the correct signature).
// Notice that the values we set here for p- and n-convergence override those
// that we set in the parameters object.
ga.terminator(GAGeneticAlgorithm::TerminateUponConvergence);
// ga.pConvergence(0.99); // converge to within 1%
// ga.nConvergence(100); // within the last 100 generations
// Evolve the GA 'by hand'. When you use this method, be sure to initialize
// the GA before you start to evolve it. You can print out the status of the
// current population by using the ga.population() member function. This is
// also how you would print the status of the GA to disk along the way (rather
// than waiting to the end then printing the scores, for example).
ga.initialize();
while(!ga.done()){
++ga;
}
ga.flushScores();
// Now that the GA is finished, we set our default genome to equal the contents
// of the best genome that the GA found. Then we print it out.
genome = ga.statistics().bestIndividual();
cout << "the ga generated:\n";
for(j=0; j<height; j++){
for(i=0; i<width; i++)
cout << (genome.gene(i,j) == 1 ? '*' : ' ') << " ";
cout << "\n";
}
cout << "\n"; cout.flush();
cout << "best of generation data are in '" << ga.scoreFilename() << "'\n";
return 0;
}
// This objective function just tries to match the genome to the pattern in the
// user data.
float
objective(GAGenome & c)
{
GA2DBinaryStringGenome & genome = (GA2DBinaryStringGenome &)c;
GA2DBinaryStringGenome * pattern =
(GA2DBinaryStringGenome *)c.userData();
float value=0.0;
for(int i=0; i<genome.width(); i++)
for(int j=0; j<genome.height(); j++)
value += (float)(genome.gene(i,j) == pattern->gene(i,j));
return(value);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -