📄 gplawn.cc
字号:
// gplawn.cpp
//--------------------------------------------------------------------------
// This code is a component of Genetic Programming in C++ (Version 0.40)
// Copyright Adam P. Fraser, 1993,1994
// This code is released for non-commercial use only.
// For comments, improvements, additions (or even money !?) contact:
// Adam Fraser, Postgraduate Section, Dept of Elec & Elec Eng,
// Maxwell Building, University Of Salford, Salford, M5 4WT, United Kingdom.
// Internet: a.fraser@eee.salford.ac.uk
// Tel: (UK) 061 745 5000 x3633
// Fax: (UK) 061 745 5999
//--------------------------------------------------------------------------
// The definitions of code to map the LawnMower problem developed by John Koza
// (& James Rice ??) into gpcpp by Adam Fraser, 1 March 1994
// Uses ADFs and is the first paper (and hence the best) on this subject I have seen.
// The paper which has this information has been submitted to Kim Kinnear (Ed)
// 'Advances in Genetic Programming' as a chapter called 'Scalable Learning in
// Genetic Programming using Automatic Function Definition' by John Koza.
// I would like to thank John Koza and James Rice for the copy of the paper
// from which I have developed the code (in one evening! Sad getalife that I am).
// and now an explanation....a paraphrasing of the introduction bit of paper
// Imagine, if you will, a lawn upon which we have placed a robot who wishes to
// evolve the ability to mow the lawn. The lawn is a sixty four grid toriodal
// world . Using standard GP the robot would have to
// evolve sixty four different moves but with new improved ADF GP its a different
// story........ and ADF GP washes whiter and is lighter than ordinary chocolate
// The function and terminals are explained in their chunks of code.....
// F(main) ={ ADF1 , 1 argument }
// T(main) = { ADF0 }
// F(adf0) = { V8A, PROG2, 2 argument each }
// T(adf0) = { LEFT, MOW, Real }
// F(adf1) = { V8A, FROG, PROG2 , 2,1,2 arguments respectively }
//NB Koza includes ADF0 in function set withargs = 0 this is a terminal, surely ??
// T(adf1) = { ARG0, LEFT, MOW, Real }
// The return values in all cases are a vector of the form (i,j) where i and j are
// integers modulus 8. (Note this changes somewhat when Koza discusses slightly larger
// or smaller worlds which I dont deal with in this code for that reason).
#include "pop.hpp"
#include "function.hpp"
#include "terminal.hpp"
#include "lawn.hpp"
#include "mower.hpp"
FS *FunctionSets[3]; // 3 Function sets, one for root, two for ADFs
TS *TerminalSets[3]; // 3 Terminal set '' ''
#define FITNESS Vector
Robot Mower;
unsigned int EvaluateFitness( GP*,int ); /* These four functions MUST be included */
ostream& (*TranslatePrint)( ostream&, Gene* );
void InitialiseGPS();
void CleanUpGPS();
FITNESS (*Translate)( Gene* );
FITNESS TranslateROOT( Gene* );
FITNESS TranslateADF0( Gene* );
FITNESS TranslateADF1( Gene* );
ostream& TranslatePrintROOT( ostream&, Gene* );
ostream& TranslatePrintADF0( ostream&, Gene* );
ostream& TranslatePrintADF1( ostream&, Gene* );
// global variables both for ADFs
FITNESS glbADF0;
GP *pgpGlobal;
// macros of how to use ADF structure
#define ROOT *(pgpGlobal->ppgHeader)
#define ADF0 *(pgpGlobal->ppgHeader + 1)
#define ADF1 *(pgpGlobal->ppgHeader + 2)
unsigned int EvaluateFitness( GP *pgp, int Evals )
{
pgpGlobal = pgp; // set up global variable for start of gene programs
// necessary to get at ADF structure, an unfortunate
// addition to the code in my opinion....
Mower.x = 4;
Mower.y = 4;
Mower.Moving = 1; // thats north
Mower.Energy = Evals;
CreateLawn(); // grow some more grass. Quite a small lawn (8x8)
Translate = TranslateROOT;
while ( Mower.Energy )
{
Translate( ROOT );
if ( Mower.Energy == 100 ) return 0; // gets nought if it don't move
//and also stop infinite loops v.important
}
return ( 64 - CheckLawn() );
}
FITNESS TranslateROOT( Gene *pg )
{
switch ( pg->iValue )
{
case 1: // ADF1 ->one args
{
// note I send the variable to ADF1 through glbADF0
Vector vReturn;
Translate = TranslateADF1;
vReturn = Translate( ADF1 );
Translate = TranslateROOT;
return vReturn;
}
case 2:
{
Translate = TranslateADF0;
glbADF0 = Translate( ADF0 ); // set up global variable...
Translate = TranslateROOT;
return glbADF0;
}
default:{
ExitSystem("TranslateMAIN" );
// need to return something to stop warning though this will nerver be called
return glbADF0;
}
}
}
ostream& TranslatePrintROOT( ostream& os, Gene *pg )
{
switch ( pg->iValue )
{
case 1: os << " ( ADF1"; /* functions */
break;
case 2: os << " ADF0";
break;
default: os << "ERROR: TranslateMAIN";
break;
}
return os;
}
FITNESS TranslateADF0( Gene *pg )
{
switch ( pg->iValue )
{
case 1: return V8A( pg->pgChild ); // two args
case 2: return PROG2( pg->pgChild ); // two args
case 3: return LEFT();
case 4: return MOW();
default:
{
// and now the real number business, hope you like the way I have done it.....
unsigned char ch = pg->iValue - 32768; //set to begin at 0;
Vector v_harvey;
v_harvey.i = ch % 8; // set the number of real numbers to 64 and then % 8
v_harvey.j = ch / 8; // / 8 to get the two sets of values.
return v_harvey;
}
}
}
ostream& TranslatePrintADF0( ostream& os, Gene *pg )
{
switch ( pg->iValue )
{
case 1: os << " ( V8A"; /* functions */
break;
case 2: os << " ( PROG2";
break;
case 3: os << " LEFT";
break;
case 4: os << " MOW";
break;
default:
{
unsigned char ch = pg->iValue - 32768; //set to begin at 0;
Vector v_harvey;
v_harvey.i = ch % 8; // set the number of real numbers to 64 and then % 8
v_harvey.j = ch / 8; // / 8 to get the two sets of values.
os << " [" << (int)v_harvey.i << "," << (int)v_harvey.j << "]";
}
break;
}
return os;
}
FITNESS TranslateADF1( Gene *pg )
{
switch ( pg->iValue )
{
case 1: return V8A( pg->pgChild ); // two args
case 2: return FROG( pg->pgChild ); // one arg
case 3: return PROG2( pg->pgChild ); // two args
case 4: return LEFT();
case 5: return MOW();
case 6: return glbADF0;
default:
{
// and now the real number business, hope you like the way I have done it.....
unsigned char ch = pg->iValue - 32768; //set to begin at 0;
Vector vector;
vector.i = ch % 8; // set the number of real numbers to 64 and then % 8
vector.j = ch / 8; // / 8 to get the two sets of values.
return vector;
}
}
}
ostream& TranslatePrintADF1( ostream& os, Gene *pg )
{
switch ( pg->iValue )
{
case 1: os << " ( V8A"; /* functions */
break;
case 2: os << " ( FROG";
break;
case 3: os << " ( PROG2";
break;
case 4: os << " LEFT";
break;
case 5: os << " MOW";
break;
case 6: os << " ADF0";
break;
default:
{
unsigned char ch = pg->iValue - 32768; //set to begin at 0;
Vector v_harvey;
v_harvey.i = ch % 8; // set the number of real numbers to 64 and then % 8
v_harvey.j = ch / 8; // / 8 to get the two sets of values.
os << " [" << (int)v_harvey.i << "," << (int)v_harvey.j << "]";
}
break;
}
return os;
}
ostream& operator <<(ostream& os, GP *pgp )
{
if ( pgp )
{
pgpGlobal = pgp; // set up global variable so you can use MACRO's
TranslatePrint = TranslatePrintROOT;
os << "Main: (" << ROOT << endl;
TranslatePrint = TranslatePrintADF0;
os << "ADF0: (" << ADF0 << endl;
TranslatePrint = TranslatePrintADF1;
os << "ADF1: (" << ADF1 << endl;
}
return os; // must return this value or hell breaks loose..
}
void InitialiseGPS()
{
// F(main) = { ADF1 , 1 argument }
// T(main) = { ADF0 }
if (!(FunctionSets[0] = new FS( 1, 1, 1 )) ) ExitSystem( "Initialise");
if (!(TerminalSets[0] = new TS( 1, 2 )) ) ExitSystem( "Initialise" );
// F(adf0) = { V8A, PROG2, 2 argument each }
// T(adf0) = { LEFT, MOW, Real }
if (!(FunctionSets[1] = new FS( 2, 1,2, 2,2 )) ) ExitSystem( "Initialise");
if (!(TerminalSets[1] = new TS( 3, 3,4,RandomReal, 64 )) ) ExitSystem( "Initialise" );
// F(adf1) = { V8A, FROG, PROG2 , 2,1,2 arguments respectively }
// T(adf1) = { ARG0, LEFT, MOW, Real }
if (!(FunctionSets[2] = new FS( 3, 1,2,3, 2,1,2 )) ) ExitSystem( "Initialise");
if (!(TerminalSets[2] = new TS( 4, 4,5,6,RandomReal, 64 )) ) ExitSystem( "Initialise" );
}
void CleanUpGPS()
{
for ( int i= 0; i < 3; i++ )
{
delete FunctionSets[i];
delete TerminalSets[i];
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -