📄 symbreg.cc
字号:
tout << "\\begin{eqnarray}" << endl; // Print all ADF's, if any GPGene* current; for (int n=0; n<containerSize(); n++) { if (n!=0) os << "\\\\" << endl; os << "f_" << n+1 << " & = & "; if ((current=NthGene (n))) os << *current; else os << " NONE"; os << "\\nonumber "; } tout << endl << "\\end{eqnarray}" << endl << endl; } else // Just call the print function of our base class to do the // standard job. GP::printOn (os);}// This function is the divide with closure. Basically if you divide// anything by zero you get an error so we have to stop this// process. We check for a very small denominator and return a very// high value.inline double divide (double x, double y){ if (fabs (y)<1e-6) { if (x*y<0.0) return -1e6; else return 1e6; } else return x/y;}// We have the freedom to define this function in any way we like. In// this case, it takes the parameter x that represents the terminal X,// and returns the value of the expression. It's recursive of course.double MyGene::evaluate (double x, MyGP& gp, double arg0, double arg1){ double ret, a0, a1; if (isFunction ()) switch (node->value ()) { case '*': ret=NthMyChild(0)->evaluate (x, gp, arg0, arg1) * NthMyChild(1)->evaluate (x, gp, arg0, arg1); break; case '+': ret=NthMyChild(0)->evaluate (x, gp, arg0, arg1) + NthMyChild(1)->evaluate (x, gp, arg0, arg1); break; case '-': ret=NthMyChild(0)->evaluate (x, gp, arg0, arg1) - NthMyChild(1)->evaluate (x, gp, arg0, arg1); break; case '%': // We use the function divide rather than "/" to ensure the // closure property ret=divide (NthMyChild(0)->evaluate (x, gp, arg0, arg1), NthMyChild(1)->evaluate (x, gp, arg0, arg1)); break; case 'A': // This is the ADF0 function call. We have access to that // subtree, as the GP gave us a reference to itself as // parameter. We first evaluate the subtrees, and then call // the adf with the parameters a0=NthMyChild(0)->evaluate (x, gp, arg0, arg1); a1=NthMyChild(1)->evaluate (x, gp, arg0, arg1); ret=gp.NthMyGene(1)->evaluate (x, gp, a0, a1); break; default: GPExitSystem ("MyGene::evaluate", "Undefined function value"); } if (isTerminal ()) switch (node->value ()) { case 'X': ret=x; break; case 1: ret=arg0; break; case 2: ret=arg1; break; default: GPExitSystem ("MyGene::evaluate", "Undefined terminal value"); } // Restrict the return value (it may become really large, especially // for large trees) const double maxValue=1e6; if (ret>maxValue) return maxValue; if (ret<-maxValue) return -maxValue; return ret;}// Evaluate the fitness of a GP and save it into the GP class variable// stdFitness.void MyGP::evaluate (){ double rawfitness=0.0, diff=0.0; // The evaluation function checks with some values of the // mathematical function for (int i=0; i<DATAPOINTS; i++) { // Calculate genetic programs answer. ques[i] is the current x // value of the function. double result=NthMyGene(0)->evaluate (ques[i], *this, 0, 0); // Calculate square error between the genetic program and the // actual answer. diff=pow (answ[i]-result, 2); // Add this difference to total rawfitness rawfitness+=diff; } rawfitness=sqrt (rawfitness); // We want a short solution and put the total GP length to the // fitness. As we know that the best solution has the length 12, we // create such a formula that the fitness will be 1.0 in this case. // This standardized fitness is saved in the GP object. stdFitness=rawfitness+(double)length ()/12.0;}// Create function and terminal setvoid createNodeSet (GPAdfNodeSet& adfNs){ // Reserve space for the node sets adfNs.reserveSpace (2); // Now define the function and terminal set for each ADF and place // function/terminal sets into overall ADF container GPNodeSet& ns0=*new GPNodeSet (6); GPNodeSet& ns1=*new GPNodeSet (4); adfNs.put (0, ns0); adfNs.put (1, ns1); // Define functions/terminals and place them into the appropriate // sets. Terminals take two arguments, functions three (the third // parameter is the number of arguments the function has) ns0.putNode (*new GPNode ('+', "+", 2)); ns0.putNode (*new GPNode ('-', "-", 2)); ns0.putNode (*new GPNode ('*', "*", 2)); ns0.putNode (*new GPNode ('%', "%", 2)); ns0.putNode (*new GPNode ('A', "ADF0", 2)); ns0.putNode (*new GPNode ('X', "x")); ns1.putNode (*new GPNode ('+', "+", 2)); ns1.putNode (*new GPNode ('*', "*", 2)); ns1.putNode (*new GPNode (1, "x1")); ns1.putNode (*new GPNode (2, "x2"));}void newHandler (){ cerr << "\nFatal error: Out of memory." << endl; exit (1);}int main (){ // We set up a new-handler, because we might need a lot of memory, // and we don't know it's there. set_new_handler (newHandler); // Set up the array with data points. This is for the evaluation // process. for (int i=0; i<DATAPOINTS; i++) { ques[i]=i; answ[i]=EQUATION(ques[i]); } // Init GP system. GPInit (1, -1); // Declare the GP Variables, set defaults and read configuration // file. The defaults will be overwritten by the configuration file // when read. If it doesn't exist, the defaults will be written to // the file. GPConfiguration config (cout, "symbreg.ini", configArray); // Open the main output file for data and statistics file. First set // up names for data file. We use also a TeX-file where the // equations are written to in TeX-style. Very nice to look at! // Remember we should delete the string from the stream, well just a // few bytes ostrstream strOutFile, strStatFile, strTeXFile; strOutFile << InfoFileName << ".dat" << ends; strStatFile << InfoFileName << ".stc" << ends; strTeXFile << InfoFileName << ".tex" << ends; ofstream fout (strOutFile.str()); ofstream bout (strStatFile.str()); tout.open (strTeXFile.str(), ios::out); tout << endl << "\\documentstyle[a4]{article}" << endl << "\\begin{document}" << endl; // Print the configuration to the files just opened fout << cfg << endl; cout << cfg << endl; tout << "\\begin{verbatim}\n" << cfg << "\\end{verbatim}\n" << endl; // Create the adf function/terminal set and print it out. GPAdfNodeSet adfNs; createNodeSet (adfNs); cout << adfNs << endl; fout << adfNs << endl; // Create a population with this configuration cout << "Creating initial population ..." << endl; MyPopulation* pop=new MyPopulation (cfg, adfNs); pop->create (); cout << "Ok." << endl; pop->createGenerationReport (1, 0, fout, bout); // Print the best of generation to the LaTeX-file. printTexStyle=1; tout << *pop->NthGP (pop->bestOfPopulation); printTexStyle=0; // This next for statement is the actual genetic programming system // which is in essence just repeated reproduction and crossover loop // through all the generations ..... MyPopulation* newPop=NULL; for (int gen=1; gen<=cfg.NumberOfGenerations; gen++) { // Create a new generation from the old one by applying the // genetic operators if (!cfg.SteadyState) newPop=new MyPopulation (cfg, adfNs); pop->generate (*newPop); // Delete the old generation and make the new the old one if (!cfg.SteadyState) { delete pop; pop=newPop; } // Print the best of generation to the LaTeX-file. printTexStyle=1; tout << "Generation " << gen << ", fitness " << pop->NthGP (pop->bestOfPopulation)->getFitness() << endl; tout << *pop->NthGP (pop->bestOfPopulation); printTexStyle=0; // Create a report of this generation and how well it is doing pop->createGenerationReport (0, gen, fout, bout); } // TeX-file: end of document tout << endl << "\\end{document}" << endl; tout.close (); cout << "\nResults are in " << InfoFileName << ".dat," << InfoFileName << ".tex," << InfoFileName << ".stc." << endl; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -