diff --git a/eo/test/t-eoSymreg.cpp b/eo/test/t-eoSymreg.cpp new file mode 100644 index 00000000..2dbe570e --- /dev/null +++ b/eo/test/t-eoSymreg.cpp @@ -0,0 +1,276 @@ +#pragma warning(disable:4786) + +#include "eoParseTree.h" +#include "eoEvalFunc.h" + +using namespace gp_parse_tree; +using namespace std; + +//----------------------------------------------------------------------------- + +class SymregNode +{ +public : + + enum Operator {X = 'x', Plus = '+', Min = '-', Mult = '*', PDiv = '/'}; + + SymregNode(void) { init(); } + SymregNode(Operator _op) { op = _op; } + virtual ~SymregNode(void) {} + + // arity function + int arity(void) const { return op == X? 0 : 2; } + + // evaluation function, single case, using first argument to give value of variable + template + double operator()(double var, Children args) const + { + switch (op) + { + case Plus : return args[0].apply(var) + args[1].apply(var); + case Min : return args[0].apply(var) - args[1].apply(var); + case Mult : return args[0].apply(var) * args[1].apply(var); + case PDiv : + { + double arg1 = args[1].apply(var); + if (arg1 == 0.0) + return 1.0; // protection a la Koza, realistic implementations should maybe throw an exception + + return args[0].apply(var) / arg1; + } + + case X : return var; + } + + return var; // to avoid compiler error + } + + /// 'Pretty' print to ostream function + template + string operator()(string dummy, Children args) + { + static const string lb = "("; + static const string rb = ")"; + char opStr[4] = " "; + opStr[1] = op; + + if (arity() == 0) + { + return string("x"); + } + // else + string result = lb + args[0].apply(dummy); + result += opStr; + result += args[1].apply(dummy) + rb; + return result; + } + + Operator getOp(void) const { return op; } + +protected : + + void init(void) { op = X; } + +private : + + Operator op; // the type of node +}; + +/// initializor +static SymregNode init_sequence[5] = {SymregNode::X, SymregNode::Plus, SymregNode::Min, SymregNode::Mult, SymregNode::PDiv}; // needed for intialization + +//----------------------------------------------------------- +// saving, loading + +std::ostream& operator<<(std::ostream& os, const SymregNode& eot) +{ + os << static_cast(eot.getOp()); + return os; +} + +std::istream& operator>>(std::istream& is, SymregNode& eot) +{ + char type; + type = (char) is.get(); + eot = SymregNode(static_cast(type)); + return is; +} + + +//----------------------------------------------------------------------------- +/** Implementation of a function evaluation object. */ + +float targetFunction(float x) +{ + return x * x * x * x - x * x * x + x * x * x - x * x + x - 1; +} + +// parameters controlling the sampling of points +const float xbegin = -10.0f; +const float xend = 10.0f; +const float xstep = 1.3f; + +template struct RMS: public eoEvalFunc< eoParseTree > +{ +public : + + typedef eoParseTree EoType; + + typedef eoParseTree argument_type; + typedef double fitness_type; + + RMS(void) : eoEvalFunc() + { + int n = int( (xend - xbegin) / xstep); + + inputs.resize(n); + target.resize(n); + + int i = 0; + + for (double x = xbegin; x < xend && i < n; ++i) + { + target[i] = targetFunction(x); + inputs[i] = x; + } + } + + ~RMS() {} + + void operator()( EoType & _eo ) const + { + vector outputs; + outputs.resize(inputs.size()); + + double fitness = 0.0; + + for (int i = 0; i < inputs.size(); ++i) + { + outputs[i] = _eo.apply(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 inputs; + vector target; +}; + +#include "eoTerm.h" + +template +class eoGenerationTerm : public eoTerm +{ + public : + eoGenerationTerm(size_t _ngen) : eoTerm(), ngen(_ngen) {} + + bool operator()(const eoPop&) + { + cout << '.'; // pacifier + cout.flush(); + + return --ngen > 0; + } + private : + unsigned ngen; +}; + +template +void print_best(eoPop& pop) +{ + cout << endl; + FitnessType best = pop[0].fitness(); + int index = 0; + + for (int i = 1; i < pop.size(); ++i) + { + if (best < pop[i].fitness()) + { + best = pop[i].fitness(); + index = i; + } + } + + cout << "\t"; + + string str = pop[index].apply(string()); + + cout << str.c_str(); + cout << endl << "Error = " << pop[index].fitness() << endl; +} + + +#include +#include "eoGOpBreeder.h" +#include "eoSequentialGOpSelector.h" +#include "eoProportionalGOpSelector.h" +#include "eoDetTournamentIndiSelector.h" +#include "eoDetTournamentInserter.h" +#include "eoSteadyStateEA.h" +#include "eoScalarFitness.h" + +void main() +{ + typedef eoScalarFitness > FitnessType; + typedef SymregNode GpNode; + + typedef eoParseTree EoType; + typedef eoPop Pop; + + const int MaxSize = 75; + const int nGenerations = 50; + + // Initializor sequence, contains the allowable nodes + vector init(init_sequence, init_sequence + 5); + + // Depth Initializor, defaults to grow method. + eoGpDepthInitializer initializer(10, init); + + // Root Mean Squared Error Measure + RMS eval; + + Pop pop(500, MaxSize, initializer, eval); + + eoSubtreeXOver xover(MaxSize); + eoBranchMutation mutation(initializer, MaxSize); + + eoSequentialGOpSel seqSel; + + seqSel.addOp(mutation, 0.25); + seqSel.addOp(xover, 0.75); + + eoDetTournamentIndiSelector selector(5); + + eoDetTournamentInserter inserter(eval, 5); + + // Terminators + eoGenerationTerm term(nGenerations); + + // GP generation + eoSteadyStateEA gp(seqSel, selector, inserter, term); + + cout << "Initialization done" << endl; + + print_best(pop); + + try + { + gp(pop); + } + catch (exception& e) + { + cout << "exception: " << e.what() << endl;; + exit(EXIT_FAILURE); + } + + print_best(pop); +} +