📄 ex14.c
字号:
/* ----------------------------------------------------------------------------
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 <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <fstream.h>
#include <ga/ga.h>
// 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 nrobots, int pathlength);
RobotPathGenome(const RobotPathGenome & orig) { n=l=0; list=0; copy(orig); }
RobotPathGenome operator=(const GAGenome & arg) { copy(arg); return *this; }
virtual ~RobotPathGenome();
virtual GAGenome *clone(GAGenome::CloneMethod) const ;
virtual void copy(const GAGenome & c);
virtual int equal(const GAGenome& g) const;
virtual int read(istream & is);
virtual int write(ostream & os) const ;
GAListGenome<int> & path(const int i){return *list[i];}
int npaths() const { return n; }
int length() const { return l; }
protected:
int n, l;
GAListGenome<int> **list;
};
RobotPathGenome::RobotPathGenome(int nrobots, int pathlength) :
GAGenome(Initializer, Mutator, Comparator){
evaluator(Evaluator); crossover(Crossover); n = nrobots; l = pathlength;
list = (n ? new GAListGenome<int> * [n] : (GAListGenome<int> **)0);
for(int i=0; i<n; i++){
list[i] = new GAListGenome<int>;
list[i]->initializer(PathInitializer);
list[i]->mutator(GAListGenome<int>::SwapMutator);
}
}
void
RobotPathGenome::copy(const GAGenome& g) {
if(&g != this && sameClass(g)){
GAGenome::copy(g); // copy the base class part
RobotPathGenome & 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<int> * [n];
for(i=0; i<n; i++)
list[i] = (GAListGenome<int> *)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);
}
int
RobotPathGenome::equal(const GAGenome& g) const {
RobotPathGenome& genome = (RobotPathGenome&)g;
int flag=0;
for(int i=0; i<n && flag==0; i++)
flag = list[i]->equal(*genome.list[i]);
return flag;
}
int
RobotPathGenome::read(istream & is) {
for(int i=0; i<n; i++)
is >> *(list[i]);
return is.fail() ? 1 : 0;
}
int
RobotPathGenome::write(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) {
RobotPathGenome & genome = (RobotPathGenome &)g;
for(int i=0; i<genome.npaths(); i++)
genome.path(i).initialize();
genome._evaluated = gaFalse;
}
int
RobotPathGenome::Mutator(GAGenome& g, float pmut) {
RobotPathGenome & genome = (RobotPathGenome &)g;
int nMut = 0;
for(int i=0; i<genome.npaths(); i++)
nMut += genome.path(i).mutate(pmut);
if(nMut) genome._evaluated = gaFalse;
return nMut;
}
float
RobotPathGenome::Comparator(const GAGenome& a, const GAGenome& b) {
RobotPathGenome& sis = (RobotPathGenome &)a;
RobotPathGenome& 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) {
RobotPathGenome & 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) {
RobotPathGenome& mom = (RobotPathGenome &)a;
RobotPathGenome& dad = (RobotPathGenome &)b;
int n=0;
if(c && d){
RobotPathGenome& sis = (RobotPathGenome &)*c;
RobotPathGenome& bro = (RobotPathGenome &)*d;
for(int i=0; i<mom.npaths(); i++)
GAListGenome<int>::PartialMatchCrossover(mom.path(i), dad.path(i),
&sis.path(i), &bro.path(i));
sis._evaluated = gaFalse;
bro._evaluated = gaFalse;
n=2;
}
else if(c) {
RobotPathGenome& sis = (RobotPathGenome &)*c;
for(int i=0; i<mom.npaths(); i++)
GAListGenome<int>::PartialMatchCrossover(mom.path(i), dad.path(i),
&sis.path(i), 0);
sis._evaluated = gaFalse;
n=1;
}
else if(d) {
RobotPathGenome& bro = (RobotPathGenome &)*d;
for(int i=0; i<mom.npaths(); i++)
GAListGenome<int>::PartialMatchCrossover(mom.path(i), dad.path(i),
0, &bro.path(i));
bro._evaluated = gaFalse;
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){
GAListGenome<int> & list = (GAListGenome<int> &)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.
int
GAListGenome<int>::write(ostream & os) const {
int *cur, *head;
GAListIter<int> iter(*this);
if((head=iter.head()) != 0) os << *head << " ";
for(cur=iter.next(); cur && cur != head; cur=iter.next())
os << *cur << " ";
return os.fail() ? 1 : 0;
}
int
main(int argc, char *argv[])
{
cout << "Example 14\n\n";
cout << "This example shows how to create a genome that contains\n";
cout << "a list of lists. We create a composite genome that has\n";
cout << "lists in it. Each list has some nodes, only one of which\n";
cout << "contains the number 0. The objective is to move the node with\n";
cout << "number 0 in it to the nth position where n is the number of the\n";
cout << "list within the composite genome.\n\n";
cout.flush();
// See if we've been given a seed to use (for testing purposes). When you
// specify a random seed, the evolution will be exactly the same each time
// you use that seed number.
int i;
for(i=1; i<argc; i++){
if(strcmp("nr", argv[i]) == 0){
if(++i >= argc){
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){
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){
cerr << argv[0] << ": seed needs a value.\n";
exit(1);
}
else {
GARandomSeed((unsigned int)atoi(argv[i]));
}
}
else if(strcmp("help",argv[i]) == 0){
cerr << "valid arguements include standard GAlib arguments plus:\n";
cerr << " nr\tnumber of robots (" << nrobots << ")\n";
cerr << " pl\tlength of the paths (" << listsize << ")\n";
cerr << "\n";
exit(1);
}
}
if(listsize < nrobots) {
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();
genome.initialize();
cout << "a randomly-generated set of paths:\n" << genome << endl;
cout << "the ga generated:\n" << ga.statistics().bestIndividual() << "\n";
return 0;
}
// If your compiler does not do automatic instantiation (e.g. g++ 2.6.8),
// then define the NO_AUTO_INST directive. This will force the instantiation
// of the template classes that we use. For some compilers (e.g. metrowerks)
// this must come after any specializations or you'll get 'multiply-defined'
// errors when you compile.
#ifdef NO_AUTO_INST
#include <ga/GAList.C>
#include <ga/GAListGenome.C>
#if defined(__GNUG__)
template class GAList<int>;
template class GAListGenome<int>;
#else
GAList<int>;
GAListGenome<int>;
#endif
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -