EvolvingObjects
|
#ifdef _MSC_VER #pragma warning(disable:4786) #endif #include <gp/eoParseTree.h> #include <eo> using namespace gp_parse_tree; using namespace std; //----------------------------------------------------------------------------- class SymregNode { public : enum Operator {X = 'x', Plus = '+', Min = '-', Mult = '*', PDiv = '/'}; SymregNode() { init(); } SymregNode(Operator _op) { op = _op; } virtual ~SymregNode() {} // arity function, need this function! int arity() const { return op == X? 0 : 2; } void randomize() {} // evaluation function, single case, using first argument to give value of variable template <class Children> void operator()(double& result, Children args, double var) const { double r1(0.), r2(0.); if (arity() == 2) { args[0].apply(r1, var); args[1].apply(r2, var); } switch (op) { case Plus : result = r1 + r2; break; case Min : result = r1 - r2; break; case Mult : result = r1 * r2; break; case PDiv : { if (r2 == 0.0) // protection a la Koza, realistic implementations // should maybe throw an exception result = 1.0; else result = r1 / r2; break; } case X : result = var; break; } } template <class Children> void operator()(string& result, Children args) const { static const string lb = "("; static const string rb = ")"; char opStr[4] = " "; opStr[1] = op; if (arity() == 0) { result = "x"; return; } // else string r1; args[0].apply(r1); result = lb + r1; result += opStr; args[1].apply(r1); result += r1 + rb; } Operator getOp() const { return op; } protected : void init() { op = X; } private : Operator op; // the type of node }; static SymregNode init_sequence[5] = {SymregNode::X, SymregNode::Plus, SymregNode::Min, SymregNode::Mult, SymregNode::PDiv}; // needed for intialization // MSVC does not recognize the lt_arity<Node> in eoParseTreeDepthInit // without this specialization ... // 2 months later, it seems it does not accept this definition ... // but dies accept the lt_arity<Node> in eoParseTreeDepthInit // !!! // #ifdef _MSC_VER // template <> // bool lt_arity(const SymregNode &node1, const SymregNode &node2) // { // return (node1.arity() < node2.arity()); // } // #endif //----------------------------------------------------------- // saving, loading std::ostream& operator<<(std::ostream& os, const SymregNode& eot) { os << static_cast<char>(eot.getOp()); return os; } std::istream& operator>>(std::istream& is, SymregNode& eot) { char type; type = (char) is.get(); eot = SymregNode(static_cast<SymregNode::Operator>(type)); return is; } //----------------------------------------------------------------------------- double targetFunction(double x) { return x * x * x * x - x * x * x + x * x * x - x * x + x - 10; } // parameters controlling the sampling of points const double xbegin = -10.0f; const double xend = 10.0f; const double xstep = 1.3f; template <class FType, class Node> struct RMS: public eoEvalFunc< eoParseTree<FType, Node> > { public : typedef eoParseTree<FType, Node> EoType; typedef eoParseTree<FType, Node> argument_type; typedef double fitness_type; RMS() : eoEvalFunc<EoType>() { int n = int( (xend - xbegin) / xstep); inputs.resize(n); target.resize(n); int i = 0; for (double x = xbegin; x < xend && i < n; ++i, x+=xstep) { target[i] = targetFunction(x); inputs[i] = x; } } ~RMS() {} void operator()( EoType & _eo ) { vector<double> outputs; outputs.resize(inputs.size()); double fitness = 0.0; for (unsigned i = 0; i < inputs.size(); ++i) { _eo.apply(outputs[i], inputs[i]); fitness += (outputs[i] - target[i]) * (outputs[i] - target[i]); } fitness /= (double) target.size(); fitness = sqrt(fitness); if (fitness > 1e+20) fitness = 1e+20; _eo.fitness(fitness); } private : vector<double> inputs; vector<double> target; }; template <class EOT, class FitnessType> void print_best(eoPop<EOT>& pop) { std::cout << std::endl; FitnessType best = pop[0].fitness(); int index = 0; for (unsigned i = 1; i < pop.size(); ++i) { if (best < pop[i].fitness()) { best = pop[i].fitness(); index = i; } } std::cout << "\t"; string str; pop[index].apply(str); std::cout << str.c_str(); std::cout << std::endl << "RMS Error = " << pop[index].fitness() << std::endl; } int main() { typedef eoMinimizingFitness FitnessType; typedef SymregNode GpNode; typedef eoParseTree<FitnessType, GpNode> EoType; typedef eoPop<EoType> Pop; const int MaxSize = 100; const int nGenerations = 10; // only a test, so few generations // Initializor sequence, contains the allowable nodes vector<GpNode> init(init_sequence, init_sequence + 5); // Depth Initializor, defaults to grow method. eoGpDepthInitializer<FitnessType, GpNode> initializer(10, init); // Root Mean Squared Error Measure RMS<FitnessType, GpNode> eval; Pop pop(50, initializer); apply<EoType>(eval, pop); eoSubtreeXOver<FitnessType, GpNode> xover(MaxSize); eoBranchMutation<FitnessType, GpNode> mutation(initializer, MaxSize); // The operators are encapsulated into an eoTRansform object, // that performs sequentially crossover and mutation eoSGATransform<EoType> transform(xover, 0.75, mutation, 0.25); // The robust tournament selection eoDetTournamentSelect<EoType> selectOne(2); // tSize in [2,POPSIZE] // is now encapsulated in a eoSelectMany: 2 at a time -> SteadyState eoSelectMany<EoType> select(selectOne,2, eo_is_an_integer); // and the Steady-State replacement eoSSGAWorseReplacement<EoType> replace; // Terminators eoGenContinue<EoType> term(nGenerations); eoCheckPoint<EoType> checkPoint(term); eoAverageStat<EoType> avg; eoBestFitnessStat<EoType> best; eoStdoutMonitor monitor; checkPoint.add(monitor); checkPoint.add(avg); checkPoint.add(best); monitor.add(avg); monitor.add(best); // GP generation eoEasyEA<EoType> gp(checkPoint, eval, select, transform, replace); std::cout << "Initialization done" << std::endl; print_best<EoType, FitnessType>(pop); try { gp(pop); } catch (std::exception& e) { std::cout << "exception: " << e.what() << std::endl;; exit(EXIT_FAILURE); } print_best<EoType, FitnessType>(pop); } // Local Variables: // coding: iso-8859-1 // mode: C++ // c-file-offsets: ((c . 0)) // c-file-style: "Stroustrup" // fill-column: 80 // End: