Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | Related Pages | Search for

# node.h

    00001 /*
    00002     This library is free software; you can redistribute it and/or modify
    00003     it under the terms of the GNU General Public License as published by
    00004     the Free Software Foundation; either version 2 of the License, or
    00005     (at your option) any later version.
    00006
    00007     This library is distributed in the hope that it will be useful,
    00008     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00009     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00010     Lesser General Public License for more details.
    00011
    00012     You should have received a copy of the GNU General Public License
    00013     along with this library; if not, write to the Free Software
    00014     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00015
    00016     Contact: todos@geneura.ugr.es, http://geneura.ugr.es
    00017              jeggermo@liacs.nl
    00018 */
    00019
    00020 #ifndef _NODE_H
    00021 #define _NODE_H
    00022
    00023
    00024
    00025 #include <iostream>
    00026 #include <string>
    00027 #include <cmath> // for finite(double) function
    00028
    00029 using namespace gp_parse_tree;
    00030 using namespace std;
    00031
    00032
    00033 /* A new Operation and Node class for even more flexibility.
    00034
    00035    Improvements over the t-eoSymreg code are:
    00036
    00037    * No hardcoded functions or operators. The Operation and Node class below
    00038      allow you to specify your own unary and binary functions as well as
    00039      binary operators (like +,-,*,/). Moreover you can detemine if you want
    00040      to allow primitve subroutines with either one or two arguments.
    00041
    00042      If a Node has a subroutine Operation it will take evaluate the first
    00043      (and possible second) child branch and use them as input variables for
    00044      the remaining second (or third) child branch.
    00045 */
    00046
    00047
    00048 typedef enum {Variable, UFunction, BFunction, BOperator, Const} Type;
    00049
    00050 typedef double (*BinaryFunction)(const double,const double);
    00051 typedef double (*UnaryFunction)(const double);
    00052
    00053 struct Operation
    00054 {
    00055         public:
    00056
    00057                 typedef unsigned int VariableID;
    00058                 typedef string Label;
    00059
    00060
    00061                 // if your compiler allows you to have nameless unions you can make this a
    00062                 // union by removing the //'s below
    00063
    00064                 //union
    00065                 //{
    00066                         UnaryFunction uFunction;
    00067                         BinaryFunction bFunction;
    00068                         VariableID id;
    00069                         double constant;
    00070                 //};
    00071
    00072
    00073
    00074                 Label label;
    00075                 Type type;
    00076
    00077                 // the default constructor results in a constant with value 0
    00078                 Operation() : constant(0),  label("0"), type(Const){};
    00079                 // two possible constructors for Unary Functions
    00080                 Operation(UnaryFunction _uf, Label _label): uFunction(_uf), label(_label), type(UFunction) {};
    00081                 Operation(Label _label, UnaryFunction _uf): uFunction(_uf), label(_label), type(UFunction) {};
    00082
    00083                 // Watch out there are two constructors using pointers two binary functions:
    00084                 // Binary Function (printed as label(subtree0,subtree1)  (e.g. pow(x,y))
    00085                 // Binary Operator (printed as (subtree0 label subtree1) (e.g. x^y)
    00086                 // The difference is purely cosmetic.
    00087
    00088                 // If you specify the label before the function pointer -> Binary Function
    00089                 Operation(Label _label, BinaryFunction _bf): bFunction(_bf), label(_label), type(BFunction) {};
    00090                 // If you specify the function pointer before the label -> Binary Operator
    00091                 Operation(BinaryFunction _bf, Label _label): bFunction(_bf), label(_label), type(BOperator) {};
    00092
    00093                 // A constructor for variables
    00094                 Operation(VariableID _id, Label _label): id(_id), label(_label), type(Variable) {};
    00095                 // A constructor for constants
    00096                 Operation(double _constant, Label _label): constant(_constant), label(_label), type(Const) {};
    00097
    00098
    00099                 Operation(const Operation &_op)
    00100                 {
    00101                         switch(_op.type)
    00102                         {
    00103                                 case Variable: id = _op.id; break;
    00104                                 case UFunction: uFunction = _op.uFunction;  break;
    00105                                 case BFunction: bFunction = _op.bFunction; break;
    00106                                 case BOperator: bFunction = _op.bFunction; break;
    00107                                 case Const: constant = _op.constant;  break;
    00108                         }
    00109                         type = _op.type;
    00110                         label = _op.label;
    00111                 };
    00112                 virtual ~Operation(){};
    00113
    00114 };
    00115
    00116
    00117 class Node
    00118 {
    00119         private:
    00120                 Operation op;
    00121
    00122         public:
    00123
    00124                 Node(void): op(Operation()){};
    00125                 Node(Operation &_op) : op(_op){};
    00126                 virtual ~Node(void) {}
    00127
    00128                 int arity(void) const
    00129                 {
    00130                         switch(op.type)
    00131                         {
    00132                                 case Variable: return 0;
    00133                                 case UFunction: return 1;
    00134                                 case BFunction: return 2;
    00135                                 case BOperator: return 2;
    00136                                 case Const: return 0;
    00137                         }
    00138                         return 0;
    00139                 }
    00140
    00141                 void randomize(void) {}
    00142
    00143                 template<class Children>
    00144                 void operator()(double& result, Children args, vector<double> &var) const
    00145                 {
    00146                         double result0;
    00147                         double result1;
    00148
    00149
    00150                         switch(op.type)
    00151                         {
    00152                                 case Variable:  result = var[op.id%var.size()]; //%var.size() used in the case of Subroutines and as a security measure
    00153                                                 break;
    00154                                 case UFunction: args[0].apply(result0, var);
    00155                                                 result = op.uFunction(result0);
    00156                                                 break;
    00157                                 case BFunction:
    00158                                 case BOperator: args[0].apply(result0, var);
    00159                                                 args[1].apply(result1, var);
    00160                                                 result = op.bFunction(result0,result1);
    00161                                                 break;
    00162                                 case Const:     result = op.constant;
    00163                                                 break;
    00164
    00165                         }
    00166
    00167                 }
    00168
    00169                 template<class Children>
    00170                 void operator()(string& result, Children args) const
    00171                 {
    00172
    00173                         string subtree0;
    00174                         string subtree1;
    00175                         string subtree2;
    00176
    00177                         switch(op.type)
    00178                         {
    00179
    00180                                 case Variable:
    00181                                 case Const:     result += op.label;
    00182                                                 break;
    00183
    00184                                 case UFunction: result += op.label;
    00185                                                 result += "(";
    00186                                                 args[0].apply(subtree0);
    00187                                                 result += subtree0;
    00188                                                 result += ")";
    00189                                                 break;
    00190                                 case BFunction: result += op.label;
    00191                                                 result += "(";
    00192                                                 args[0].apply(subtree0);
    00193                                                 result += subtree0;
    00194                                                 result += ",";
    00195                                                 args[1].apply(subtree1);
    00196                                                 result += subtree1;
    00197                                                 result += ")";
    00198                                                 break;
    00199                                 case BOperator: result += "(";
    00200                                                 args[0].apply(subtree0);
    00201                                                 result += subtree0;
    00202                                                 result += op.label;
    00203                                                 args[1].apply(subtree1);
    00204                                                 result += subtree1;
    00205                                                 result += ")";
    00206                                                 break;
    00207                                 default: result += "ERROR in Node::operator(string,...) \n"; break;
    00208                         }
    00209                 }
    00210
    00211                 Operation getOp(void) const {return op;}
    00212
    00213 };
    00214
    00215
    00216
    00217
    00218
    00219
    00220
    00221
    00222
    00223
    00224
    00225 //-----------------------------------------------------------
    00226 // saving, loading LETS LEAVE IT OUT FOR NOW
    00227
    00228
    00229
    00230 std::ostream& operator<<(std::ostream& os, const Node& eot)
    00231 {
    00232     Operation op(eot.getOp());
    00233
    00234     os << (eot.getOp()).label;
    00235     return os;
    00236 }
    00237
    00238
    00239 // we can't load because we are using function pointers. Instead we prevent a compiler warning by calling the arity() function.
    00240 std::istream& operator>>(std::istream& is, Node& eot)
    00241 {
    00242     eot.arity();
    00243     return is;
    00244 }
    00245
    00246
    00247
    00248 #endif