// Chrome.h version to support stack.cc, from GPQUICK-2.1 // W.Langdon cs.ucl.ac.uk $Revision: 1.3 $ //Modifications (reverse order): // WBL 15 Oct 1994 Add support for loading populations // WBL 8 Sep 1994 Add static_check // WBL 25 Aug 1994 Make CSelector different for each tree, remove funcbag // from chrome (use problem pointer instead) // WBL 24 Aug 1994 Add Bestof and Worstof to Problem. Add select_candidates // WBL 22 Aug 1994 remove (to problem files) hits and write_hits() // add Problem::NewChrome // WBL 15 Aug 1994 Add hits and write_hits() // Initialise xtree to -1 rather than 0 // WBL 6 Jul 1994 Add pPopWidth and pDemeWidth // WBL 6 Jul 1994 Put NUM_TREES to 6 (for adf1) // WBL 30 Jun 1994 Add pTraceStatic+pTraceDynamic+pTraceDStats // WBL 28 Jun 1994 Supply default for go_until tree param // WBL 21 Jun 1994 Put back NUM_TREES to 5. Add parameter to generate() // go_until() and CrossTree() // WBL 21 Jun 1994 Increase NUM_TREES from 5 to 7 (for two adfs) // WBL 16 Jun 1994 Add PopSeed and pTestSeed, pTrace. Add TRACE // WBL 14 Jun 1994 Add Save and Load to ChromeParams (based on GPCPlus3.0 // gpv.cc). Add pGenerateLimit // Add DisplayStats() and Write() // WBL 16 May 1994 Add DisplayStats() to Pop, Fix MULTREE bug // GPQUICK // C++ prefix stack implementation // Divides GP system into classes: // Chrome-Function - representation of the genetic program // Pop - Runs the GA // Problem - fitness and primitive functions #ifndef _CHROME_H #define _CHROME_H #define INT32 int #include "selector.h" // uniform argument and return type for "closure" typedef int retval; //WBL for stack // Support for multiple trees within one individual in pop WBL // Only tested with FASTEVAL so far #define MULTREE #define NUM_TREES 6 // keep and print genelogical trace info #define TRACE // Define this if you do multiple evals, one Chrome at a time // It speeds up the EVAL calls significantly // Penalties are: Time to expand the chrome once before evaluations // Uses globals, so only one Chrome at a time #define INTERFACE #define FASTEVAL #ifdef FASTEVAL // evaluation code with global pointers typedef retval (*EVALFUNC)(); #else // evaluation code with pointer passing typedef retval (*EVALFUNC)(class Chrome*); #endif // two byte instruction node, 8 bits function index, 8 bits operand index typedef struct {unsigned char op; unsigned char idx;} node; // node type // eval node with pointers for direct function calls typedef struct {EVALFUNC ef; unsigned char op; unsigned char idx;} evalnode; // node type // Grab the function index #define FUNCNUM(c) (c.op) // argument count for the current function #define ARGNUM() (funclist[FUNCNUM(expr[ip])]->argnum) #define PARGNUM(ip) (funclist[ip->op]->argnum) // Grab the operand #define VARNUM(c) (c.idx) #define PVARNUM(ip) (ip->idx) // Build a node "c" #define SETNODE(c,o,v) c.op=o;c.idx=v #define SETEVALNODE(ip,o,v) ip->op=o;ip->idx=v;ip->ef=funclist[o]->evalfunc // Function evaluation stuff // These macros may change internal form for faster evaluation. // Arguments will be removed. Use them. #ifdef FASTEVAL //Define an EVALFUNC with no arguments #define OPDEF(Op) retval Op() //Get a pointer to the chrome being evaluated #define CHROMEP ChromeGlobal //current instruction pointer #define IP IpGlobal // get its argument #define GETIDX (IP->idx) // traverse an unused argument in an eval #define TRAVERSE() CHROMEP->TraverseGlobal() //Evaluate the next expression #ifdef INTERFACE //#define EVAL ((++IP)->ef)() #define EVAL CHROMEP->evalwithstore() #else //#define EVAL ((++IP)->ef)() #endif #else //Define an EVALFUNC #define OPDEF(Op) retval Op(Chrome* curchrome) //Get a pointer to the chrome being evaluated #define CHROMEP curchrome //current instruction pointer #define IP CHROMEP->ip // get its argument #define GETIDX (CHROMEP->expr[IP].idx) // traverse an unused argument in an eval #define TRAVERSE() CHROMEP->Traverse() //Evaluate the next expression #define EVAL CHROMEP->eval() #endif //function and memory arrays #define FUNCARRAYSIZE 100 #define CONSTARRAYSIZE 256 // cut numeric overflows. Bound returns to 10^15 #define BIGFLOAT ( (retval) 1.0e15 ) #define SMALLFLOAT ( (retval) 1.0e-15 ) #define BOUNDF(f) (f==0? f : (f>0 ?((f)>BIGFLOAT ? BIGFLOAT : ((f)-SMALLFLOAT? -SMALLFLOAT : (f))) )) // Compatibility stuff #define BOOL int #define UINT unsigned int // All primitives in a problem are subclasses of this FUNCTION object class Function { public: int serial; // serial number in universal function list (not implemented) char name[30]; // Function name int argnum; // number of arguments int varnum; // number of variables in variable table of opcode int weight; // selection frequency relative to other functions Function() {}; Function(int a,int v,int w,EVALFUNC e,char* n) {argnum=a;varnum=v;weight=w;evalfunc=e;strcpy(name,n);}; virtual char* getprint(class Chrome* st); // Printed name may differ char* getname() {return name;}; EVALFUNC evalfunc; // pointer to evaluation code. Not a virtual for speed reasons #ifndef FASTEVAL retval eval(class Chrome* st) {return (evalfunc)(st);}; // active ingredient #else retval eval() {return (evalfunc)();}; #endif }; //******************* Parameters enum { pMaxExpr, // Maximum expression size in nodes pInitExpr, // Maximum initial expression depth pMuteRate, // Node mutation rate per 1000 pCrossSelf, // Allow self crossover? pUnRestrictWt, // any point crossover per 100 pCrossWt, // Crossover weight on generate pMuteWt, // overall Mutation weight on generate pMuteNodeWt, // Normal-Mutation weight on generate pMuteConstWt, // C-Mutation weight on generate pMuteShrinkWt, // Shrink-Mutation weight on generate pAnnealMuteWt, // Mut. Annealing weight pAnnealCrossWt, // Crossover Annealing weight pCopyWt, // Copy weight on generate pSelectMethod, // can be tournament, ranked, proportional pTournSize, // tournament size 2-10 pMateRadius, // mating radius. 0 for panmictic pGaussRegion, // 0 for flat selection in region, 1 for gaussian pRepeatEval, // repeat evaluation on copy? For sampled evals pKillTourn, // number for anti-tournament pMaxAge, // age to start killing off a good guy pParsimony, pFitnessCases, // number of fitness cases pPopSize, // population size pGenerateLimit, // Terminate GP if no solution pTestSeed, // Seed for application to generate tests pPopSeed, // Seed for Pop etc. pTrace, // display trace info pPopWidth, // if !=0 treat pop as being torroid with this as width pDemeWidth, // if !=0 treat deme as being rectangle. nb area =pMateRadius PARAM_COUNT }; // total number of parameters #define pTraceStatic 1 #define pTraceDynamic 2 #define pTraceDStats 4 class ChromeParams { // parameter set for initializing a chrome public: int params[PARAM_COUNT]; static char *pnames[]; // names are added in the constructor int varcount; int funccount; ChromeParams(); virtual ~ChromeParams(); virtual void Edit() {}; // Put your own edit code here void Save( ostream& out = cout); void Load( istream& in); }; // Carrier for fitness values. // Feel free to subclass this if you want to track your fitness cases more closely (by adding data) // or minimize instead of maximize (by redefining IsBetter) // or combine multiple scores class FitnessValue { public: float fvalue; // Always provide this for reporting reasons virtual BOOL IsBetter(FitnessValue* fv) {return fvalue>fv->fvalue;}; virtual BOOL IsBetter(float fv) {return fvalue>fv;}; virtual void Copy(FitnessValue* fv) {memcpy(this,fv,sizeof(FitnessValue));}; operator float() {return fvalue;}; operator >(FitnessValue& fv) {return IsBetter(&fv);}; operator <(FitnessValue& fv) {return fv.IsBetter(this);}; virtual void write(ostream& ofile = cout) { ofile<IsBetter(chrome->nfitness);}; //D.Raithatha retval DReval() {ip++;return funclist[FUNCNUM(expr[ip])]->eval();} ; #ifndef FASTEVAL retval eval() {ip++;return funclist[FUNCNUM(expr[ip])]->eval(this);} ; #endif #ifdef INTERFACE retval evalwithstore(); double zoomtext(double); #endif #ifdef MULTREE retval evalAll(int) ; // eval the whole expression anew #else retval evalAll() ; // eval the whole expression anew #endif void SetupEval(); // expand expression for multiple evals void Traverse(); // Skips over next subtree void TraverseGlobal(); #ifdef MULTREE Chrome* CrossTree(Chrome* mate, int tree); int GetIntNode(int tree); // get an internal node for crossover int GetAnyNode(int tree); // get any node for crossover #else Chrome* CrossTree(Chrome* mate); int GetIntNode(); // get an internal node for crossover int GetAnyNode(); // get any node for crossover #endif void Mutate(); // mutate nodes with rate r void MutateC(); void MutateShrink(); int SubLen(int startat=0) {ip=startat;Traverse();return ip-startat;}; // return length of expression at startat //void write(int pretty, ofstream & ofile); void write(int pretty,ostream& ofile = cout); double ca(int,int); //compares number of args of two funcs of same depth int get_depth(); #ifdef INTERFACE void suitwrite(int); double *suitsubwrite(double,double,int); #endif #ifndef MULTREE {ip=-1;depth=0;SubWrite(ofile,pretty);};} // write the expression #endif ; #ifdef TRACE void write_trace(ostream& ofile = cout); #endif void SubWrite(ostream& ostr,int pretty = 0); int SubLoad(istream& istr,node* buf); // load an expression. Return 0 on success or error val int FindFunc(char* funcname); // find index of a function, or -1 if not found virtual int Load(istream& istr,int issource); // load from a stream. Return success }; class Problem { // Sets up a particular GP problem. GA independent. // contains function set, variables, and fitness function protected: retval* constlist; // array of constants retval* varlist; // array of variables public: Function** funclist; // primitive functions public: int funccount; CSelector* funcbag[NUM_TREES]; // select functions by weight Problem(); // allocate the arrays virtual ~Problem(); void AddF(Function* f) // add a function to the problem {funclist[funccount++]=f;}; Function** getfuncs() {return funclist;}; retval* getconsts() {return constlist;}; // CSelector* getfuncbag() ; void addtofuncbag(int tree, Function* f); // User hooks virtual char* GetTreeName(int tree)= 0; //D.Raithatha virtual FitnessValue* GetFitnessObj(); // Can change behavior of FitnessValue virtual float fitness(Chrome* chrome); // The active ingredient. You add this. virtual void WriteTreeName(int tree, ostream& ostr = cout ) // The active ingredient. You add this. {ostr<<" T"<