From 00c671f24c9de4b6fe453148fb7598b84c857f42 Mon Sep 17 00:00:00 2001 From: jeggermo Date: Thu, 28 Jun 2001 14:38:00 +0000 Subject: [PATCH] node.h containing Tree-node classes for symreg gp --- eo/app/gpsymreg/node.h | 247 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 eo/app/gpsymreg/node.h diff --git a/eo/app/gpsymreg/node.h b/eo/app/gpsymreg/node.h new file mode 100644 index 00000000..a3d8335b --- /dev/null +++ b/eo/app/gpsymreg/node.h @@ -0,0 +1,247 @@ +/* + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact: todos@geneura.ugr.es, http://geneura.ugr.es + jeggermo@liacs.nl +*/ + +#ifndef _NODE_H +#define _NODE_H + +#include +#include +#include // for finite(double) function + +using namespace gp_parse_tree; +using namespace std; + + +/* A new Operation and Node class for even more flexibility. + + Improvements over the t-eoSymreg code are: + + * No hardcoded functions or operators. The Operation and Node class below + allow you to specify your own unary and binary functions as well as + binary operators (like +,-,*,/). Moreover you can detemine if you want + to allow primitve subroutines with either one or two arguments. + + If a Node has a subroutine Operation it will take evaluate the first + (and possible second) child branch and use them as input variables for + the remaining second (or third) child branch. +*/ + + +typedef enum {Variable, UFunction, BFunction, BOperator, Const} Type; + + +struct Operation +{ + public: + + + typedef double (*BinaryFunction)(const double,const double); + typedef double (*UnaryFunction)(const double); + typedef unsigned int VariableID; + typedef string Label; + + + + union + { + UnaryFunction uFunction; + BinaryFunction bFunction; + VariableID id; + double constant; + }; + + + Label label; + Type type; + + // the default constructor results in a constant with value 0 + Operation() : constant(0), label("0"), type(Const){}; + // two possible constructors for Unary Functions + Operation(UnaryFunction _uf, Label _label): uFunction(_uf), label(_label), type(UFunction) {}; + Operation(Label _label, UnaryFunction _uf): uFunction(_uf), label(_label), type(UFunction) {}; + + // Watch out there are two constructors using pointers two binary functions: + // Binary Function (printed as label(subtree0,subtree1) (e.g. pow(x,y)) + // Binary Operator (printed as (subtree0 label subtree1) (e.g. x^y) + // The difference is purely cosmetic. + + // If you specify the label before the function pointer -> Binary Function + Operation(Label _label, BinaryFunction _bf): bFunction(_bf), label(_label), type(BFunction) {}; + // If you specify the function pointer before the label -> Binary Operator + Operation(BinaryFunction _bf, Label _label): bFunction(_bf), label(_label), type(BOperator) {}; + + // A constructor for variables + Operation(VariableID _id, Label _label): id(_id), label(_label), type(Variable) {}; + // A constructor for constants + Operation(double _constant, Label _label): constant(_constant), label(_label), type(Const) {}; + + + Operation(const Operation &_op) + { + switch(_op.type) + { + case Variable: id = _op.id; break; + case UFunction: uFunction = _op.uFunction; break; + case BFunction: bFunction = _op.bFunction; break; + case BOperator: bFunction = _op.bFunction; break; + case Const: constant = _op.constant; break; + } + type = _op.type; + label = _op.label; + }; + virtual ~Operation(){}; + +}; + + +class Node +{ + private: + Operation op; + + public: + + Node(void): op(Operation()){}; + Node(Operation &_op) : op(_op){}; + virtual ~Node(void) {} + + int arity(void) const + { + switch(op.type) + { + case Variable: return 0; + case UFunction: return 1; + case BFunction: return 2; + case BOperator: return 2; + case Const: return 0; + } + return 0; + } + + void randomize(void) {} + + template + void operator()(double& result, Children args, vector &var) const + { + double result0; + double result1; + + + switch(op.type) + { + case Variable: result = var[op.id%var.size()]; //%var.size() used in the case of Subroutines and as a security measure + break; + case UFunction: args[0].apply(result0, var); + result = op.uFunction(result0); + break; + case BFunction: + case BOperator: args[0].apply(result0, var); + args[1].apply(result1, var); + result = op.bFunction(result0,result1); + break; + case Const: result = op.constant; + break; + + } + + // if the result is infinite (positive or negative) or not_a_number (nan) then result becomes 0 + if (!finite(result)) + result=0; + } + + template + void Node::operator()(string& result, Children args) const + { + + string subtree0; + string subtree1; + string subtree2; + + switch(op.type) + { + + case Variable: + case Const: result += op.label; + break; + + case UFunction: result += op.label; + result += "("; + args[0].apply(subtree0); + result += subtree0; + result += ")"; + break; + case BFunction: result += op.label; + result += "("; + args[0].apply(subtree0); + result += subtree0; + result += ","; + args[1].apply(subtree1); + result += subtree1; + result += ")"; + break; + case BOperator: result += "("; + args[0].apply(subtree0); + result += subtree0; + result += op.label; + args[1].apply(subtree1); + result += subtree1; + result += ")"; + break; + default: result += "ERROR in Node::operator(string,...) \n"; break; + } + } + + Operation getOp(void) const {return op;} + +}; + + + + + + + + + + + +//----------------------------------------------------------- +// saving, loading LETS LEAVE IT OUT FOR NOW + + + +std::ostream& operator<<(std::ostream& os, const Node& eot) +{ + Operation op(eot.getOp()); + + os << (eot.getOp()).label; + return os; +} + + +// we can't load because we are using function pointers. Instead we prevent a compiler warning by calling the arity() function. +std::istream& operator>>(std::istream& is, Node& eot) +{ + eot.arity(); + return is; +} + + + +#endif