t-eoSymreg.cpp

00001 #ifdef _MSC_VER
00002 #pragma warning(disable:4786)
00003 #endif
00004 
00005 #include <gp/eoParseTree.h>
00006 #include <eo>
00007 
00008 using namespace gp_parse_tree;
00009 using namespace std;
00010 
00011 //-----------------------------------------------------------------------------
00012 
00013 class SymregNode
00014 {
00015 public :
00016 
00017         enum Operator {X = 'x', Plus = '+', Min = '-', Mult = '*', PDiv = '/'};
00018 
00019         SymregNode(void)                                { init(); }
00020         SymregNode(Operator _op)                { op = _op; }
00021         virtual ~SymregNode(void)                       {}
00022 
00023         // arity function, need this function!
00024         int arity(void) const      { return op == X? 0 : 2; }
00025 
00026     void randomize(void) {}
00027     
00028         // evaluation function, single case, using first argument to give value of variable
00029         template <class Children>
00030         void operator()(double& result, Children args, double var) const
00031         {
00032         double r1, r2;
00033 
00034         if (arity() == 2)
00035         {
00036             args[0].apply(r1, var);
00037             args[1].apply(r2, var);
00038         }
00039 
00040                 switch (op)
00041                 {
00042                 case Plus : result = r1 + r2; break;
00043                 case Min  : result = r1 - r2; break;
00044                 case Mult : result = r1 * r2; break;
00045                 case PDiv : 
00046                         {
00047                                 if (r2 == 0.0)
00048                                         result = 1.0; // protection a la Koza, realistic implementations should maybe throw an exception
00049                 else
00050                                     result = r1 / r2;
00051                 break;
00052                         }
00053 
00054                 case X    : result = var; break;
00055                 }
00056 
00057         }
00058 
00060     template <class Children>
00061         void operator()(string& result, Children args) const
00062     {
00063         static const string lb = "(";
00064         static const string rb = ")";
00065         char opStr[4] = "   ";
00066         opStr[1] = op;
00067         
00068             if (arity() == 0)
00069                 {
00070             result = "x";
00071             return;
00072         }
00073         // else
00074         string r1;
00075         args[0].apply(r1);
00076         result = lb + r1;
00077         result += opStr; 
00078         args[1].apply(r1);
00079         result += r1 + rb;
00080     }
00081 
00082     Operator getOp(void) const { return op; }    
00083 
00084 protected :
00085 
00086         void init(void)                                 { op = X; }
00087 
00088 private :
00089 
00090         Operator op; // the type of node
00091 };
00092 
00094 static SymregNode init_sequence[5] = {SymregNode::X, SymregNode::Plus, SymregNode::Min, SymregNode::Mult, SymregNode::PDiv}; // needed for intialization
00095 
00096 // MSVC does not recognize the lt_arity<Node> in eoParseTreeDepthInit
00097 // without this specialization ...
00098 // 2 months later, it seems it does not accept this definition ...
00099 // but dies accept the lt_arity<Node> in eoParseTreeDepthInit
00100 // !!!
00101 // #ifdef _MSC_VER 
00102 // template <>
00103 // bool lt_arity(const SymregNode &node1, const SymregNode &node2) 
00104 // {
00105 //              return (node1.arity() < node2.arity());
00106 // }
00107 // #endif
00108 
00109 //-----------------------------------------------------------
00110 // saving, loading
00111 
00112 std::ostream& operator<<(std::ostream& os, const SymregNode& eot)
00113 {
00114     os << static_cast<char>(eot.getOp());
00115     return os;
00116 }
00117 
00118 std::istream& operator>>(std::istream& is, SymregNode& eot)
00119 {
00120     char type;
00121     type = (char) is.get();
00122     eot = SymregNode(static_cast<SymregNode::Operator>(type));
00123     return is;
00124 }
00125 
00126 
00127 //-----------------------------------------------------------------------------
00130 double targetFunction(double x)
00131 { 
00132         return x * x * x * x - x * x * x + x * x * x - x * x + x - 10; 
00133 }
00134 
00135 // parameters controlling the sampling of points
00136 const double xbegin = -10.0f;
00137 const double xend   = 10.0f;
00138 const double xstep  = 1.3f; 
00139 
00140 template <class FType, class Node> struct RMS: public eoEvalFunc< eoParseTree<FType, Node> > 
00141 {
00142 public :
00143 
00144     typedef eoParseTree<FType, Node> EoType;
00145 
00146     typedef eoParseTree<FType, Node> argument_type;
00147     typedef double                   fitness_type;
00148 
00149         RMS(void) : eoEvalFunc<EoType>()
00150         {
00151                 int n = int( (xend - xbegin) / xstep);
00152                 
00153                 inputs.resize(n);
00154                 target.resize(n);
00155 
00156                 int i = 0;
00157 
00158         for (double x = xbegin; x < xend && i < n; ++i, x+=xstep)
00159                 {
00160                         target[i] = targetFunction(x);
00161                         inputs[i] = x;
00162                 }
00163         }
00164 
00165     ~RMS() {}
00166     
00167         void operator()( EoType & _eo )  
00168         {
00169                 vector<double> outputs;
00170                 outputs.resize(inputs.size());
00171                 
00172         double fitness = 0.0;
00173         
00174         for (unsigned i = 0; i < inputs.size(); ++i)
00175         {
00176                     _eo.apply(outputs[i], inputs[i]);
00177                 fitness += (outputs[i] - target[i]) * (outputs[i] - target[i]);
00178         }
00179                 
00180         fitness /= (double) target.size();
00181         fitness = sqrt(fitness);
00182                         
00183                 if (fitness > 1e+20)
00184                         fitness = 1e+20;
00185 
00186                 _eo.fitness(fitness);
00187         }
00188 
00189 private :
00190         vector<double> inputs;
00191         vector<double> target;
00192 };
00193 
00194 template <class EOT, class FitnessType>
00195 void print_best(eoPop<EOT>& pop)
00196 {
00197     std::cout << std::endl;
00198     FitnessType best = pop[0].fitness();
00199     int index = 0;
00200 
00201     for (unsigned i = 1; i < pop.size(); ++i)
00202     {
00203         if (best < pop[i].fitness())
00204         {
00205             best = pop[i].fitness();
00206             index = i;
00207         }
00208     }
00209     
00210     std::cout << "\t";
00211         
00212     string str;
00213     pop[index].apply(str);
00214     
00215     std::cout << str.c_str();
00216     std::cout << std::endl << "RMS Error = " << pop[index].fitness() << std::endl;
00217 }
00218 
00219 int main()
00220 {
00221     typedef eoMinimizingFitness FitnessType;
00222     typedef SymregNode GpNode;
00223 
00224     typedef eoParseTree<FitnessType, GpNode> EoType;
00225     typedef eoPop<EoType> Pop;  
00226 
00227     const int MaxSize = 100;
00228     const int nGenerations = 10; // only a test, so few generations
00229 
00230     // Initializor sequence, contains the allowable nodes
00231     vector<GpNode> init(init_sequence, init_sequence + 5);
00232 
00233     // Depth Initializor, defaults to grow method.
00234     eoGpDepthInitializer<FitnessType, GpNode> initializer(10, init);
00235     
00236     // Root Mean Squared Error Measure
00237     RMS<FitnessType, GpNode>              eval;
00238 
00239     Pop pop(50, initializer);
00240 
00241     apply<EoType>(eval, pop);
00242 
00243     eoSubtreeXOver<FitnessType, GpNode>   xover(MaxSize);
00244     eoBranchMutation<FitnessType, GpNode> mutation(initializer, MaxSize);
00245 
00246     // The operators are  encapsulated into an eoTRansform object, 
00247     // that performs sequentially crossover and mutation
00248     eoSGATransform<EoType> transform(xover, 0.75, mutation, 0.25);
00249 
00250     // The robust tournament selection
00251     eoDetTournamentSelect<EoType> selectOne(2);   // tSize in [2,POPSIZE]
00252     // is now encapsulated in a eoSelectMany: 2 at a time -> SteadyState
00253     eoSelectMany<EoType> select(selectOne,2, eo_is_an_integer);    
00254   
00255     // and the Steady-State replacement
00256     eoSSGAWorseReplacement<EoType> replace;
00257   
00258     // Terminators
00259     eoGenContinue<EoType> term(nGenerations);
00260 
00261     eoCheckPoint<EoType> checkPoint(term);
00262 
00263     eoAverageStat<EoType>     avg;
00264     eoBestFitnessStat<EoType> best;
00265     eoStdoutMonitor monitor;
00266 
00267     checkPoint.add(monitor);
00268     checkPoint.add(avg);
00269     checkPoint.add(best);
00270 
00271     monitor.add(avg);
00272     monitor.add(best);
00273 
00274     // GP generation
00275     eoEasyEA<EoType> gp(checkPoint, eval, select, transform, replace);
00276 
00277     std::cout << "Initialization done" << std::endl;
00278 
00279     print_best<EoType, FitnessType>(pop);
00280 
00281     try
00282     {
00283       gp(pop);
00284     }
00285     catch (std::exception& e)
00286     {
00287             std::cout << "exception: " << e.what() << std::endl;;
00288             exit(EXIT_FAILURE);
00289     }
00290 
00291     print_best<EoType, FitnessType>(pop);
00292 
00293 }
00294 
00295 

Generated on Thu Oct 19 05:06:44 2006 for EO by  doxygen 1.3.9.1