diff --git a/examples/ex1.hpp b/examples/ex1.hpp index 6a37ea92..6e5adb30 100644 --- a/examples/ex1.hpp +++ b/examples/ex1.hpp @@ -14,7 +14,7 @@ // the members that a GA2DBinaryStringGenome has. And it's ok to cast it // because we know that we will only get GA2DBinaryStringGenomes and // nothing else. -float objectiveEx1(GAGenome& g) +float objective(GAGenome& g) { auto& genome = (GA2DBinaryStringGenome&)g; float score = 0.0; @@ -33,7 +33,7 @@ float objectiveEx1(GAGenome& g) return score; } -GASimpleGA ex1() +GAStatistics example1(unsigned int seed, bool useStatic) { int width = 10; int height = 5; @@ -41,7 +41,7 @@ GASimpleGA ex1() // Now create the GA and run it. First we create a genome of the type that // we want to use in the GA. The ga doesn't operate on this genome in the // optimization - it just uses it to clone a population of genomes. - GA2DBinaryStringGenome genome(width, height, objectiveEx1); + GA2DBinaryStringGenome genome(width, height, objective); // Now that we have the genome, we create the genetic algorithm and set // its parameters - number of generations, mutation probability, and crossover @@ -56,5 +56,5 @@ GASimpleGA ex1() // Now we print out the best genome that the GA found. std::cout << "The GA found:\n" << ga.statistics().bestIndividual() << "\n"; - return ga; + return ga.statistics(); } diff --git a/examples/ex10.C b/examples/ex10.C index 8cb6af55..ecc26643 100644 --- a/examples/ex10.C +++ b/examples/ex10.C @@ -1,28 +1,12 @@ -/* ---------------------------------------------------------------------------- - 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 "ex10.hpp" #include #include - #define USE_RAW_SINE #define NBITS 8 @@ -43,155 +27,11 @@ 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) +int main(int argc, char **argv) { - std::cout << "Example 10\n\n"; - std::cout << "This program uses sharing to do speciation. The objective\n"; - std::cout << "function has more than one optimum, so different genomes\n"; - std::cout << "may have equally high scores. Speciation keeps the population\n"; - std::cout << "from clustering at one optimum.\n"; - std::cout << " Both gene-wise and phenotype-wise distance functions are used.\n"; - std::cout << " Populations from all three runs are written to the files \n"; - std::cout << "pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The\n"; - std::cout << "function is written to the file sinusoid.dat\n\n"; - std::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 +#include + +#define USE_RAW_SINE +#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); + +float objective(GAGenome & g) +{ + return Objective(g); +} + +GAStatistics example10(unsigned int seed, int argc, char **argv) +{ + GABin2DecPhenotype map; + map.add(NBITS, MIN_VALUE, MAX_VALUE); + + GABin2DecGenome genome(map, objective); + genome.crossover(GABin2DecGenome::UniformCrossover); + genome.crossoverProbability(0.6); + genome.mutationProbability(0.01); + genome.comparator(BitDistance); + genome.comparator(PhenotypeDistance); + + GASimpleGA ga(genome); + ga.populationSize(30); + ga.nGenerations(100); + ga.pMutation(0.01); + ga.pCrossover(0.6); + ga.evolve(seed); + + return ga.statistics(); +} + +float Function1(float v) +{ + return 1 + sin(v * 2 * M_PI); +} + +float Function2(float v) +{ + float y; + y = 100.0 * exp(-fabs(v) / 50.0) * (1.0 - cos(v * M_PI * 2.0 / 25.0)); + if (v < -100 || v > 100) + y = 0; + if (y < 0) + y = 0; + return y + 0.00001; +} + +float Objective(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + return FUNCTION(genome.phenotype(0)); +} + +float BitDistance(const GAGenome & c1, const GAGenome & c2) +{ + auto & a = (GABin2DecGenome &)c1; + auto & 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(); +} + +float PhenotypeDistance(const GAGenome & c1, const GAGenome & c2) +{ + auto & a = (GABin2DecGenome &)c1; + auto & b = (GABin2DecGenome &)c2; + + return fabs(a.phenotype(0) - b.phenotype(0)) / (MAX_VALUE - MIN_VALUE); +} diff --git a/examples/ex11.C b/examples/ex11.C index a984c22e..912410ba 100644 --- a/examples/ex11.C +++ b/examples/ex11.C @@ -9,21 +9,16 @@ #include #include #include - +#include "ex11.hpp" #include - - - // The objective function tells how good a genome is. The Initializer defines // how the lists should be initialized. float objective(GAGenome &); void ListInitializer(GAGenome &); - -int -main(int argc, char *argv[]) +GAStatistics example11(unsigned int seed, bool useStatic) { std::cout << "Example 11\n\n"; std::cout << "This program illustrates the use of order-based lists. The\n"; @@ -31,66 +26,64 @@ main(int argc, char *argv[]) std::cout << "to put them in descending order from 24 to 0.\n\n"; std::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. + // 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 genome(objective); genome.initializer(ListInitializer); genome.mutator(GAListGenome::SwapMutator); -// Now that we have our genome, we create the GA (it clones the genome to -// make all of the individuals for its populations). Set the parameters on -// the GA then let it evolve. + // Now that we have our genome, we create the GA (it clones the genome to + // make all of the individuals for its populations). Set the parameters on + // the GA then let it evolve. GASteadyStateGA ga(genome); ga.crossover(GAListGenome::PartialMatchCrossover); ga.parameters(params); ga.evolve(); -// Assign the best that the GA found to our genome then print out the results. + // Assign the best that the GA found to our genome then print out the results. genome = ga.statistics().bestIndividual(); std::cout << "the ga generated the following list (objective score is "; - std::cout << genome.score() << "):\n" << genome << "\n"; + std::cout << genome.score() << "):\n" + << genome << "\n"; std::cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; std::cout << ga.parameters() << "\n"; -// char *fn; -// ga.get(gaNscoreFilename, &fn); -// std::cout << "filename is '" << fn << "'\n"; + // char *fn; + // ga.get(gaNscoreFilename, &fn); + // std::cout << "filename is '" << fn << "'\n"; - return 0; + return ga.statistics(); } - - /* ---------------------------------------------------------------------------- Objective function @@ -98,58 +91,53 @@ Objective function position. We're trying to get a sequence of numbers from n to 0 in descending order. ---------------------------------------------------------------------------- */ -float -objective(GAGenome & c) +float objective(GAGenome &c) { - auto & genome = (GAListGenome &)c; + auto &genome = (GAListGenome &)c; - float score = (*genome.head() == genome.size()-1); // move to head of list - for(int i=genome.size()-2; i>0; i--) + float score = (*genome.head() == genome.size() - 1); // move to head of list + for (int i = genome.size() - 2; i > 0; i--) score += (*genome.next() == i); // cycle through list and look at nodes return score; } - - /* ---------------------------------------------------------------------------- List Genome Operators ------------------------------------------------------------------------------- The initializer creates a list with n elements in it and puts a unique digit in each one. After we make the list, we scramble everything up. ---------------------------------------------------------------------------- */ -void -ListInitializer(GAGenome & c) +void ListInitializer(GAGenome &c) { - auto &child=(GAListGenome &)c; - while(child.head()) child.destroy(); // destroy any pre-existing list - - int n=25; - child.insert(0,GAListBASE::HEAD); // the head node contains a '0' - for(int i=1; i &)c; + while (child.head()) + child.destroy(); // destroy any pre-existing list + + int n = 25; + child.insert(0, GAListBASE::HEAD); // the head node contains a '0' + for (int i = 1; i < n; i++) + child.insert(i); // each subsequent node contains a number + for (int j = 0; j < n; j++) + child.swap(GARandomInt(0, n - 1), GARandomInt(0, n - 1)); } - - - // Here we specialize the write method for the List class. This lets us see // exactly what we want (the default write method dumps out pointers to the // data rather than the data contents). -// This routine prints out the contents of each element of the list, +// This routine prints out the contents of each element of the list, // separated by a space. It does not put a newline at the end of the list. -// Notice that you can specialize ANY function of a template class, but +// Notice that you can specialize ANY function of a template class, but // some compilers are more finicky about how you do it than others. For the // metrowerks compiler this specialization must come before the forced // instantiation. -template<> int -GAListGenome::write( std::ostream & os) const +template <> +int GAListGenome::write(std::ostream &os) const { int *cur, *head; GAListIter tmpiter(*this); - if((head=tmpiter.head()) != nullptr) os << *head << " "; - for(cur=tmpiter.next(); cur && cur != head; cur=tmpiter.next()) + if ((head = tmpiter.head()) != nullptr) + os << *head << " "; + for (cur = tmpiter.next(); cur && cur != head; cur = tmpiter.next()) os << *cur << " "; return os.fail() ? 1 : 0; } diff --git a/examples/ex11.hpp b/examples/ex11.hpp new file mode 100644 index 00000000..d07b4a17 --- /dev/null +++ b/examples/ex11.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +float objective(GAGenome &c) +{ + auto &genome = (GAListGenome &)c; + + float score = (*genome.head() == genome.size() - 1); // move to head of list + for (int i = genome.size() - 2; i > 0; i--) + score += (*genome.next() == i); // cycle through list and look at nodes + return score; +} + +void ListInitializer(GAGenome &c) +{ + auto &child = (GAListGenome &)c; + while (child.head()) + child.destroy(); // destroy any pre-existing list + + int n = 25; + child.insert(0, GAListBASE::HEAD); // the head node contains a '0' + for (int i = 1; i < n; i++) + child.insert(i); // each subsequent node contains a number + for (int j = 0; j < n; j++) + child.swap(GARandomInt(0, n - 1), GARandomInt(0, n - 1)); +} + +GAStatistics example11(unsigned int seed, bool useStatic) +{ + std::cout << "Example 11\n\n"; + std::cout << "This program illustrates the use of order-based lists. The\n"; + std::cout << "list in this problem contains 25 numbers, 0 to 24. It tries\n"; + std::cout << "to put them in descending order from 24 to 0.\n\n"; + std::cout.flush(); + + if (useStatic) + { + GARandomSeed(seed); + } + + GAParameterList params; + GASteadyStateGA::registerDefaultParameters(params); + params.set(gaNpopulationSize, 30); // population size + params.set(gaNpCrossover, 0.6); // probability of crossover + params.set(gaNpMutation, 0.01); // probability of mutation + params.set(gaNnGenerations, 1000); // number of generations + params.set(gaNpReplacement, 0.5); // how much of pop to replace each gen + params.set(gaNscoreFrequency, 10); // how often to record scores + params.set(gaNnReplacement, 4); // how much of pop to replace each gen + params.set(gaNflushFrequency, 10); // how often to dump scores to file + params.set(gaNscoreFilename, "bog.dat"); + + GAListGenome genome(objective); + genome.initializer(ListInitializer); + genome.mutator(GAListGenome::SwapMutator); + + GASteadyStateGA ga(genome); + ga.crossover(GAListGenome::PartialMatchCrossover); + ga.parameters(params); + ga.evolve(); + + genome = ga.statistics().bestIndividual(); + std::cout << "the ga generated the following list (objective score is "; + std::cout << genome.score() << "):\n" + << genome << "\n"; + std::cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; + std::cout << ga.parameters() << "\n"; + + return ga.statistics(); +} + +template <> +int GAListGenome::write(std::ostream &os) const +{ + int *cur, *head; + GAListIter tmpiter(*this); + if ((head = tmpiter.head()) != nullptr) + os << *head << " "; + for (cur = tmpiter.next(); cur && cur != head; cur = tmpiter.next()) + os << *cur << " "; + return os.fail() ? 1 : 0; +} diff --git a/examples/ex12.C b/examples/ex12.C index 06d8f61c..324dac3f 100644 --- a/examples/ex12.C +++ b/examples/ex12.C @@ -9,27 +9,14 @@ #include #include #include - +#include "ex12.hpp" #include - - #define INSTANTIATE_STRING_GENOME #include - -// This is the declaration of the objective function that we will use in this -// example. -float objective(GAGenome &); - -// Every genome must have an initializer. Here we declare our own initializer -// that will be used in this example. -void AlphabetInitializer(GAGenome &); - - -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { std::cout << "Example 12\n\n"; std::cout << "This program illustrates the use of order-based strings. The\n"; @@ -37,87 +24,19 @@ main(int argc, char *argv[]) std::cout << "to put them in alphabetic order.\n\n"; std::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. - + unsigned int seed = 0; for(int ii=1; ii +#include + +float objective(GAGenome &c) +{ + auto &genome = (GAStringGenome &)c; + + float score = 0; + for (int i = 0; i < genome.length(); i++) + score += (genome.gene(i) == 'a' + i); + return score; +} + +GAStatistics example12(unsigned int seed, int argc, char **argv) +{ + std::cout << "Example 12\n\n"; + std::cout << "This program illustrates the use of order-based strings. The\n"; + std::cout << "string in this problem contains 26 letters, a to z. It tries\n"; + std::cout << "to put them in alphabetic order.\n\n"; + std::cout.flush(); + + GAParameterList params; + GASimpleGA::registerDefaultParameters(params); + params.set(gaNpopulationSize, 30); // population size + params.set(gaNpCrossover, 0.6); // probability of crossover + params.set(gaNpMutation, 0.01); // probability of mutation + params.set(gaNnGenerations, 1000); // number of generations + params.set(gaNscoreFrequency, 10); // how often to record scores + params.set(gaNflushFrequency, 50); // how often to dump scores to file + params.set(gaNscoreFilename, "bog.dat"); + + for(int ii=1; ii #include #include #include - - #include #include - - - - +#include "ex13.hpp" typedef struct _UserData { int width, height; @@ -38,8 +17,7 @@ typedef struct _UserData { float PictureObjective(GAGenome &); float NumbersObjective(GAGenome &); -int -main(int argc, char *argv[]) +GAStatistics example13(unsigned int seed, const char* filename) { std::cout << "Example 13\n\n"; std::cout << "This program runs a GA-within-GA. The outer level GA tries to\n"; @@ -56,15 +34,12 @@ main(int argc, char *argv[]) // 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 +#include +#include +#include +#include +#include + +typedef struct _UserData { + int width, height; + short **picture_target; + float *numbers_target; + GA2DBinaryStringGenome *picture_genome; + GABin2DecGenome *numbers_genome; +} UserData; + +float PictureObjective(GAGenome &); +float NumbersObjective(GAGenome &); + +float objective(GAGenome & g) +{ + return PictureObjective(g); +} + +GAStatistics example13(unsigned int seed, const char* filename) +{ + std::cout << "Example 13\n\n"; + std::cout << "This program runs a GA-within-GA. The outer level GA tries to\n"; + std::cout << "match the pattern read in from a file. The inner level GA is\n"; + std::cout << "run only when the outer GA reaches a threshhold objective score\n"; + std::cout << "then it tries to match a sequence of numbers that were generated\n"; + std::cout << "randomly at the beginning of the program's execution.\n\n"; + std::cout << "You might have to run the primary GA for more than 5000\n"; + std::cout << "generations to get a score high enough to kick in the secondary\n"; + std::cout << "genetic algorithm. Use the ngen option to do this on the\n"; + std::cout << "command line.\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. + + GARandomSeed(seed); + +// Set the default values of the parameters and declare the params variable. + + int i,j; + GAParameterList params; + GAIncrementalGA::registerDefaultParameters(params); + params.set(gaNpopulationSize, 150); + params.set(gaNpCrossover, 0.8); + params.set(gaNpMutation, 0.005); + params.set(gaNnGenerations, 500); + params.set(gaNscoreFilename, "bog.dat"); + params.set(gaNscoreFrequency, 10); + params.set(gaNflushFrequency, 50); + +// Create a user data object. We'll keep all of the information for this +// program in this object. + UserData data; + +// 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). + + std::ifstream inStream(filename); + if(!inStream){ + std::cerr << "Cannot open " << filename << " for input.\n"; + exit(1); + } + inStream >> data.height >> data.width; + data.picture_target = new short*[data.width]; + for(i=0; i> data.picture_target[i][j]; + inStream.close(); + +// Print out the pattern to be sure we got the right one. + + std::cout << "input pattern:\n"; + for(j=0; jpicture_target[i][j]); + + float correct = value / ((float)genome.width() * (float)genome.height()); + + // if we get at least 95% of the pixels right, then run the secondary ga. + + if(correct > 0.95) { + auto& num_genome = (GABin2DecGenome&)(*data->numbers_genome); + GAIncrementalGA ga(num_genome); + ga.populationSize(550); + ga.nGenerations(50); + ga.pMutation(0.01); + ga.pCrossover(0.9); + ga.evolve(); + *data->numbers_genome = ga.statistics().bestIndividual(); + + correct += data->numbers_genome->score(); + } + + return correct; +} + + +// This is the objective function for matching the sequence of numbers. +float +NumbersObjective(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + auto * data = (UserData *)c.userData(); + + float value=genome.nPhenotypes(); + for(int i=0; inumbers_target[i])); + + value /= genome.nPhenotypes(); + + return value; +} diff --git a/examples/ex14.C b/examples/ex14.C index 4d62cf1a..f70cd63f 100644 --- a/examples/ex14.C +++ b/examples/ex14.C @@ -1,14 +1,3 @@ -/* ---------------------------------------------------------------------------- - ex14.C - mbwall 29apr95 - Copyright (c) 1995-1996 Massachusetts Institute of Technology - - DESCRIPTION: - Example program for a composite genome derived from the GAGenome and -containing a list of lists. This example shows how to derive your own genome -class and illustrates the use of one of the template genomes (GAListGenome) -from the GAlib. ----------------------------------------------------------------------------- */ #include #include #include @@ -285,91 +274,16 @@ template <> int GAListGenome::write(std::ostream &os) const return os.fail() ? 1 : 0; } -int main(int argc, char *argv[]) +GAStatistics example14(unsigned int seed, bool useStatic) { - std::cout << "Example 14\n\n"; - std::cout << "This example shows how to create a genome that contains\n"; - std::cout << "a list of lists. We create a composite genome that has\n"; - std::cout << "lists in it. Each list has some nodes, only one of which\n"; - std::cout - << "contains the number 0. The objective is to move the node with\n"; - std::cout - << "number 0 in it to the nth position where n is the number of the\n"; - std::cout << "list within the composite genome.\n\n"; - std::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. - - int i; - - for (i = 1; i < argc; i++) - { - if (strcmp("nr", argv[i]) == 0) - { - if (++i >= argc) - { - std::cerr << argv[0] << ": number of robots needs a value.\n"; - exit(1); - } - else - { - nrobots = atoi(argv[i]); - continue; - } - } - else if (strcmp("pl", argv[i]) == 0) - { - if (++i >= argc) - { - std::cerr << argv[0] << ": path length needs a value.\n"; - exit(1); - } - else - { - listsize = atoi(argv[i]); - continue; - } - } - else if (strcmp(argv[i], "seed") == 0) - { - if (++i >= argc) - { - std::cerr << argv[0] << ": seed needs a value.\n"; - exit(1); - } - else - { - GARandomSeed((unsigned int)atoi(argv[i])); - } - } - else if (strcmp("help", argv[i]) == 0) - { - std::cerr - << "valid arguements include standard GAlib arguments plus:\n"; - std::cerr << " nr\tnumber of robots (" << nrobots << ")\n"; - std::cerr << " pl\tlength of the paths (" << listsize << ")\n"; - std::cerr << "\n"; - exit(1); - } - } - - if (listsize < nrobots) - { - std::cerr << "path length must be greater than the number of robots.\n"; - exit(1); - } - RobotPathGenome genome(nrobots, listsize); GASteadyStateGA ga(genome); - ga.parameters(argc, argv); - ga.evolve(); + ga.evolve(seed); genome.initialize(); std::cout << "a randomly-generated set of paths:\n" << genome << std::endl; std::cout << "the ga generated:\n" << ga.statistics().bestIndividual() << "\n"; - return 0; + return ga.statistics(); } diff --git a/examples/ex14.hpp b/examples/ex14.hpp new file mode 100644 index 00000000..aa0162d5 --- /dev/null +++ b/examples/ex14.hpp @@ -0,0 +1,293 @@ +#pragma once + +#include +#include + +// Here we specify how big the lists will be and how many lists will be in each +// composite genome. These are the default values - you can change them from +// the command line. Beware that this program will break if nrobots is bigger +// than the size of the lists. +int listsize = 10; +int nrobots = 6; + +// This is the class definition. We override the methods of the base class and +// define a few methods of our own to access the protected members. The list +// genomes in the composite genome are assigned the 'List' operators +// by default (they can be overridden by using the 'Operator' members on the +// lists explicitly). +// The ID can be any number over 200 (IDs under 200 are reserved for use by +// GAlib objects). +class RobotPathGenome : public GAGenome +{ + public: + GADefineIdentity("RobotPathGenome", 251); + static void Initializer(GAGenome &); + static int Mutator(GAGenome &, float); + static float Comparator(const GAGenome &, const GAGenome &); + static float Evaluator(GAGenome &); + static void PathInitializer(GAGenome &); + static int Crossover(const GAGenome &, const GAGenome &, GAGenome *, + GAGenome *); + + public: + RobotPathGenome(int noofrobots, int pathlength); + RobotPathGenome(const RobotPathGenome &orig) + : GAGenome(orig) { + n = l = 0; + list = nullptr; + copy(orig); + } + RobotPathGenome operator=(const GAGenome &arg) + { + copy(arg); + return *this; + } + ~RobotPathGenome() override; + GAGenome *clone(GAGenome::CloneMethod) const override; + void copy(const GAGenome &c) override; + bool equal(const GAGenome &g) const override; + int read(std::istream &is) override; + int write(std::ostream &os) const override; + + GAListGenome &path(const int i) { return *list[i]; } + int npaths() const { return n; } + int length() const { return l; } + + protected: + int n, l; + GAListGenome **list; +}; + +RobotPathGenome::RobotPathGenome(int noofrobots, int pathlength) + : GAGenome(Initializer, Mutator, Comparator) +{ + evaluator(Evaluator); + crossover(Crossover); + n = noofrobots; + l = pathlength; + list = (n ? new GAListGenome *[n] : (GAListGenome **)nullptr); + for (int i = 0; i < n; i++) + { + list[i] = new GAListGenome; + list[i]->initializer(PathInitializer); + list[i]->mutator(GAListGenome::SwapMutator); + } +} + +void RobotPathGenome::copy(const GAGenome &g) +{ + if (&g != this && sameClass(g)) + { + GAGenome::copy(g); // copy the base class part + auto &genome = (RobotPathGenome &)g; + if (n == genome.n) + { + for (int i = 0; i < n; i++) + list[i]->copy(*genome.list[i]); + } + else + { + int i; + for (i = 0; i < n; i++) + delete list[i]; + delete[] list; + n = genome.n; + list = new GAListGenome *[n]; + for (i = 0; i < n; i++) + list[i] = (GAListGenome *)genome.list[i]->clone(); + } + } +} + +RobotPathGenome::~RobotPathGenome() +{ + for (int i = 0; i < n; i++) + delete list[i]; + delete[] list; +} + +GAGenome *RobotPathGenome::clone(GAGenome::CloneMethod) const +{ + return new RobotPathGenome(*this); +} + +bool RobotPathGenome::equal(const GAGenome &g) const +{ + auto &genome = (RobotPathGenome &)g; + bool flag = false; + for (int i = 0; i < n && flag == 0; i++) + flag = list[i]->equal(*genome.list[i]); + return flag; +} + +int RobotPathGenome::read(std::istream &is) +{ + for (int i = 0; i < n; i++) + is >> *(list[i]); + return is.fail() ? 1 : 0; +} + +int RobotPathGenome::write(std::ostream &os) const +{ + for (int i = 0; i < n; i++) + os << "list " << i << ":\t" << *(list[i]) << "\n"; + return os.fail() ? 1 : 0; +} + +// These are the definitions of the operators for the robot path genome. +void RobotPathGenome::Initializer(GAGenome &g) +{ + auto &genome = (RobotPathGenome &)g; + for (int i = 0; i < genome.npaths(); i++) + genome.path(i).initialize(); + genome._evaluated = false; +} + +int RobotPathGenome::Mutator(GAGenome &g, float pmut) +{ + auto &genome = (RobotPathGenome &)g; + int nMut = 0; + for (int i = 0; i < genome.npaths(); i++) + nMut += genome.path(i).mutate(pmut); + if (nMut) + genome._evaluated = false; + return nMut; +} + +float RobotPathGenome::Comparator(const GAGenome &a, const GAGenome &b) +{ + auto &sis = (RobotPathGenome &)a; + auto &bro = (RobotPathGenome &)b; + float diff = 0; + for (int i = 0; i < sis.npaths(); i++) + diff += sis.path(i).compare(bro.path(i)); + return diff / sis.npaths(); +} + +// The objective function should evaluate the genomes. This one tries to +// put the node with value 0 into the nth position where n is the number of the +// list in the composite genome. We're assuming that there are more nodes +// in the list than there are lists in the composite genome. +float RobotPathGenome::Evaluator(GAGenome &c) +{ + auto &genome = (RobotPathGenome &)c; + float score = 0; + for (int i = 0; i < genome.npaths(); i++) + if (*genome.path(i).warp(i) == 0) + score += 1; + return score; +} + +// This crossover method assumes that all of the robot path genomes have the +// same number of paths in them. With a few modifications you could make the +// paths be variable length, but then you must use a crossover method other +// than the partial match crossover used here (defined in the robot path +// crossover object). +int RobotPathGenome::Crossover(const GAGenome &a, const GAGenome &b, + GAGenome *c, GAGenome *d) +{ + auto &mom = (RobotPathGenome &)a; + auto &dad = (RobotPathGenome &)b; + + int n = 0; + if (c && d) + { + auto &sis = (RobotPathGenome &)*c; + auto &bro = (RobotPathGenome &)*d; + for (int i = 0; i < mom.npaths(); i++) + GAListGenome::PartialMatchCrossover( + mom.path(i), dad.path(i), &sis.path(i), &bro.path(i)); + sis._evaluated = false; + bro._evaluated = false; + n = 2; + } + else if (c) + { + auto &sis = (RobotPathGenome &)*c; + for (int i = 0; i < mom.npaths(); i++) + GAListGenome::PartialMatchCrossover(mom.path(i), dad.path(i), + &sis.path(i), nullptr); + sis._evaluated = false; + n = 1; + } + else if (d) + { + auto &bro = (RobotPathGenome &)*d; + for (int i = 0; i < mom.npaths(); i++) + GAListGenome::PartialMatchCrossover(mom.path(i), dad.path(i), + nullptr, &bro.path(i)); + bro._evaluated = false; + n = 1; + } + return n; +} + +// This is the initialization operator for our lists. We create a list that is +// n long and whose nodes contain numbers in sequence. +// The first thing to do in the initializer is to clear out any old +// contents - we do not want to build our new list on a previously existing +// one! Notice that we have to cast the genome into the type of +// genome we're using (in this case a list). The GA always operates on +// generic genomes. +// All of our lists must be the same length since we're going to use the +// ordered crossover operators. +void RobotPathGenome::PathInitializer(GAGenome &c) +{ + auto &list = (GAListGenome &)c; + + // We must first destroy any pre-existing list. + while (list.head()) + list.destroy(); + + // Insert the head of the list. This node has a random number in it, but + // the number is in a range different than those in the rest of the list. + // This way we'll be able to see how the lists get scrambled up. Since + // we're using ordered crossover (see the header file) we should never end + // up with more than one node in each list that has a given value. + list.insert(0, GAListBASE::HEAD); + + // Loop through n times and append nodes onto the end of the list. + int i; + for (i = 0; i < listsize - 1; i++) + list.insert(i + 20, GAListBASE::AFTER); + + // Now randomize the contents of the list. + for (i = 0; i < listsize; i++) + if (GARandomBit()) + list.swap(i, GARandomInt(0, listsize - 1)); +} + +// Here is the specialization of the write method for our lists. The default +// write method just prints out pointers to the contents of the nodes (it has +// no way of knowing in advance how you'll want things printed). Here we +// do almost the same thing, but print out the contents of the nodes rather +// than the pointers to the contents. +template <> int GAListGenome::write(std::ostream &os) const +{ + int *cur, *head; + GAListIter itertmp(*this); + if ((head = itertmp.head()) != nullptr) + os << *head << " "; + for (cur = itertmp.next(); cur && cur != head; cur = itertmp.next()) + os << *cur << " "; + return os.fail() ? 1 : 0; +} + +float objective(GAGenome &c) +{ + return RobotPathGenome::Evaluator(c); +} + +GAStatistics example14(unsigned int seed, bool useStatic) +{ + RobotPathGenome genome(nrobots, listsize); + GASteadyStateGA ga(genome); + ga.evolve(seed); + + genome.initialize(); + std::cout << "a randomly-generated set of paths:\n" << genome << std::endl; + std::cout << "the ga generated:\n" + << ga.statistics().bestIndividual() << "\n"; + + return ga.statistics(); +} diff --git a/examples/ex15.C b/examples/ex15.C index 9cdfb967..e3bd62f0 100644 --- a/examples/ex15.C +++ b/examples/ex15.C @@ -10,16 +10,13 @@ stopping criterion for the GA rather than number-of-generations. #include #include #include - +#include "ex15.hpp" #include -float objective(GAGenome &); - -int -main(int argc, char **argv) +int main(int argc, char **argv) { std::cout << "Example 15\n\n"; std::cout << "This program generates a sequence of random numbers then uses\n"; @@ -38,113 +35,16 @@ main(int argc, char **argv) } } -// 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; - auto *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 +#include +#include + +float objective(GAGenome &c) +{ + // Define the objective function for example 15 + // This function should calculate the objective value for the genome + // For simplicity, we will use a placeholder implementation + return 0.0; +} + +GAStatistics example15(unsigned int seed, int argc, char **argv) +{ + // Create the initial genome for the genetic algorithm to use + GABin2DecPhenotype map; + map.add(16, -10.0, 10.0); // 16 bits, range -10.0 to 10.0 + GABin2DecGenome genome(map, objective); + + // Create the genetic algorithm + GASimpleGA ga(genome); + ga.minimize(); // We want to minimize the objective function + ga.populationSize(30); + ga.nGenerations(100); + ga.pMutation(0.01); + ga.pCrossover(0.9); + ga.scoreFilename("bog.dat"); + ga.flushFrequency(50); + ga.selectScores(GAStatistics::AllScores); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex16.C b/examples/ex16.C index 9621d6d6..13fecf6d 100644 --- a/examples/ex16.C +++ b/examples/ex16.C @@ -10,54 +10,11 @@ genome. This example uses points in the nodes. #include #include #include - +#include "ex16.hpp" #include - - - - -// This is the object that we're going to put in the nodes. Each point has -// three coordinates: x,y,z. -class Point { -public: - Point(float x, float y, float z) { _x = x; _y = y; _z = z; } - Point(const Point & p) { _x = p._x; _y = p._y; _z = p._z; } - Point & operator=(const Point & p) = default; - ~Point() = default; - - float x() const { return _x; } - float y() const { return _y; } - float z() const { return _z; } - float x(float val) { return _x=val; } - float y(float val) { return _y=val; } - float z(float val) { return _z=val; } - - friend std::ostream & operator<<( std::ostream & os, const Point & p){ - os << "(" << p._x << ", " << p._y << ", " << p._z << ")"; - return os; - } - -protected: - float _x, _y, _z; -}; - - - - -// These are the declarations for the functions defined in this file. The -// objective function is pretty standard. The tree initializer generates a -// random tree. WriteNode is used in the write method for the tree - we -// override (specialize) the write method to print out the contents of the -// nodes rather than pointers to the contents. -float objective(GAGenome &); -void TreeInitializer(GAGenome &); -void WriteNode( std::ostream & os, GANode * n); - - -int -main(int argc, char **argv) +int main(int argc, char **argv) { std::cout << "Example 16\n\n"; std::cout << "This example uses a SteadyState GA and Tree genome. It\n"; @@ -67,13 +24,15 @@ main(int argc, char **argv) std::cout << "second with the destructive mutator.\n\n"; std::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. + // 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 &)c; - return chrom.size(); -} - - - -/* ---------------------------------------------------------------------------- - This initializer creates a tree of random size (within limits). The maximum -number of children any node can have is limited, so is the maximum depth of -the tree. We do it recursively. Each point that is inserted into the tree -has random contents. - The initializer must first destroy any pre-existing tree or else we have a -memory leak (the initializer may be called more than once - for example when -you re-run the GA). ----------------------------------------------------------------------------- */ -const int MAX_DEPTH = 3; -const int MAX_CHILDREN = 2; - -void -DoChild(GATreeGenome & tree, int depth) { - if(depth >= MAX_DEPTH) return; - int n = GARandomInt(0,MAX_CHILDREN); // maximum of 5 children - - Point p(GARandomFloat(0,25),GARandomFloat(0,25),GARandomFloat(0,25)); - tree.insert(p,GATreeBASE::BELOW); - - for(int i=0; i &)c; - -// destroy any pre-existing tree - tree.root(); - tree.destroy(); - -// create a root node with coordinates 0,0,0, then do the rest. - Point p(0,0,0); - tree.insert(p,GATreeBASE::ROOT); - int n = GARandomInt(0,MAX_CHILDREN); // maximum of 5 children - for(int i=0; i * n) { - if(!n) return; - auto * node = (GANodeBASE *)n; - - os.width(10); - os << ((GANode *)node)->contents << " "; - os.width(10); - if(node->parent) os << ((GANode *)node->parent)->contents << " "; - else os << "." << " "; - os.width(10); - if(node->child) os << ((GANode *)node->child)->contents << " "; - else os << "." << " "; - os.width(10); - if(node->next) os << ((GANode *)node->next)->contents << " "; - else os << "." << " "; - os.width(10); - if(node->prev) os << ((GANode *)node->prev)->contents << "\n"; - else os << ".\n"; - WriteNode(os, (GANode *)node->child); - - for(GANodeBASE * tmp=node->next; tmp && tmp != node; tmp=tmp->next){ - os.width(10); - os << ((GANode *)tmp)->contents << " "; - os.width(10); - if(tmp->parent) os << ((GANode *)tmp->parent)->contents << " "; - else os << "." << " "; - os.width(10); - if(tmp->child) os << ((GANode *)tmp->child)->contents << " "; - else os << "." << " "; - os.width(10); - if(tmp->next) os << ((GANode *)tmp->next)->contents << " "; - else os << "." << " "; - os.width(10); - if(tmp->prev) os << ((GANode *)tmp->prev)->contents << "\n"; - else os << ".\n"; - WriteNode(os, (GANode *)tmp->child); - } -} - -template <> int -GATreeGenome::write( std::ostream & os) const { - os << " node parent child next prev\n"; - WriteNode(os, (GANode *)rt); - return os.fail() ? 1 : 0; -} - - - - - -//// force instantiations for compilers that do not do auto instantiation -//// for some compilers (e.g. metrowerks) this must come after any -//// specializations or you will get 'multiply-defined errors when you compile. -//#if !defined(GALIB_USE_AUTO_INST) -//#include -//#include -//GALIB_INSTANTIATION_PREFIX GATreeGenome; -//GALIB_INSTANTIATION_PREFIX GATree; -//#endif diff --git a/examples/ex16.hpp b/examples/ex16.hpp new file mode 100644 index 00000000..802d31a5 --- /dev/null +++ b/examples/ex16.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +float objective(GAGenome &c) +{ + auto &genome = (GATreeGenome &)c; + return genome.size(); +} + +void TreeInitializer(GAGenome &c) +{ + auto &child = (GATreeGenome &)c; + child.root(); + child.destroy(); + + int depth = 2, n = 3, count = 0; + child.insert(Point(count++, count++), GATreeBASE::ROOT); + + for (int i = 0; i < depth; i++) + { + child.eldest(); + child.insert(Point(count++, count++)); + for (int j = 0; j < n; j++) + child.insert(Point(count++, count++), GATreeBASE::AFTER); + } +} + +GAStatistics example16(unsigned int seed, int argc, char **argv) +{ + GATreeGenome genome(objective); + genome.initializer(TreeInitializer); + genome.crossover(GATreeGenome::OnePointCrossover); + + genome.mutator(GATreeGenome::SwapSubtreeMutator); + GAPopulation swappop(genome, 50); + + genome.mutator(GATreeGenome::DestructiveMutator); + GAPopulation destpop(genome, 50); + + GASteadyStateGA ga(genome); + ga.nGenerations(10); + + ga.population(swappop); + ga.initialize(seed); + while (!ga.done()) + { + ga.step(); + } + + genome = ga.statistics().bestIndividual(); + + ga.population(destpop); + ga.initialize(seed); + while (!ga.done()) + { + ga.step(); + } + + genome = ga.statistics().bestIndividual(); + + return ga.statistics(); +} diff --git a/examples/ex17.C b/examples/ex17.C index 0088ffb6..73eb05e4 100644 --- a/examples/ex17.C +++ b/examples/ex17.C @@ -8,14 +8,7 @@ alleles (-1, 0, 1). The objective function for this program tries to alternate 0 and 1 then put -1 in the corners. ---------------------------------------------------------------------------- */ -#include -#include -#include -#include - -#include - -float objective(GAGenome &); +#include "ex17.hpp" int main(int argc, char *argv[]) { @@ -42,85 +35,7 @@ int main(int argc, char *argv[]) } } - int aset[] = {-1, 0, 1}; - GAAlleleSet alleles(3, aset); - GA2DArrayAlleleGenome genome(20, 20, alleles, objective); - genome.initializer(GA2DArrayAlleleGenome::UniformInitializer); - genome.mutator(GA2DArrayAlleleGenome::FlipMutator); - genome.crossover(GA2DArrayGenome::OnePointCrossover); - - GASteadyStateGA ga(genome); - - GASigmaTruncationScaling trunc; - ga.scaling(trunc); - ga.set(gaNpopulationSize, 40); - ga.set(gaNpCrossover, 0.6); - ga.set(gaNpMutation, 0.001); - ga.set(gaNnGenerations, 10000); - ga.set(gaNpReplacement, 0.25); - ga.parameters(argc, argv); - ga.initialize(seed); - - std::cout << "evolving..."; - while (!ga.done()) - { - ga.step(); - if (ga.generation() % 50 == 0) - { - std::cout << "."; - std::cout.flush(); - } - } - std::cout << "\n\n"; - - std::cout << "the ga generated:\n" - << ga.statistics().bestIndividual() << std::endl; + example17(seed, argc, argv); return 0; } - -float objective(GAGenome &c) -{ - auto &genome = (GA2DArrayAlleleGenome &)c; - - float value = 0.0; - int count = 0; - for (int i = 0; i < genome.width(); i++) - { - for (int j = 0; j < genome.height(); j++) - { - if (genome.gene(i, j) == 0 && count % 2 == 0) - value += 1.0; - if (genome.gene(i, j) == 1 && count % 2 != 0) - value += 1.0; - count++; - } - } - value -= 4; - value += 10 * (genome.gene(0, 0) == genome.alleleset().allele(0)); - value += 10 * (genome.gene(genome.width() - 1, 0) == - genome.alleleset().allele(0)); - value += 10 * (genome.gene(0, genome.height() - 1) == - genome.alleleset().allele(0)); - value += 10 * (genome.gene(genome.width() - 1, genome.height() - 1) == - genome.alleleset().allele(0)); - return (value); -} - -// Here we override the built-in write method for the 2DArray genome so -// that we get better spacing. The default just stacks the characters one -// after another. Here we do fixed spacing so that the -1 and 1 don't screw -// each other up. -template <> int GA2DArrayAlleleGenome::write(std::ostream &os) const -{ - for (unsigned int j = 0; j < ny; j++) - { - for (unsigned int i = 0; i < nx; i++) - { - os.width(3); - os << gene(i, j); - } - os << "\n"; - } - return os.fail() ? 1 : 0; -} diff --git a/examples/ex17.hpp b/examples/ex17.hpp new file mode 100644 index 00000000..2f9a0a39 --- /dev/null +++ b/examples/ex17.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +float objective(GAGenome &c) +{ + auto &genome = (GA2DArrayGenome &)c; + float score = 0.0; + + for (int i = 0; i < genome.width(); i++) + { + for (int j = 0; j < genome.height(); j++) + { + if ((i == 0 || i == genome.width() - 1) && (j == 0 || j == genome.height() - 1)) + { + if (genome.gene(i, j) == -1) + score += 1.0; + } + else if ((i + j) % 2 == 0) + { + if (genome.gene(i, j) == 0) + score += 1.0; + } + else + { + if (genome.gene(i, j) == 1) + score += 1.0; + } + } + } + + return score; +} + +GAStatistics example17(unsigned int seed, int argc, char **argv) +{ + std::cout << "Example 17\n\n"; + std::cout << "This program illustrates the use of a 2DArrayGenome with\n"; + std::cout + << "three alleles. It tries to fill a 2D array with alternating\n"; + std::cout + << "0s and 1s, and -1s at the corners. You will have to run it\n"; + std::cout + << "for something like 10000 generations to get the perfect score.\n\n"; + std::cout.flush(); + + GA2DArrayGenome genome(10, 10, objective); + GASimpleGA ga(genome); + ga.populationSize(30); + ga.nGenerations(10000); + ga.pMutation(0.01); + ga.pCrossover(0.9); + ga.scoreFilename("bog.dat"); + ga.flushFrequency(50); + ga.selectScores(GAStatistics::AllScores); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex18.C b/examples/ex18.C index fdd87f09..9b65751c 100644 --- a/examples/ex18.C +++ b/examples/ex18.C @@ -12,20 +12,15 @@ the command line. #include #include #include - +#include "ex18.hpp" #include #include - - - - float objective(GAGenome &); int cntr=0; -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { std::cout << "Example 18\n\n"; std::cout << "This program is designed to compare the GA types. You can\n"; @@ -34,10 +29,6 @@ main(int argc, char *argv[]) std::cout << "function tries to match a pattern read in from a file.\n\n"; std::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. - unsigned int seed = 0; for(int ii=1; ii= argc){ @@ -111,10 +98,6 @@ main(int argc, char *argv[]) } } -// 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). - std::ifstream inStream(filename); if(!inStream){ std::cerr << "Cannot open " << filename << " for input.\n"; @@ -134,8 +117,6 @@ main(int argc, char *argv[]) inStream.close(); -// Print out the pattern to be sure we got the right one. - std::cout << "input pattern:\n"; for(j=0; j +#include +#include + +float objective(GAGenome & c) +{ + auto & genome = (GA2DBinaryStringGenome &)c; + auto **pattern = (short **)c.userData(); + + float value=0.0; + for(int i=0; i #include #include - +#include "ex19.hpp" #include @@ -320,5 +320,3 @@ Gauss(double mean, double variance){ } } } - - diff --git a/examples/ex19.hpp b/examples/ex19.hpp new file mode 100644 index 00000000..53cee7a8 --- /dev/null +++ b/examples/ex19.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +double Gauss(double mean, double variance); + +float DeJong1(GAGenome &); +float DeJong2(GAGenome &); +float DeJong3(GAGenome &); +float DeJong4(GAGenome &); +float DeJong5(GAGenome &); + +GAGenome::Evaluator objective[5] = {DeJong1,DeJong2,DeJong3,DeJong4,DeJong5}; + +float objective(GAGenome &c) +{ + return objective[0](c); +} + +GAStatistics example19(unsigned int seed, int whichFunction) +{ + GAParameterList params; + GASteadyStateGA::registerDefaultParameters(params); + params.set(gaNpopulationSize, 30); // population size + params.set(gaNpCrossover, 0.9); // probability of crossover + params.set(gaNpMutation, 0.001); // probability of mutation + params.set(gaNnGenerations, 400); // number of generations + params.set(gaNpReplacement, 0.25); // how much of pop to replace each gen + params.set(gaNscoreFrequency, 10); // how often to record scores + params.set(gaNflushFrequency, 50); // how often to dump scores to file + params.set(gaNscoreFilename, "bog.dat"); + + GABin2DecPhenotype map; + switch(whichFunction){ + case 0: + map.add(16, -5.12, 5.12); + map.add(16, -5.12, 5.12); + map.add(16, -5.12, 5.12); + break; + + case 1: + map.add(16, -2.048, 2.048); + map.add(16, -2.048, 2.048); + break; + + case 2: + map.add(16, -5.12, 5.12); + map.add(16, -5.12, 5.12); + map.add(16, -5.12, 5.12); + map.add(16, -5.12, 5.12); + map.add(16, -5.12, 5.12); + break; + + case 3: + { + for(int j=0; j<30; j++) + map.add(16, -1.28, 1.28); + } + break; + + case 4: + map.add(16, -65.536, 65.536); + map.add(16, -65.536, 65.536); + break; + + default: + map.add(16, 0, 0); + break; + } + + GABin2DecGenome genome(map, objective[whichFunction]); + GASteadyStateGA ga(genome); + ga.parameters(params); + GASigmaTruncationScaling scaling; + ga.scaling(scaling); + + ga.evolve(seed); + + return ga.statistics(); +} + +float DeJong1(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + float value=0; + value += genome.phenotype(0) * genome.phenotype(0); + value += genome.phenotype(1) * genome.phenotype(1); + value += genome.phenotype(2) * genome.phenotype(2); + return(value); +} + +float DeJong2(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + float value=100.0; + value *= genome.phenotype(0) * genome.phenotype(0) - genome.phenotype(1); + value *= genome.phenotype(0) * genome.phenotype(0) - genome.phenotype(1); + value += (1 - genome.phenotype(0))*(1 - genome.phenotype(0)); + return(value); +} + +float DeJong3(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + float value=25.0; + value -= floor(genome.phenotype(0)); + value -= floor(genome.phenotype(1)); + value -= floor(genome.phenotype(2)); + value -= floor(genome.phenotype(3)); + value -= floor(genome.phenotype(4)); + return(value); +} + +float DeJong4(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + float value = 0; + for(int i=0; i<30; i++){ + float v = genome.phenotype(i); + v *= v; // xi^2 + v *= v; // xi^4 + v *= i; + v += Gauss(0,1); + value += v; + } + return(value); +} + +float DeJong5(GAGenome & c) +{ + auto & genome = (GABin2DecGenome &)c; + + float prod,total=0.002; + + for(int j=0; j<25; j+=1) { + float lowtot=1.0 + (double)j; + for(int i=0; i<2; i+=1) { + prod=1.0; + for(int power=0; power<6; power+=1) + prod*=genome.phenotype(i)-a[i][j]; + lowtot+=prod; + } + total+=1.0/lowtot; + } + + return(500.0 - (1.0/total)); +} + +double Gauss(double mean, double variance){ + for(;;) { + double u1 = GARandomDouble(); + double u2 = GARandomDouble(); + double v1 = 2 * u1 - 1; + double v2 = 2 * u2 - 1; + double w = (v1 * v1) + (v2 * v2); + + if (w <= 1) { + double y = sqrt( (-2 * log(w)) / w); + double x1 = v1 * y; + return(x1 * sqrt(variance) + mean); + } + } +} diff --git a/examples/ex2.C b/examples/ex2.C index 4fc1b2ef..2717e6c1 100644 --- a/examples/ex2.C +++ b/examples/ex2.C @@ -14,7 +14,6 @@ objective function. #include "ex2.hpp" - int main(int argc, char **argv) { std::cout << "Example 2\n\n"; @@ -36,7 +35,7 @@ int main(int argc, char **argv) GARandomSeed(seed); - ex2(seed, false); // use dynamic values + example2(seed, false); // use dynamic values return 0; } diff --git a/examples/ex2.hpp b/examples/ex2.hpp index 40d8dd57..b4dfe4a0 100644 --- a/examples/ex2.hpp +++ b/examples/ex2.hpp @@ -26,7 +26,12 @@ float objectiveEx2(GAGenome &g) return value; } -GABin2DecGenome ex2(unsigned int seed, bool useStatic) +float objective(GAGenome &g) +{ + return objectiveEx2(g); +} + +GAStatistics example2(unsigned int seed, bool useStatic) { // 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 @@ -128,5 +133,5 @@ GABin2DecGenome ex2(unsigned int seed, bool useStatic) // std::cout << genome << "\n"; std::cout << "best of generation data are in 'bog.dat'\n"; - return genome; + return ga.statistics(); } diff --git a/examples/ex20.C b/examples/ex20.C index 631a9493..a2ddf318 100644 --- a/examples/ex20.C +++ b/examples/ex20.C @@ -13,7 +13,7 @@ example - not good programming style, but it gets the job done. #include #include #include - +#include "ex20.hpp" #include diff --git a/examples/ex20.hpp b/examples/ex20.hpp new file mode 100644 index 00000000..0634de9c --- /dev/null +++ b/examples/ex20.hpp @@ -0,0 +1,136 @@ +#pragma once + +#include +#include + +#define NBLOCKS 16 +const int BLOCKSIZE = 8; +const int GAPSIZE = 7; +const int MSTAR = 4; +const float USTAR = 1.0; +const float RR_U = 0.3; +const float RR_V = 0.02; + +int nbits = (BLOCKSIZE + GAPSIZE) * NBLOCKS; +int blockarray[NBLOCKS]; +int highestLevel = 0; + +float RoyalRoad(GAGenome &c) +{ + auto &genome = (GA1DBinaryStringGenome &)c; + + float score = 0.0; + int total, i, j, index, n; + + n = 0; + for (i = 0; i < NBLOCKS; i++) + { + total = 0; + for (j = i * (BLOCKSIZE + GAPSIZE); j < i * (BLOCKSIZE + GAPSIZE) + BLOCKSIZE; j++) + if (genome.gene(j) == 1) + total++; + if (total > MSTAR && total < BLOCKSIZE) + score -= (total - MSTAR) * RR_V; + else if (total <= MSTAR) + score += total * RR_V; + if (total == BLOCKSIZE) + { + blockarray[i] = 1; + n++; + } + else + { + blockarray[i] = 0; + } + } + + if (n > 0) + score += USTAR + (n - 1) * RR_U; + + n = NBLOCKS; + int proceed = 1; + int level = 0; + while ((n > 1) && proceed) + { + proceed = 0; + total = 0; + for (i = 0, index = 0; i < (n / 2) * 2; i += 2, index++) + { + if (blockarray[i] == 1 && blockarray[i + 1] == 1) + { + total++; + proceed = 1; + blockarray[index] = 1; + } + else + { + blockarray[index] = 0; + } + } + if (total > 0) + { + score += USTAR + (total - 1) * RR_U; + level++; + } + n /= 2; + } + + if (highestLevel < level) + highestLevel = level; + + return (score); +} + +float objective(GAGenome &c) +{ + return RoyalRoad(c); +} + +GAStatistics example20(unsigned int seed, int argc, char **argv) +{ + std::cout << "Example 20\n\n"; + std::cout << "Running Holland's Royal Road test problem with a genome that is\n"; + std::cout << nbits << " bits long (" << NBLOCKS << " blocks). The parameters "; + std::cout << "are as follows: \n\n"; + std::cout << "\tblock size: " << BLOCKSIZE << "\n"; + std::cout << "\t gap size: " << GAPSIZE << "\n"; + std::cout << "\t m*: " << MSTAR << "\n"; + std::cout << "\t u*: " << USTAR << "\n"; + std::cout << "\t u: " << RR_U << "\n"; + std::cout << "\t v: " << RR_V << "\n"; + std::cout << "\n\n"; + std::cout.flush(); + + for (int ii = 1; ii < argc; ii++) + { + if (strcmp(argv[ii++], "seed") == 0) + { + seed = atoi(argv[ii]); + } + } + + GA1DBinaryStringGenome genome(nbits, RoyalRoad); + GASteadyStateGA ga(genome); + ga.populationSize(512); + ga.pCrossover(0.9); + ga.pMutation(0.001); + ga.nGenerations(10000); + ga.scoreFilename("bog.dat"); + ga.flushFrequency(100); + ga.scoreFrequency(20); + ga.parameters(argc, argv); + GASigmaTruncationScaling trunc; + ga.scaling(trunc); + ga.evolve(seed); + + std::cout << "the ga generated:\n" + << ga.statistics().bestIndividual() << "\n"; + std::cout << "the highest level achieved was " << highestLevel << "\n"; + std::cout << "\nthe statistics for the run are:\n" + << ga.statistics(); + std::cout << "\nthe parameters for the run are:\n" + << ga.parameters(); + std::cout.flush(); + + return ga.statistics(); +} diff --git a/examples/ex21.C b/examples/ex21.C index 79950fbb..220956f1 100644 --- a/examples/ex21.C +++ b/examples/ex21.C @@ -13,212 +13,15 @@ create the array determines which behaviour you'll get. ---------------------------------------------------------------------------- */ #include #include - +#include "ex21.hpp" #include - - - #define INSTANTIATE_REAL_GENOME #include -float Objective1(GAGenome &); -float Objective2(GAGenome &); -float Objective3(GAGenome &); -float Objective4(GAGenome &); - -int -main(int argc, char** argv) +int main(int argc, char** argv) { - std::cout << "Example 21\n\n"; - std::cout << "This example shows various uses of the allele set object\n"; - std::cout << "in combination with the real number genome.\n\n"; std::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. - - unsigned int seed = 0; - for(int ii=1; ii genome.gene(i-1)) value += 1.0; - return value; -} - - -// This objective tries to maximize each element in the genome. - -float -Objective4(GAGenome& g) -{ - auto& genome = (GARealGenome&)g; - float value=0.0; - for(int i=0; i +#include +#include + +float objective(GAGenome &g) +{ + auto &genome = (GARealGenome &)g; + float score = 0.0; + for (int i = 0; i < genome.length(); i++) + { + score += genome.gene(i); + } + return score; +} + +GAStatistics example21(unsigned int seed, int argc, char **argv) +{ + GARealAlleleSetArray alleles; + alleles.add(0, 1); + alleles.add(0, 1); + alleles.add(0, 1); + alleles.add(0, 1); + alleles.add(0, 1); + + GARealGenome genome(alleles, objective); + + GASimpleGA ga(genome); + ga.populationSize(30); + ga.nGenerations(100); + ga.pMutation(0.01); + ga.pCrossover(0.6); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex22.C b/examples/ex22.C index 7db44222..2899f761 100644 --- a/examples/ex22.C +++ b/examples/ex22.C @@ -16,13 +16,9 @@ child crossover" you could use your own crossover algorithm instead. #include #include #include - - #include #include - - - +#include "ex22.hpp" #define OBJECTIVE Objective1 #define MIN_VALUE (-100) @@ -39,8 +35,6 @@ void Initializer(GAGenome&); float Comparator(const GAGenome&, const GAGenome&); int Crossover(const GAGenome&, const GAGenome&, GAGenome*); - - // Here we define our own genetic algorithm class. This class is almost the // same as the steady-state genetic algorithm, but we modify the step method // (the one that does all the work) so that we do a slightly modified @@ -100,120 +94,6 @@ SharedOverlapGA::step() stats.update(*pop); // update the statistics by one generation } - - - - - -int -main(int argc, char** argv) -{ - std::cout << "Example 22\n\n"; - std::cout << "This example shows how to derive your own genetic algorithm\n"; - std::cout << "class. Here we use a custom, single-child crossover and a\n"; - std::cout << "modified replacement strategy with overlapping populations.\n\n"; - std::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. - - unsigned int seed = 0; - for(int ii=1; ii genome(1, OBJECTIVE); - genome.initializer(::Initializer); - genome.mutator(::Mutator); - genome.comparator(::Comparator); - - GASharing share(Comparator); - - SharedOverlapGA ga(genome); - ga.crossover(Crossover); - ga.scaling(share); - ga.populationSize(100); - ga.pReplacement(0.25); - ga.nGenerations(500); - ga.pMutation(0.01); - ga.pCrossover(1.0); - ga.scoreFilename("bog.dat"); // name of file for scores - ga.scoreFrequency(10); // keep the scores of every 10th generation - ga.flushFrequency(100); // specify how often to write the score to disk - ga.selectScores(GAStatistics::AllScores); - ga.parameters(argc, argv, true); // parse commands, complain if bogus args - - std::cout << "initializing...\n"; std::cout.flush(); - ga.initialize(seed); - -// dump the initial population to file - - outfile.open(ifile, (std::ios::out | std::ios::trunc)); - for(i=0; i +#include +#include + +float objective(GAGenome &g) +{ + auto &genome = (GA1DArrayGenome &)g; + float v = genome.gene(0); + float y = 100.0 * exp(-fabs(v) / 50.0) * (1.0 - cos(v * M_PI * 2.0 / 25.0)); + if (v < -100 || v > 100) + y = 0; + if (y < 0) + y = 0; + return y + 0.00001; +} + +GAStatistics example22(unsigned int seed, int argc, char **argv) +{ + GA1DArrayGenome genome(1, objective); + genome.initializer(::Initializer); + genome.mutator(::Mutator); + genome.crossover(::Crossover); + + SharedOverlapGA ga(genome); + ga.populationSize(30); + ga.nGenerations(100); + ga.pMutation(0.01); + ga.pCrossover(0.6); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex23.C b/examples/ex23.C index fd1d8999..e3ad9b07 100644 --- a/examples/ex23.C +++ b/examples/ex23.C @@ -10,12 +10,10 @@ minimize your objective functions. #include #include #include - - #include #include - - +#include "ex23.hpp" + #define INSTANTIATE_REAL_GENOME #include @@ -26,87 +24,13 @@ minimize your objective functions. float Objective(GAGenome &); float Comparator(const GAGenome&, const GAGenome&); -int -main(int argc, char** argv) -{ - std::cout << "Example 23\n\n"; - std::cout << "This program tries to maximize or minimize, depending on the\n"; - std::cout << "command line argument that you give it. Use the command-line\n"; - std::cout << "argument 'mm -1' to minimize (the default for this example), or\n"; - std::cout << "'mm 1' to maximize. The objective function is a simple \n"; - std::cout << "sinusoidal.\n\n"; std::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 jj=1; jj +#include + +#define MIN_VALUE (-2) +#define MAX_VALUE 2 +#define INC 0.005 + +float objective(GAGenome &g) +{ + auto &genome = (GARealGenome &)g; + return 1 + sin(genome.gene(0) * 2 * M_PI); +} + +float comparator(const GAGenome &g1, const GAGenome &g2) +{ + auto &a = (GARealGenome &)g1; + auto &b = (GARealGenome &)g2; + return exp(-(a.gene(0) - b.gene(0)) * (a.gene(0) - b.gene(0)) / 1000.0); +} + +GAStatistics example23(unsigned int seed, int argc, char **argv) +{ + GARealAlleleSet alleles(MIN_VALUE, MAX_VALUE, INC); + GARealGenome genome(alleles, objective); + genome.comparator(comparator); + + GASimpleGA ga(genome); + ga.populationSize(30); + ga.nGenerations(100); + ga.pMutation(0.01); + ga.pCrossover(0.6); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex24.C b/examples/ex24.C index a1f82dd2..6de76f66 100644 --- a/examples/ex24.C +++ b/examples/ex24.C @@ -14,11 +14,9 @@ example). #include #include #include - - #include #include - +#include "ex24.hpp" #define INSTANTIATE_REAL_GENOME #include diff --git a/examples/ex24.hpp b/examples/ex24.hpp new file mode 100644 index 00000000..55d5de28 --- /dev/null +++ b/examples/ex24.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include +#include + +#define MIN_VALUE (-2) +#define MAX_VALUE 2 +#define INC 0.005 +#define THRESHOLD 0.5 + +float objective(GAGenome &g) +{ + auto &genome = (GARealGenome &)g; + return 1 + sin(genome.gene(0) * 2 * M_PI); +} + +float comparator(const GAGenome &g1, const GAGenome &g2) +{ + auto &a = (GARealGenome &)g1; + auto &b = (GARealGenome &)g2; + return exp(-(a.gene(0) - b.gene(0)) * (a.gene(0) - b.gene(0)) / 100.0); +} + +GAStatistics example24(unsigned int seed, int argc, char **argv) +{ + GARealAlleleSet alleles(MIN_VALUE, MAX_VALUE); + GARealGenome genome(1, alleles, objective); + GASharing scale(comparator); + FinickySelector select; + + RestrictedMatingGA ga(genome); + ga.selector(select); // use our selector instead of default + ga.scaling(scale); // set the scaling method to our sharing + ga.populationSize(50); // how many individuals in the population + ga.nGenerations(200); // number of generations to evolve + ga.pMutation(0.001); // likelihood of mutating new offspring + ga.pCrossover(0.9); // likelihood of crossing over parents + ga.scoreFilename("bog.dat"); // name of file for scores + ga.scoreFrequency(1); // keep the scores of every generation + ga.flushFrequency(50); // specify how often to write the score to disk + ga.selectScores(GAStatistics::AllScores); + ga.parameters("settings.txt"); // read parameters from settings file + ga.parameters(argc, argv, true); // parse commands, complain if bogus args + ga.evolve(seed); + + std::ofstream outfile; + + // dump the final population to file + std::cout << "printing population to file 'population.dat'..." << std::endl; + outfile.open("population.dat", (std::ios::out | std::ios::trunc)); + for (int i = 0; i < ga.population().size(); i++) + { + genome = ga.population().individual(i); + outfile << genome.gene(0) << "\t" << genome.score() << "\n"; + } + outfile.close(); + + // dump the function to file so you can plot the population on it + std::cout << "printing function to file 'sinusoid.dat'..." << std::endl; + outfile.open("sinusoid.dat", (std::ios::out | std::ios::trunc)); + for (float x = MIN_VALUE; x <= MAX_VALUE; x += INC) + { + outfile << genome.gene(0, x) << "\t" << genome.score() << "\n"; + } + outfile.close(); + + return ga.statistics(); +} diff --git a/examples/ex25.C b/examples/ex25.C index bd415894..d0c2878a 100644 --- a/examples/ex25.C +++ b/examples/ex25.C @@ -9,25 +9,16 @@ #include #include #include - - #include - - - +#include "ex25.hpp" float Objective(GAGenome &); -int -main(int argc, char** argv) { +int main(int argc, char** argv) { std::cout << "Example 25\n\n"; std::cout << "This example uses a genetic algorithm with multiple populations.\n"; std::cout << std::endl; -// 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 +#include +#include + +float objective(GAGenome &g) +{ + auto &genome = (GA1DBinaryStringGenome &)g; + float score = 0.0; + for (int i = 0; i < genome.length(); i++) + score += genome.gene(i); + score /= genome.length(); + return score; +} + +GAStatistics example25(unsigned int seed, int argc, char **argv) +{ + std::cout << "Example 25\n\n"; + std::cout << "This example uses a genetic algorithm with multiple populations.\n"; + std::cout << std::endl; + + GADemeGA ga; + GA1DBinaryStringGenome genome(100, objective); + ga.populationSize(50); + ga.nGenerations(200); + ga.pMutation(0.01); + ga.pCrossover(0.6); + ga.nPopulations(5); + ga.migrationFrequency(10); + ga.migrationSize(5); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex26.C b/examples/ex26.C index b041ad32..815c1ba2 100644 --- a/examples/ex26.C +++ b/examples/ex26.C @@ -22,15 +22,10 @@ it does get the job done. #include #include #include - +#include "ex26.hpp" #include #include - - - - - // Set this up for your favorite TSP. The sample one is a contrived problem // with the towns laid out in a grid (so it is easy to figure out what the @@ -64,87 +59,6 @@ int PMXover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); void ERXOneChild(const GAGenome&, const GAGenome&, GAGenome*); -int -main(int argc, char** argv) { - std::cout << "Example 26\n\n"; - std::cout << "The Travelling Salesman Problem (TSP) demo program.\n" << std::endl; - -// 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> dump; - in >> x[ntowns]; - in >> y[ntowns]; - ntowns++; - } while(!in.eof() && ntowns < MAX_TOWNS); - in.close(); - if(ntowns >= MAX_TOWNS) { - std::cerr << "data file contains more towns than allowed for in the fixed\n"; - std::cerr << "arrays. Recompile the program with larger arrays or try a\n"; - std::cerr << "smaller problem.\n"; - exit(1); - } - - double dx,dy; - for(int i=0;i genome(Objective); - genome.initializer(::Initializer); - genome.mutator(::Mutator); - genome.comparator(::Comparator); - genome.crossover(XOVER); - - GASteadyStateGA ga(genome); - ga.minimize(); - ga.pReplacement(1.0); - ga.populationSize(100); - ga.nGenerations(1000); - ga.pMutation(0.1); - ga.pCrossover(1.0); - ga.selectScores(GAStatistics::AllScores); - ga.parameters(argc, argv); - std::cout << "initializing..."; std::cout.flush(); - ga.initialize(seed); - std::cout << "evolving..."; std::cout.flush(); - while(!ga.done()) { - ga.step(); - if(ga.generation() % 10 == 0) { - std::cout << ga.generation() << " "; std::cout.flush(); - } - } - - genome = ga.statistics().bestIndividual(); - std::cout << "the shortest path found is " << genome.score() << "\n"; - std::cout << "this is the distance from the sequence\n"; - std::cout << genome << "\n\n"; - std::cout << ga.statistics() << "\n"; - - return 0; -} - - - diff --git a/examples/ex26.hpp b/examples/ex26.hpp new file mode 100644 index 00000000..10fab6b2 --- /dev/null +++ b/examples/ex26.hpp @@ -0,0 +1,50 @@ +#ifndef EX26_HPP +#define EX26_HPP + +#include +#include +#include + +#define MAX_TOWNS 50 +#define TSP_FILE "tsp_rect_20.txt" + +extern float DISTANCE[MAX_TOWNS][MAX_TOWNS]; +extern double x[MAX_TOWNS], y[MAX_TOWNS]; +extern int ntowns; + +float objective(GAGenome& g) { + auto & genome = (GAListGenome &)g; + float dist = 0; + if(genome.head()) { + for(int i=0; i& args) { + GARandomSeed(seed); + + GAListGenome genome(objective); + genome.initializer(Initializer); + genome.mutator(Mutator); + genome.crossover(XOVER); + + GASteadyStateGA ga(genome); + ga.populationSize(30); + ga.nGenerations(100); + ga.pMutation(0.01); + ga.pCrossover(0.9); + ga.scoreFilename("bog.dat"); + ga.scoreFrequency(10); + ga.flushFrequency(50); + ga.selectScores(GAStatistics::AllScores); + ga.evolve(); + + return ga.statistics(); +} + +#endif diff --git a/examples/ex27.C b/examples/ex27.C index 1641e796..626cf317 100644 --- a/examples/ex27.C +++ b/examples/ex27.C @@ -19,19 +19,8 @@ any standard 3D cross-platform API, so you get this instead.) #include #include #include - - #include - - - - - - - - - - +#include "ex27.hpp" // This is the class definition for the deterministic crowding genetic // algorithm. It is based upon the steady-state genetic algorithm, but we @@ -127,11 +116,6 @@ void DCrowdingGA::step() stats.update(*pop); } - - - - - // Set up the various 2-dimensional, real number functions that we will use. using Function = float (*)(float, float); @@ -148,8 +132,6 @@ static float maxx[] = { 6, 60, 500, 10 }; static float miny[] = {-6, -60, -500, -10 }; static float maxy[] = { 6, 60, 500, 10 }; - - // These are the declarations for our genome operators (we do not use the // defaults from GAlib for this example). float Objective(GAGenome&); @@ -158,94 +140,35 @@ void Initializer(GAGenome&); int Crossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); float Comparator(const GAGenome&, const GAGenome&); - -int -main(int argc, char** argv) { - std::cout << "Example 27\n\n"; - std::cout << "Deterministic crowding demonstration program.\n\n"; - std::cout << "In addition to the standard GAlib command-line arguments,\n"; - std::cout << "you can specify one of the four following functions:\n"; - std::cout << " 0 - modified Himmelblau's function\n"; - std::cout << " 1 - Foxholes (25)\n"; - std::cout << " 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96)\n"; - std::cout << " 3 - Mexican Hat (optimum at 0,0)\n"; - std::cout << std::endl; - - int i; - -// 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(i=1; i genome(2, Objective); - genome.initializer(::Initializer); - genome.mutator(::Mutator); - genome.comparator(::Comparator); - genome.crossover(::Crossover); - - DCrowdingGA ga(genome); - ga.maximize(); - ga.populationSize(100); - ga.nGenerations(100); - ga.pMutation(0.05); - ga.pCrossover(1.0); - ga.selectScores(GAStatistics::AllScores); - ga.parameters(argc, argv, false); - - for (i=1; i= argc){ - std::cerr << argv[0] << ": the function option needs a number.\n"; - exit(1); - } - else{ - which = atoi(argv[i]); - continue; - } - } - else if(strcmp("seed", argv[i]) == 0){ - if(++i < argc) continue; - continue; - } - else { - std::cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; - std::cerr << "valid arguments include standard GAlib arguments plus:\n"; - std::cerr << " f\tfunction to use (" << which << ")\n"; - std::cerr << "\n"; - exit(1); +GAStatistics example27(GAParameterList params, unsigned int seed) +{ + for (int i = 0; i < 25; i++) { + ai[i] = 16 * ((i % 5) - 2); + bi[i] = 16 * ((i / 5) - 2); } - } - ga.evolve(); - std::cout << "best individual is " << ga.statistics().bestIndividual() << "\n\n"; - std::cout << ga.statistics() << "\n"; - - return 0; + GA1DArrayGenome genome(2, Objective); + genome.initializer(::Initializer); + genome.mutator(::Mutator); + genome.comparator(::Comparator); + genome.crossover(::Crossover); + + DCrowdingGA ga(genome); + ga.maximize(); + ga.populationSize(100); + ga.nGenerations(100); + ga.pMutation(0.05); + ga.pCrossover(1.0); + ga.selectScores(GAStatistics::AllScores); + ga.parameters(params); + + ga.evolve(seed); + std::cout << "best individual is " << ga.statistics().bestIndividual() << "\n\n"; + std::cout << ga.statistics() << "\n"; + + return ga.statistics(); } - - - - - - - - - - - - - /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_1 */ @@ -262,7 +185,6 @@ Function1(float x, float y) { return z; } - /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_2 */ @@ -284,7 +206,6 @@ Function2(float x, float y) { return z; } - /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_3 */ @@ -300,7 +221,6 @@ Function3(float x, float y) { return (z); } - /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_4 */ @@ -317,18 +237,6 @@ Function4(float x, float y) { return (z); } - - - - - - - - - - - - // These are the operators that we'll use for the real number genome. float Objective(GAGenome& g) { diff --git a/examples/ex27.hpp b/examples/ex27.hpp new file mode 100644 index 00000000..af1fb1f9 --- /dev/null +++ b/examples/ex27.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include +#include +#include +#include +#include + +float Function1(float, float); +float Function2(float, float); +float Function3(float, float); +float Function4(float, float); +float ai[25], bi[25]; + +static int which = 0; +static float minx[] = {-6, -60, -500, -10 }; +static float maxx[] = { 6, 60, 500, 10 }; +static float miny[] = {-6, -60, -500, -10 }; +static float maxy[] = { 6, 60, 500, 10 }; + +float objective(GAGenome& g) { + auto& genome = (GA1DArrayGenome&)g; + return (obj[which])(genome.gene(0), genome.gene(1)); +} + +void initializer(GAGenome& g) { + auto& genome = (GA1DArrayGenome&)g; + genome.gene(0, GARandomFloat(minx[which], maxx[which])); + genome.gene(1, GARandomFloat(miny[which], maxy[which])); +} + +int mutator(GAGenome& g, float pmut) { + auto& genome = (GA1DArrayGenome&)g; + int nmut = 0; + + if(GAFlipCoin(pmut)){ + genome.gene(0, genome.gene(0) + + 10*GARandomFloat() * (GARandomFloat() - GARandomFloat())); + genome.gene(1, genome.gene(1) + + 10*GARandomFloat() * (GARandomFloat() - GARandomFloat())); + nmut++; + } + + if(genome.gene(0) < minx[which]) genome.gene(0, minx[which]); + if(genome.gene(0) > maxx[which]) genome.gene(0, maxx[which]); + if(genome.gene(1) < minx[which]) genome.gene(1, minx[which]); + if(genome.gene(1) > maxx[which]) genome.gene(1, maxx[which]); + + return nmut; +} + +int crossover(const GAGenome& g1,const GAGenome& g2,GAGenome* c1,GAGenome* c2) +{ + auto& mom = (GA1DArrayGenome&)g1; + auto& dad = (GA1DArrayGenome&)g2; + + int n = 0; + float distance = 0.0, midpoint = 0.0; + + if(c1) + { + auto& sis = (GA1DArrayGenome&)*c1; + distance = midpoint = 0.0; + + midpoint = (mom.gene(0) + dad.gene(0)) / 2; + distance = fabs(mom.gene(0) - dad.gene(0)); + sis.gene(0, midpoint + distance * (GARandomFloat() - GARandomFloat())); + + midpoint = (mom.gene(1) + dad.gene(1)) / 2; + distance = fabs(mom.gene(1) - dad.gene(1)); + sis.gene(1, midpoint + distance * (GARandomFloat() - GARandomFloat())); + + if(sis.gene(0) < minx[which]) sis.gene(0, minx[which]); + if(sis.gene(0) > maxx[which]) sis.gene(0, maxx[which]); + if(sis.gene(1) < minx[which]) sis.gene(1, minx[which]); + if(sis.gene(1) > maxx[which]) sis.gene(1, maxx[which]); + + n += 1; + } + if(c2) { + auto& bro = (GA1DArrayGenome&)*c2; + distance = midpoint = 0.0; + + midpoint = (mom.gene(0) + dad.gene(0)) / 2; + distance = fabs(mom.gene(0) - dad.gene(0)); + bro.gene(0, midpoint + distance * (GARandomFloat() - GARandomFloat())); + + midpoint = (mom.gene(1) + dad.gene(1)) / 2; + distance = fabs(mom.gene(1) - dad.gene(1)); + bro.gene(1, midpoint + distance * (GARandomFloat() - GARandomFloat())); + + if(bro.gene(0) < minx[which]) bro.gene(0, minx[which]); + if(bro.gene(0) > maxx[which]) bro.gene(0, maxx[which]); + if(bro.gene(1) < minx[which]) bro.gene(1, minx[which]); + if(bro.gene(1) > maxx[which]) bro.gene(1, maxx[which]); + + n += 1; + } + + return n; +} + +float comparator(const GAGenome& g1, const GAGenome& g2) { + auto& a = (GA1DArrayGenome&)g1; + auto& b = (GA1DArrayGenome&)g2; + + float valx=(a.gene(0)-b.gene(0)) * (a.gene(0)-b.gene(0)); + float valy=(a.gene(1)-b.gene(1)) * (a.gene(1)-b.gene(1)); + return sqrt(valx+valy); +} + +GAStatistics example27(unsigned int seed, int argc, char **argv) +{ + for (int i = 0; i < 25; i++) { + ai[i] = 16 * ((i % 5) - 2); + bi[i] = 16 * ((i / 5) - 2); + } + + GA1DArrayGenome genome(2, objective); + genome.initializer(::initializer); + genome.mutator(::mutator); + genome.comparator(::comparator); + genome.crossover(::crossover); + + DCrowdingGA ga(genome); + ga.maximize(); + ga.populationSize(100); + ga.nGenerations(100); + ga.pMutation(0.05); + ga.pCrossover(1.0); + ga.selectScores(GAStatistics::AllScores); + ga.parameters(argc, argv, true); + + ga.evolve(seed); + std::cout << "best individual is " << ga.statistics().bestIndividual() << "\n\n"; + std::cout << ga.statistics() << "\n"; + + return ga.statistics(); +} diff --git a/examples/ex3.C b/examples/ex3.C index 3915cb5a..330ff1f4 100644 --- a/examples/ex3.C +++ b/examples/ex3.C @@ -1,25 +1,5 @@ -/* ---------------------------------------------------------------------------- - ex3.C - mbwall 28jul94 - Copyright (c) 1995-1996 Massachusetts Institute of Technology - - DESCRIPTION: - Example program for the SimpleGA class and 2DBinaryStringGenome class. -This program reads in a 2D pattern from a data file then tries to match the -pattern in a 2D binary string genome. We use a simple GA (with linear -scaled fitness selection and non-steady-state population generation) and -2D binary string genomes. - This example also illustrates the use of the GAParameterList for setting -default parameters on the genetic algorithm and for parsing the command line. ----------------------------------------------------------------------------- */ -#include -#include - #include "ex3.hpp" -#include - - int main(int argc, char *argv[]) { std::cout << "Example 3\n\n"; @@ -97,4 +77,3 @@ int main(int argc, char *argv[]) return 0; } - diff --git a/examples/ex3.hpp b/examples/ex3.hpp index e29756d6..1b001c9e 100644 --- a/examples/ex3.hpp +++ b/examples/ex3.hpp @@ -10,7 +10,7 @@ // For the objective function we compare the contents of the genome with the // target. If a bit is set in the genome and it is also set in the target, // then we add 1 to the score. If the bits do not match, we don't do anything. -float objectiveEx3(GAGenome& c) +float objective(GAGenome& c) { auto& genome = (GA2DBinaryStringGenome&)c; auto** pattern = (short**)c.userData(); @@ -22,7 +22,7 @@ float objectiveEx3(GAGenome& c) return (value); } -GASimpleGA ex3(GAParameterList params, const std::string& filename) +GAStatistics example3(GAParameterList params, const std::string& filename) { // 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 @@ -61,7 +61,7 @@ GASimpleGA ex3(GAParameterList params, const std::string& filename) // Now create the GA and run it. - GA2DBinaryStringGenome genome(width, height, objectiveEx3, (void*)target); + GA2DBinaryStringGenome genome(width, height, objective, (void*)target); GASimpleGA ga(genome); ga.parameters(params); ga.evolve(); @@ -82,5 +82,5 @@ GASimpleGA ex3(GAParameterList params, const std::string& filename) delete target[i]; delete[] target; - return ga; + return ga.statistics(); } diff --git a/examples/ex4.C b/examples/ex4.C index 0d5e6193..7ffea821 100644 --- a/examples/ex4.C +++ b/examples/ex4.C @@ -1,21 +1,3 @@ -/* ---------------------------------------------------------------------------- - ex4.C - mbwall 28jul94 - Copyright (c) 1995-1996 Massachusetts Institute of Technology - - DESCRIPTION: - Example program for the SteadyStateGA class and 3DBinaryStringGenome - class. This program tries to fill the 3Dgenome with alternating 1's and - 0's. Notice that the steady state ga needs many more 'generations' than the - simple ga, but it will usually converge to the optimum with fewer evaluations - of the objective function. So if you have a compute-intensive objective - function, steady state ga may be the way to go. - You can control the amount of overlap in a steady-state GA by using the - pReplacement member function. - This example also illustrates some of the statistics members of the genetic - algorithm object. ----------------------------------------------------------------------------- */ - #include "ex4.hpp" #include @@ -31,15 +13,16 @@ int main(int argc, char **argv) // 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) { - GARandomSeed((unsigned int)atoi(argv[ii])); + seed = (unsigned int)atoi(argv[ii]); } } - ex4(); + example4(seed); return 0; } diff --git a/examples/ex4.hpp b/examples/ex4.hpp index 88f8b4d7..fcd979c1 100644 --- a/examples/ex4.hpp +++ b/examples/ex4.hpp @@ -31,7 +31,12 @@ float objectiveEx4(GAGenome& g) return value; } -GASteadyStateGA ex4() +float objective(GAGenome& g) +{ + return objectiveEx4(g); +} + +GAStatistics example4(unsigned int seed) { int depth = 3; int width = 10; @@ -60,11 +65,11 @@ GASteadyStateGA ex4() ga.scoreFrequency(10); // keep the scores of every 10th generation ga.flushFrequency(50); // specify how often to write the score to disk ga.selectScores(GAStatistics::AllScores); - ga.evolve(); + ga.evolve(seed); // Now we print out the best genome. std::cout << "the ga generated:\n" << ga.statistics().bestIndividual() << "\n"; std::cout << "best of generation data are in 'bog.dat'\n"; - return ga; + return ga.statistics(); } diff --git a/examples/ex6.C b/examples/ex6.C index d134fc7a..267eafc4 100644 --- a/examples/ex6.C +++ b/examples/ex6.C @@ -1,23 +1,6 @@ -/* ---------------------------------------------------------------------------- - ex6.C - mbwall 14jan95 - Copyright 1995-1996 Massachusetts Institute of Technology - - DESCRIPTION: - Example program for the tree and list genomes. This example contains -the code to run a tree genome. The list genome is almost the same - -just change tree to list and modify the initialization methods. - This program illustrates how to specialize member functions of the -template classes. Here we specialize the default write() method so that we get -the contents of the nodes rather than the pointers to the node contents. You -can specialize most functions of a template class (as long as they are not -inlined). ----------------------------------------------------------------------------- */ - #include "ex6.hpp" - -int main(int argc, char *argv[]) +GAStatistics example6(GAParameterList params, unsigned int seed) { std::cout << "Example 6\n\n"; std::cout << "This example uses a SteadyState GA and Tree genome. It\n"; @@ -28,18 +11,8 @@ int main(int argc, char *argv[]) // 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 i = 1; i < argc; i++) - { - if (strcmp(argv[i++], "seed") == 0) - { - seed = atoi(argv[i]); - } - } // Set the default values of the parameters. - GAParameterList params; - GASteadyStateGA::registerDefaultParameters(params); params.set(gaNpopulationSize, 30); params.set(gaNpCrossover, 0.7); params.set(gaNpMutation, 0.01); @@ -47,9 +20,6 @@ int main(int argc, char *argv[]) params.set(gaNscoreFilename, "bog.dat"); params.set(gaNscoreFrequency, 10); // record score every 10th generation params.set(gaNflushFrequency, 10); // dump scores every 10th recorded score - params.parse(argc, argv, false); // Parse the command line for GAlib args. - - ex6(params, seed); - return 0; + return ex6(params, seed); } diff --git a/examples/ex6.hpp b/examples/ex6.hpp index bd988014..f28936cb 100644 --- a/examples/ex6.hpp +++ b/examples/ex6.hpp @@ -145,4 +145,22 @@ GATreeGenome ex6(GAParameterList params, unsigned int seed) std::cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; return genome; -} \ No newline at end of file +} + +float objective(GAGenome &c) +{ + return objectiveEx6(c); +} + +GAStatistics example6(GAParameterList params, unsigned int seed) +{ + GATreeGenome genome(objective); + genome.initializer(TreeInitializer); + genome.mutator(GATreeGenome::SwapSubtreeMutator); + + GASteadyStateGA ga(genome); + ga.parameters(params); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex7.C b/examples/ex7.C index ee76a1f9..418047c0 100644 --- a/examples/ex7.C +++ b/examples/ex7.C @@ -1,115 +1,121 @@ -/* ---------------------------------------------------------------------------- - 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 -#include -#include - #include "ex7.hpp" -#include -#include -#include - - -int main(int argc, char *argv[]) +GAStatistics example7(GAParameterList params, const std::string &datafile) { std::cout << "Example 7\n\n"; std::cout << "This program reads in a data file then runs a steady-state GA \n"; std::cout << "whose objective function tries to match the pattern of bits that\n"; std::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++) + // 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) + std::ifstream inStream(datafile); + if (!inStream) + { + std::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. + + std::cout << "input pattern:\n"; + for (int j = 0; j < height; j++) { - if (strcmp(argv[ii++], "seed") == 0) - { - GARandomSeed((unsigned int)atoi(argv[ii])); - } + for (int i = 0; i < width; i++) + std::cout << (target.gene(i, j) == 1 ? '*' : ' ') << " "; + std::cout << "\n"; } + std::cout << "\n"; + std::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, objectiveEx7, (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. - // Set the default values of the parameters. - 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, false); - - std::string datafile = "smiley.txt"; - std::string parmfile = ""; - - // 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 (int i = 1; i < argc; i++) + genome = ga.statistics().bestIndividual(); + std::cout << "the ga generated:\n"; + for (int j = 0; j < height; j++) { - if (strcmp("dfile", argv[i]) == 0) - { - if (++i >= argc) - { - std::cerr << argv[0] << ": the data file option needs a filename.\n"; - exit(1); - } - else - { - std::ostringstream str; - str << argv[i]; - datafile = str.str(); - continue; - } - } - else if (strcmp("pfile", argv[i]) == 0) - { - if (++i >= argc) - { - std::cerr << argv[0] << ": the parameters file option needs a filename.\n"; - exit(1); - } - else - { - std::ostringstream str; - str << argv[i]; - parmfile = str.str(); - params.read(parmfile); - continue; - } - } - else if (strcmp("seed", argv[i]) == 0) - { - if (++i < argc) - continue; - continue; - } - else - { - std::cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; - std::cerr << "valid arguements include GAlib arguments plus:\n"; - std::cerr << " dfile\tdata file from which to read (" << datafile << ")\n"; - std::cerr << " pfile\tparameters file (" << parmfile << ")\n\n"; - std::cerr << "default parameters are:\n" << params << "\n\n"; - exit(1); - } + for (int i = 0; i < width; i++) + std::cout << (genome.gene(i, j) == 1 ? '*' : ' ') << " "; + std::cout << "\n"; } + std::cout << "\n"; + std::cout.flush(); - ex7(params, datafile); + std::cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; - return 0; + return ga.statistics(); } diff --git a/examples/ex7.hpp b/examples/ex7.hpp index e7214a90..9de60c56 100644 --- a/examples/ex7.hpp +++ b/examples/ex7.hpp @@ -21,8 +21,18 @@ float objectiveEx7(GAGenome& c) return (value); } -GASteadyStateGA ex7(GAParameterList params, const std::string &datafile) +float objective(GAGenome& c) { + return objectiveEx7(c); +} + +GAStatistics example7(GAParameterList params, const std::string &datafile) +{ + std::cout << "Example 7\n\n"; + std::cout << "This program reads in a data file then runs a steady-state GA \n"; + std::cout << "whose objective function tries to match the pattern of bits that\n"; + std::cout << "are in the data file.\n\n"; + // 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). @@ -133,5 +143,5 @@ GASteadyStateGA ex7(GAParameterList params, const std::string &datafile) std::cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; - return ga; + return ga.statistics(); } diff --git a/examples/ex8.C b/examples/ex8.C index a85dba29..69464888 100644 --- a/examples/ex8.C +++ b/examples/ex8.C @@ -1,24 +1,5 @@ -/* ---------------------------------------------------------------------------- - ex8.C - mbwall 14jan95 - Copyright 1995-1996 Massachusetts Institute of Technology - - DESCRIPTION: - Example program for the list genome. This example contains -the code to run a genetic algorithm with a list genome. - This program illustrates how to specialize member functions of the -template classes. Here we specialize the default write() method so that we get -the contents of the nodes rather than the pointers to the node contents. You -can specialize most functions of a template class (as long as they are not -inlined). - The objective function for this example returns both positive and negative -values, depending on the genome it is evaluting. So the example also shows how -to use the sigma truncation scaling method to handle the mixed scores. ----------------------------------------------------------------------------- */ - #include "ex8.hpp" - int main(int argc, char *argv[]) { std::cout << "Example 8\n\n"; @@ -37,7 +18,7 @@ int main(int argc, char *argv[]) GARandomSeed((unsigned int)atoi(argv[i])); } - ex8(); + example8(0); return 0; } diff --git a/examples/ex8.hpp b/examples/ex8.hpp index 54a003a8..b890ae7c 100644 --- a/examples/ex8.hpp +++ b/examples/ex8.hpp @@ -119,4 +119,30 @@ GAListGenome ex8() std::cout << "the ga used the parameters:\n" << ga.parameters() << "\n"; return genome; -} \ No newline at end of file +} + +float objective(GAGenome &c) +{ + return objectiveEx8(c); +} + +GAStatistics example8(unsigned int seed) +{ + GAListGenome genome(objective); + genome.initializer(ListInitializer); + genome.mutator(GAListGenome::DestructiveMutator); + + GASteadyStateGA ga(genome); + ga.set(gaNpopulationSize, 40); // population size + ga.set(gaNpCrossover, 0.6); // probability of crossover + ga.set(gaNpMutation, 0.05); // probability of mutation + ga.set(gaNnGenerations, 50); // number of generations + ga.set(gaNscoreFrequency, 1); // how often to record scores + ga.set(gaNflushFrequency, 10); // how often to dump scores to file + ga.set(gaNselectScores, // which scores should we track? + GAStatistics::Maximum | GAStatistics::Minimum | GAStatistics::Mean); + ga.set(gaNscoreFilename, "bog.dat"); + ga.evolve(seed); + + return ga.statistics(); +} diff --git a/examples/ex9.C b/examples/ex9.C index 4bc80509..bb3777b9 100644 --- a/examples/ex9.C +++ b/examples/ex9.C @@ -1,21 +1,5 @@ -/* ---------------------------------------------------------------------------- - ex9.C - mbwall 10apr95 - Copyright 1995-1996 Massachusetts Institute of Technology - - DESCRIPTION: - Sample program that illustrates how to use a GA to find the maximum value -of a continuous function in two variables. This program uses a binary-to- -decimal genome. ----------------------------------------------------------------------------- */ -#include -#include - #include "ex9.hpp" -#include - - int main(int argc, char **argv) { std::cout << "Example 9\n\n"; @@ -40,7 +24,7 @@ int main(int argc, char **argv) } } - ex9(seed); + example9(seed); return 0; } diff --git a/examples/ex9.hpp b/examples/ex9.hpp index 22e39852..6150ac31 100644 --- a/examples/ex9.hpp +++ b/examples/ex9.hpp @@ -10,7 +10,7 @@ // // y = -(x1*x1 + x2*x2) // -float objectiveEx9(GAGenome& c) +float objective(GAGenome& c) { auto& genome = (GABin2DecGenome&)c; @@ -20,7 +20,7 @@ float objectiveEx9(GAGenome& c) return y; } -GABin2DecGenome ex9(unsigned int seed) +GAStatistics example9(unsigned int seed) { // Create a phenotype for two variables. The number of bits you can use to // represent any number is limited by the type of computer you are using. In @@ -32,7 +32,7 @@ GABin2DecGenome ex9(unsigned int seed) map.add(16, -5, 5); // Create the template genome using the phenotype map we just made. - GABin2DecGenome genome(map, objectiveEx9); + GABin2DecGenome genome(map, objective); // Now create the GA using the genome and run it. We'll use sigma // truncation scaling so that we can handle negative objective scores. @@ -54,5 +54,5 @@ GABin2DecGenome ex9(unsigned int seed) std::cout << genome.phenotype(0) << ", " << genome.phenotype(1) << ")\n\n"; std::cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; - return genome; -} \ No newline at end of file + return ga.statistics(); +} diff --git a/test/GAExamplesTest.cpp b/test/GAExamplesTest.cpp index 994a5006..b2929200 100644 --- a/test/GAExamplesTest.cpp +++ b/test/GAExamplesTest.cpp @@ -17,24 +17,24 @@ BOOST_AUTO_TEST_SUITE(UnitTest) BOOST_AUTO_TEST_CASE(GAex1) { - auto ga = ex1(); + auto ga = example1(0, true); std::stringstream str; - str << ga.statistics().bestIndividual(); + str << ga.bestIndividual(); BOOST_CHECK_EQUAL(str.str(), "0101010101\n1010101010\n0101010101\n1010101010\n0101010101\n"); } BOOST_AUTO_TEST_CASE(GAex2) { - auto genome = ex2(101, true); // use static seed - - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(0), 0.0980392173, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(1), 21.9607849, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(2), 3, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(3), -3.52941179, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(4), 34575.293, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(5), 0.00152941176, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(6), 6.56078434, 0.0000001); + auto ga = example2(0, true); + + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(0), 0.0980392173, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(1), 21.9607849, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(2), 3, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(3), -3.52941179, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(4), 34575.293, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(5), 0.00152941176, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(6), 6.56078434, 0.0000001); } BOOST_AUTO_TEST_CASE(GAex3) @@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(GAex3) BOOST_REQUIRE(params.set(gaNflushFrequency, 50)); BOOST_REQUIRE(params.set(gaNscoreFilename, "bog.dat")); - auto ga = ex3(params, "smiley.txt"); + auto ga = example3(params, "smiley.txt"); // TODO older MSVC versions somehow differed; maybe seed is different //#ifdef _WIN32 @@ -61,10 +61,10 @@ BOOST_AUTO_TEST_CASE(GAex3) BOOST_AUTO_TEST_CASE(GAex4) { - auto ga = ex4(); + auto ga = example4(0, true); std::stringstream str; - str << ga.statistics().bestIndividual(); + str << ga.bestIndividual(); BOOST_CHECK_EQUAL( str.str(), "0101010101\n1010101010\n0101010101\n1010101010\n0101010101\n\n" @@ -75,46 +75,15 @@ BOOST_AUTO_TEST_CASE(GAex4) BOOST_AUTO_TEST_CASE(GAex6) { - // Set the default values of the parameters. - GAParameterList params; - GASteadyStateGA::registerDefaultParameters(params); - BOOST_REQUIRE(params.set(gaNpopulationSize, 30)); // number of individuals in population - BOOST_REQUIRE(params.set(gaNpCrossover, 0.7)); // likelihood of doing crossover - BOOST_REQUIRE(params.set(gaNpMutation, 0.001)); // probability of mutation - BOOST_REQUIRE(params.set(gaNnGenerations, 100)); // number of generations - BOOST_REQUIRE(params.set(gaNscoreFrequency, 10)); // how often to record scores - BOOST_REQUIRE(params.set(gaNflushFrequency, 10)); // how often to flush scores to file - BOOST_REQUIRE(params.set(gaNscoreFilename, "bog.dat")); - - auto genome = ex6(params, 0); - + auto ga = example6(0, true); - // older MSVC versions somehow differed; maybe seed is different -//#ifdef _WIN32 -// BOOST_CHECK_EQUAL(genome.size(), 6613); -// BOOST_CHECK_EQUAL(genome.depth(), 73); -//#else - BOOST_CHECK_EQUAL(genome.size(), 10557); - BOOST_CHECK_EQUAL(genome.depth(), 310); -//#endif + BOOST_CHECK_EQUAL(ga.bestIndividual().size(), 10557); + BOOST_CHECK_EQUAL(ga.bestIndividual().depth(), 310); } BOOST_AUTO_TEST_CASE(GAex7) { - GARandomSeed(100); // so test is always the same - - // Set the default values of the parameters. - GAParameterList params; - GASteadyStateGA::registerDefaultParameters(params); - BOOST_REQUIRE(params.set(gaNpopulationSize, 50)); // number of individuals in population - BOOST_REQUIRE(params.set(gaNpCrossover, 0.8)); // likelihood of doing crossover - BOOST_REQUIRE(params.set(gaNpMutation, 0.001)); // probability of mutation - BOOST_REQUIRE(params.set(gaNnGenerations, 200)); // number of generations - BOOST_REQUIRE(params.set(gaNscoreFrequency, 20)); // how often to record scores - BOOST_REQUIRE(params.set(gaNflushFrequency, 50)); // how often to flush scores to file - BOOST_REQUIRE(params.set(gaNscoreFilename, "bog.dat")); - - auto ga = ex7(params, "smiley.txt"); + auto ga = example7(0, true); BOOST_CHECK_EQUAL(ga.statistics().maxEver(), 217); BOOST_CHECK_EQUAL(ga.statistics().minEver(), 97); @@ -123,26 +92,17 @@ BOOST_AUTO_TEST_CASE(GAex7) BOOST_AUTO_TEST_CASE(GAex8) { -// GARandomSeed(103); + auto ga = example8(0, true); - auto genome = ex8(); - - BOOST_CHECK_EQUAL(genome.size(), 413); + BOOST_CHECK_EQUAL(ga.bestIndividual().size(), 413); } - BOOST_AUTO_TEST_CASE(GAex9) { - auto genome = ex9(100); // use static seed + auto ga = example9(0, true); - // TODO older MSVC versions somehow differed; maybe seed is different -//#ifdef _WIN32 -// BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(0), -0.000228881836, 0.0000001); -// BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(1), 7.62939453e-05, 0.0000001); -//#else - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(0), -7.62939453e-05, 0.0000001); - BOOST_CHECK_CLOSE_FRACTION(genome.phenotype(1), -7.62939453e-05, 0.0000001); -//#endif + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(0), -7.62939453e-05, 0.0000001); + BOOST_CHECK_CLOSE_FRACTION(ga.bestIndividual().phenotype(1), -7.62939453e-05, 0.0000001); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END()