📄 gpkernel_1.html
字号:
Demetic migration takes place after a new generation has been created.The members being swapped are chosen using the same selection schemeused for crossover and reproduction. <A NAME="IDX143"></A><DT><STRONG>SwapMutationProbability (double, <CODE>[0.0..100.0]</CODE>)</STRONG><DD>The probability (in percent) that swap mutation takes place. Whenever agenetic program is evolved (by creation, reproduction or crossover) andis going to be put into the new generation, this parameter determinesthe probability that that member should be mutated. <A NAME="IDX144"></A><DT><STRONG>ShrinkMutationProbability (double, <CODE>[0.0..100.0]</CODE>)</STRONG><DD>The probability (in percent) that shrink mutation takes place, otherwisesimilar to <EM>SwapMutationProbability</EM>. <A NAME="IDX145"></A><DT><STRONG>AddBestToNewPopulation (integer, <CODE>[0..1]</CODE>)</STRONG><DD>If this flag is set and steady state Genetic Programming is not used,the best performing genetic program from the old population will bemoved unchanged to the new one. <A NAME="IDX146"></A><DT><STRONG>SteadyState (integer, <CODE>[0..1]</CODE>)</STRONG><DD>If this flag is set, then steady state Genetic Programming is used,which means that during the invocation of function<EM>GPPopulation::generate()</EM> no new generation is built up, but theold one is gradually replaced by the new one. The advantage is thatmemory is needed only for one population instead of two. This parameteralso influences the main loop which resides in the user's code. Ifsteady state is not used, the old generation must be deleted and the newgeneration must replace the old one.</DL><H2><A NAME="SEC16" HREF="gpkernel_toc.html#TOC16">1.9 Loading and Saving of Populations</A></H2><P><A NAME="IDX147"></A></P><P>To save or to load an object seems to be quite simple: one has only towrite all member variables to the stream in a way that they can be readlater by the complementary load function. Problems arise when a classthat owns objects, class <EM>GPContainer</EM>, has to do the same for allthe objects it owns. To save objects is easy: just a virtual functionhas to be provided. But to load them implies that they are createdfirst.</P><H3><A NAME="SEC17" HREF="gpkernel_toc.html#TOC17">1.9.1 Registration</A></H3><P><A NAME="IDX148"></A></P><P><A NAME="IDX149"></A><A NAME="IDX150"></A><A NAME="IDX151"></A></P><BLOCKQUOTE><PRE>GPObject* GPCreateRegisteredClassObject (int ID);void GPRegisterClass (GPObject* gpo);void GPRegisterKernelClasses ();</PRE></BLOCKQUOTE><P>What is often done in such a case is to implement a registrationmechanism for all classes that want to participate in the load and saveoperation. Each class gets a unique identification value that can beobtained by a virtual function every class has to define. Beforemembers of a certain class can be loaded, they must be registered,e.g. an object of the class must be created and function<EM>GPRegisterClass()</EM> must be called.</P><P><A NAME="IDX152"></A></P><P>The trick is that class <EM>GPContainer</EM> saves not only the objects itcontains, but also their identification value. If they are to be loadedagain, function <EM>GPCreateRegisteredClassObject()</EM> is called whichcreates a new object of the given identification value. For that, itloops through all the objects that are registered until it finds onethat matches the identification value, and calls a virtual function,<EM>createObject()</EM>, for that object to create a new object of thesame class.</P><P>During the initialisation process, the kernel calls<EM>GPRegisterKernelClasses()</EM> to register all kernel classes.</P><H3><A NAME="SEC18" HREF="gpkernel_toc.html#TOC18">1.9.2 Requirements</A></H3><P>We consider a new class that inherits from <EM>GPObject</EM>:</P><P><A NAME="IDX153"></A><A NAME="IDX154"></A><A NAME="IDX155"></A><A NAME="IDX156"></A></P><BLOCKQUOTE><PRE>const int UserClassID=GPUserID;class UserClass : public GPObject{ ... virtual char* load (istream& is); virtual void save (ostream& os); virtual int isA () { return UserClassID; } virtual GPObject* createObject() { return new UserClass; } ...}</PRE></BLOCKQUOTE><P>Every class has to define those four virtual functions. <EM>load()</EM>tries to load objects from a stream, and returns NULL or an errormessage, if something went wrong. <EM>save()</EM> simply saves the objectto the stream.</P><P><A NAME="IDX157"></A></P><P><EM>isA()</EM> returns the identification value of the class. If the userinherits from any kernel class, he has to use different identificationvalues. All values greater or equal than <EM>GPUserID</EM> can be usedfor that purpose.</P><P><EM>createObject()</EM> allocates a new object of the same class bycalling a parameterless constructor. Every class should thereforedefine such a constructor.</P><H3><A NAME="SEC19" HREF="gpkernel_toc.html#TOC19">1.9.3 Loading and Saving of Gene and Population Objects</A></H3><P>As mentioned before, the gene class saves not the pointer to its nodeinformation object, but the node identification value. This value isread in from the stream during the load operation and must afterwards beconverted again to a pointer to the node. This is done by the followingfunctions.</P><P>Similarly, a population object has a pointer to its node set. When apopulation is saved, this node set is not saved. This object componentis therefore not initialised when a population is loaded again, and hasto be set manually.</P><P><A NAME="IDX158"></A><A NAME="IDX159"></A><A NAME="IDX160"></A></P><BLOCKQUOTE><PRE>class GPGene : public GPContainer{ ... void resolveNodeValues (GPNodeSet& ns); ...}class GP : public GPContainer{ ... void resolveNodeValues (GPAdfNodeSet& adfNs); ...}class GPPopulation : public GPContainer{ ... void setNodeSets (GPAdfNodeSet& adfNs_); ...}</PRE></BLOCKQUOTE><H3><A NAME="SEC20" HREF="gpkernel_toc.html#TOC20">1.9.4 Example</A></H3><P>Consider a complete population in pointer variable <EM>pop</EM> and theappropriate container of the node sets in pointer variable <EM>adfNn</EM>.To save the population and the node set, simply open a stream and callthe function <EM>save()</EM> for each object.</P><BLOCKQUOTE><PRE> GPPopulation* pop; GPAdfNodeSet* adfNs; ... ofstream savePop ("pop.dat"); adfNs->save (savePop); pop->save (savePop);</PRE></BLOCKQUOTE><P><A NAME="IDX161"></A></P><P>To reload that population, again open a stream, create an emptypopulation and call <EM>load()</EM> for each the node set and thepopulation. Afterwards, call <EM>GPPopulation::setNodeSets()</EM> toresolve the pointers to the nodes.</P><BLOCKQUOTE><PRE> ifstream loadPop ("pop.dat"); pop=new GPPopulation(); adfNs->load (loadPop); pop->load (loadPop); pop->setNodeSets (*adfNs);</PRE></BLOCKQUOTE><H2><A NAME="SEC21" HREF="gpkernel_toc.html#TOC21">1.10 Miscellaneous</A></H2><H3><A NAME="SEC22" HREF="gpkernel_toc.html#TOC22">1.10.1 Error Handling</A></H3><P><A NAME="IDX162"></A></P><P>The Genetic Programming kernel makes a lot of run time checks. Mostly,parameters of functions are checked to make the system safer and todetect errors in the early program development stage. These checks canbe suppressed by a compiler switch which then also speeds up executiontime.</P><P><A NAME="IDX163"></A><A NAME="IDX164"></A><A NAME="IDX165"></A><A NAME="IDX166"></A></P><BLOCKQUOTE><PRE>#define GPINTERNALCHECK 1#define GPCREATE_SEGMENTATIONFAULT_ON_ERROR 1void GPExitSystem (char *functionName, char *errorMessage); </PRE></BLOCKQUOTE><P>If an error is detected, the function <EM>GPExitSystem()</EM> is calledwhich reports the name of the function where the error was detected andthe error message itself, and then exits. If a special compiler switchis on, the program tries to create a segmentation fault so that it iseasier to track down the error with a debugger and find out which pieceof code really caused the error. This works only on computers andoperating systems that are able to detect a segmentation fault. Itcertainly does not work with MS-DOS!</P><H3><A NAME="SEC23" HREF="gpkernel_toc.html#TOC23">1.10.2 Kernel Initialisation</A></H3><P><A NAME="IDX167"></A><A NAME="IDX168"></A></P><BLOCKQUOTE><PRE>void GPInit (int printCopyright, long seedRandomGenerator);</PRE></BLOCKQUOTE><P>Before the Genetic Programming kernel is used, this function should becalled once. It prints out a copyright message, if flag<EM>printCopyright</EM> is true, initialises the random number generatorwith the value <EM>seedRandomGenerator</EM> and registers all kernelclasses for the load and save operations.</P><P><A NAME="IDX169"></A></P><P>If <EM>seedRandomGenerator</EM> has the value <CODE>-1</CODE>, the random numbergenerator is initialised with the return value from the system function<EM>time()</EM>, otherwise with the given value. This can be very helpfulin the debugging stage where errors must be reproduced: even thoughrandom numbers are used, the program behaviour stays the same.</P><H3><A NAME="SEC24" HREF="gpkernel_toc.html#TOC24">1.10.3 Random Functions</A></H3><P><A NAME="IDX170"></A></P><P>The Genetic Programming kernel uses its own random number generatormostly due to the fact that the random number generators of manystandard C libraries are usually of poor performance with respect to therandom numbers that are generated.</P><P><A NAME="IDX171"></A><A NAME="IDX172"></A><A NAME="IDX173"></A></P><BLOCKQUOTE><PRE>void GPsrand (long);long GPrand ();int GPRandomPercent (double percent);</PRE></BLOCKQUOTE><P><EM>GPsrand()</EM> initialises the random number generator. This isnormally done by <EM>GPInit()</EM>. <EM>GPrand()</EM> returns a randomnumber in the range <CODE>0..2^31-2</CODE>. <EM>GPRandomPercent()</EM> returns0 or 1, depending on the probability of the parameter <EM>percent</EM>.The resolution for <EM>percent</EM> is <CODE>0.0001</CODE>.</P><H3><A NAME="SEC25" HREF="gpkernel_toc.html#TOC25">1.10.4 Reading a Configuration File</A></H3><P><A NAME="IDX174"></A><A NAME="IDX175"></A></P><P><STRONG>Note:</STRONG> this module will probably be replaced one day by a moresophisticated one.</P><P><A NAME="IDX176"></A></P><P>The module <EM>Config</EM> defines a class called <EM>GPConfiguration</EM>and provides an easy and simple to use way to define configurationvariables in a <EM>.ini</EM> file, which are read in by the constructor ofthis class.</P><P><A NAME="IDX177"></A></P><P>Simply call the constructor of the class with the stream to put anymessages on (only for error messages, in case the file is malformed),the name of the file that should be read, and an array of structures<EM>GPConfigVarInformation</EM> describing the variables. The array mustend with a <EM>NULL</EM> pointer in the structure variable <EM>varPtr</EM>.The constructor reads the file and puts all the values of the variableshe finds in the denoted memory location.</P><P>The file format of a configuration file consists of the variable name,the character <SAMP>`='</SAMP> and the value which can be a string, an integerof a floating point value. Comments are allowed and recognised by linesstarting with the character <SAMP>`#'</SAMP>.</P><P>Strings are duplicated; space is allocated with <CODE>new char[]</CODE> andshould be freed, if no longer used. In case any configuration variableis of type string, the structure variable <EM>varPtr</EM> points to avariable of type <EM>(char *)</EM>. That's a better way than letting theuser provide
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -