# 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