Paradiseo-eo sources added
git-svn-id: svn://scm.gforge.inria.fr/svnroot/paradiseo@40 331e1502-861f-0410-8da2-ba01fb791d7f
This commit is contained in:
parent
bc1f453978
commit
c3aec878e5
3609 changed files with 342772 additions and 0 deletions
6
trunk/paradiseo-eo/src/gp/.cvsignore
Normal file
6
trunk/paradiseo-eo/src/gp/.cvsignore
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
10
trunk/paradiseo-eo/src/gp/CVS/Entries
Normal file
10
trunk/paradiseo-eo/src/gp/CVS/Entries
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/.cvsignore/1.1/Mon Apr 3 09:32:08 2000//
|
||||
/Makefile.am/1.5/Wed Sep 22 18:18:30 2004//
|
||||
/eoParseTree.h/1.25/Mon Mar 27 18:55:20 2006//
|
||||
/eoParseTreeDepthInit.h/1.9/Wed Nov 26 11:15:59 2003//
|
||||
/eoParseTreeOp.h/1.4/Thu Feb 27 19:24:31 2003//
|
||||
/eoStParseTreeDepthInit.h/1.4/Thu Feb 27 19:24:31 2003//
|
||||
/eoStParseTreeOp.h/1.2/Thu Feb 27 19:24:31 2003//
|
||||
/node_pool.h/1.4/Tue Mar 25 10:46:08 2003//
|
||||
/parse_tree.h/1.8/Thu Dec 23 15:29:06 2004//
|
||||
D
|
||||
1
trunk/paradiseo-eo/src/gp/CVS/Repository
Normal file
1
trunk/paradiseo-eo/src/gp/CVS/Repository
Normal file
|
|
@ -0,0 +1 @@
|
|||
eo/src/gp
|
||||
1
trunk/paradiseo-eo/src/gp/CVS/Root
Normal file
1
trunk/paradiseo-eo/src/gp/CVS/Root
Normal file
|
|
@ -0,0 +1 @@
|
|||
:ext:evomarc@eodev.cvs.sourceforge.net:/cvsroot/eodev
|
||||
11
trunk/paradiseo-eo/src/gp/Makefile.am
Normal file
11
trunk/paradiseo-eo/src/gp/Makefile.am
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
## Makefile.am for eo/src/gp
|
||||
|
||||
gpincludedir = $(pkgincludedir)/gp
|
||||
|
||||
gpinclude_HEADERS = eoParseTreeDepthInit.h \
|
||||
eoParseTree.h \
|
||||
eoParseTreeOp.h \
|
||||
eoStParseTreeDepthInit.h \
|
||||
eoStParseTreeOp.h \
|
||||
node_pool.h \
|
||||
parse_tree.h
|
||||
189
trunk/paradiseo-eo/src/gp/eoParseTree.h
Normal file
189
trunk/paradiseo-eo/src/gp/eoParseTree.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoParseTree.h : eoParseTree class (for Tree-based Genetic Programming)
|
||||
// (c) Maarten Keijzer 2000
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser 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 Lesser 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
|
||||
mak@dhi.dk
|
||||
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef eoParseTree_h
|
||||
#define eoParseTree_h
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
|
||||
#include <EO.h>
|
||||
#include <eoInit.h>
|
||||
#include <eoOp.h>
|
||||
#include <gp/parse_tree.h>
|
||||
|
||||
using namespace gp_parse_tree;
|
||||
|
||||
/** @defgroup ParseTree
|
||||
|
||||
Various functions for tree-based Genetic Programming
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/** Implementation of parse-tree for genetic programming
|
||||
|
||||
@class eoParseTree eoParseTree.h gp/eoParseTree.h
|
||||
|
||||
@ingroup ParseTree
|
||||
*/
|
||||
template <class FType, class Node>
|
||||
class eoParseTree : public EO<FType>, public parse_tree<Node>
|
||||
{
|
||||
public:
|
||||
|
||||
using parse_tree<Node>::back;
|
||||
using parse_tree<Node>::ebegin;
|
||||
using parse_tree<Node>::eend;
|
||||
using parse_tree<Node>::size;
|
||||
|
||||
|
||||
typedef typename parse_tree<Node>::subtree Subtree;
|
||||
|
||||
/* For Compatibility with the intel C++ compiler for Linux 5.x */
|
||||
typedef Node reference;
|
||||
typedef const reference const_reference;
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
eoParseTree(void) {}
|
||||
|
||||
/**
|
||||
* Copy Constructor
|
||||
* @param tree The tree to copy
|
||||
*/
|
||||
eoParseTree(const parse_tree<Node>& tree) : parse_tree<Node>(tree) {}
|
||||
|
||||
// eoParseTree(const eoParseTree<FType, Node>& tree) : parse_tree<Node>(tree) {}
|
||||
/**
|
||||
* To prune me to a certain size
|
||||
* @param _size My maximum size
|
||||
*/
|
||||
virtual void pruneTree(unsigned _size)
|
||||
{
|
||||
if (_size < 1)
|
||||
return;
|
||||
|
||||
while (size() > _size)
|
||||
{
|
||||
back() = operator[](size()-2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To read me from a stream
|
||||
* @param is The std::istream
|
||||
*/
|
||||
|
||||
eoParseTree(std::istream& is) : EO<FType>(), parse_tree<Node>()
|
||||
{
|
||||
readFrom(is);
|
||||
}
|
||||
|
||||
/// My class name
|
||||
std::string className(void) const { return "eoParseTree"; }
|
||||
|
||||
/**
|
||||
* To print me on a stream
|
||||
* @param os The std::ostream
|
||||
*/
|
||||
void printOn(std::ostream& os) const
|
||||
{
|
||||
EO<FType>::printOn(os);
|
||||
os << ' ';
|
||||
|
||||
os << size() << ' ';
|
||||
|
||||
std::copy(ebegin(), eend(), std::ostream_iterator<Node>(os, " "));
|
||||
}
|
||||
|
||||
/**
|
||||
* To read me from a stream
|
||||
* @param is The std::istream
|
||||
*/
|
||||
void readFrom(std::istream& is)
|
||||
{
|
||||
|
||||
|
||||
EO<FType>::readFrom(is);
|
||||
|
||||
unsigned sz;
|
||||
is >> sz;
|
||||
|
||||
|
||||
std::vector<Node> v(sz);
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sz; ++i)
|
||||
{
|
||||
Node node;
|
||||
is >> node;
|
||||
v[i] = node;
|
||||
}
|
||||
parse_tree<Node> tmp(v.begin(), v.end());
|
||||
swap(tmp);
|
||||
|
||||
/*
|
||||
* old code which caused problems for paradisEO
|
||||
*
|
||||
* this can be removed once it has proved itself
|
||||
EO<FType>::readFrom(is);
|
||||
|
||||
// even older code
|
||||
FType fit;
|
||||
is >> fit;
|
||||
|
||||
fitness(fit);
|
||||
|
||||
|
||||
std::copy(std::istream_iterator<Node>(is), std::istream_iterator<Node>(), back_inserter(*this));
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
// friend function to print eoParseTree
|
||||
template <class FType, class Node>
|
||||
std::ostream& operator<<(std::ostream& os, const eoParseTree<FType, Node>& eot)
|
||||
{
|
||||
eot.printOn(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
// friend function to read eoParseTree
|
||||
template <class FType, class Node>
|
||||
std::istream& operator>>(std::istream& is, eoParseTree<FType, Node>& eot)
|
||||
{
|
||||
eot.readFrom(is);
|
||||
return is;
|
||||
}
|
||||
|
||||
// for backward compatibility
|
||||
#include <gp/eoParseTreeOp.h>
|
||||
#include <gp/eoParseTreeDepthInit.h>
|
||||
|
||||
#endif
|
||||
218
trunk/paradiseo-eo/src/gp/eoParseTreeDepthInit.h
Normal file
218
trunk/paradiseo-eo/src/gp/eoParseTreeDepthInit.h
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoParseTreeDepthInit.h : initializor for eoParseTree class
|
||||
// (c) Maarten Keijzer 2000 Jeroen Eggermont 2002
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser 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 Lesser 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
|
||||
mak@dhi.dk
|
||||
jeggermo@liacs.nl
|
||||
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef eoParseTreeDepthInit_h
|
||||
#define eoParseTreeDepthInit_h
|
||||
|
||||
#include <EO.h>
|
||||
#include <gp/eoParseTree.h>
|
||||
#include <eoInit.h>
|
||||
#include <eoOp.h>
|
||||
#include <eoPop.h>
|
||||
|
||||
using namespace gp_parse_tree;
|
||||
|
||||
/** eoParseTreeDepthInit : the initializer class for eoParseTree
|
||||
\class eoParseTreeDepthInit eoParseTreeDepthInit.h gp/eoParseTreeDepthInit.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
|
||||
// eoGpDepthInitializer is defined for backward compatibility
|
||||
#define eoGpDepthInitializer eoParseTreeDepthInit
|
||||
|
||||
template <class FType, class Node>
|
||||
class eoParseTreeDepthInit : public eoInit< eoParseTree<FType, Node> >
|
||||
{
|
||||
protected:
|
||||
// a binary predicate for sorting
|
||||
// hopefully this will work with M$VC++ 6.0
|
||||
struct lt_arity:public std::binary_function<Node,Node,bool>
|
||||
{
|
||||
bool operator()(const Node &_node1, const Node &_node2) { return (_node1.arity() < _node2.arity());};
|
||||
};
|
||||
|
||||
public :
|
||||
|
||||
typedef eoParseTree<FType, Node> EoType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @parm _max_depth The maximum depth of a tree
|
||||
* @param _initializor A std::vector containing the possible nodes
|
||||
* @param _grow False results in a full tree, True result is a randomly grown tree
|
||||
* @param _ramped_half_and_half True results in Ramped Half and Half Initialization
|
||||
*/
|
||||
eoParseTreeDepthInit(
|
||||
unsigned _max_depth,
|
||||
const std::vector<Node>& _initializor,
|
||||
bool _grow = true,
|
||||
bool _ramped_half_and_half = false)
|
||||
:
|
||||
eoInit<EoType>(),
|
||||
max_depth(_max_depth),
|
||||
initializor(_initializor),
|
||||
grow(_grow),
|
||||
ramped_half_and_half(_ramped_half_and_half),
|
||||
current_depth(_max_depth)
|
||||
{
|
||||
if(initializor.empty())
|
||||
{
|
||||
throw std::logic_error("eoParseTreeDepthInit: uhm, wouldn't you rather give a non-empty set of Nodes?");
|
||||
}
|
||||
// lets sort the initializor std::vector according to arity (so we can be sure the terminals are in front)
|
||||
// we use stable_sort so that if element i was in front of element j and they have the same arity i remains in front of j
|
||||
stable_sort(initializor.begin(), initializor.end(), lt_arity());
|
||||
}
|
||||
/// My class name
|
||||
virtual std::string className() const { return "eoParseTreeDepthInit"; };
|
||||
|
||||
/**initialize a tree
|
||||
* @param _tree : the tree to be initialized
|
||||
*/
|
||||
void operator()(EoType& _tree)
|
||||
{
|
||||
std::list<Node> sequence;
|
||||
generate(sequence, current_depth);
|
||||
|
||||
parse_tree<Node> tmp(sequence.begin(), sequence.end());
|
||||
_tree.swap(tmp);
|
||||
|
||||
if(ramped_half_and_half)
|
||||
{
|
||||
if(grow)
|
||||
{
|
||||
if (current_depth > 2)
|
||||
current_depth--;
|
||||
else
|
||||
current_depth = max_depth;
|
||||
}
|
||||
// change the grow method from 'grow' to 'full' or from 'full' to 'grow'
|
||||
grow = !grow;
|
||||
};
|
||||
|
||||
}
|
||||
private :
|
||||
void generate(std::list<Node>& sequence, int the_max, int last_terminal = -1)
|
||||
{
|
||||
if (last_terminal == -1)
|
||||
{ // check where the last terminal in the sequence resides
|
||||
typename std::vector<Node>::iterator it;
|
||||
for (it = initializor.begin(); it != initializor.end(); ++it)
|
||||
{
|
||||
if (it->arity() > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
last_terminal = it - initializor.begin();
|
||||
}
|
||||
|
||||
if (the_max == 1)
|
||||
{ // generate terminals only
|
||||
typename std::vector<Node>::iterator it = initializor.begin() + rng.random(last_terminal);
|
||||
it->randomize();
|
||||
sequence.push_front(*it);
|
||||
return;
|
||||
}
|
||||
|
||||
typename std::vector<Node>::iterator what_it;
|
||||
|
||||
if (grow)
|
||||
{
|
||||
what_it = initializor.begin() + rng.random(initializor.size());
|
||||
}
|
||||
else // full
|
||||
{
|
||||
what_it = initializor.begin() + last_terminal + rng.random(initializor.size() - last_terminal);
|
||||
}
|
||||
|
||||
what_it->randomize();
|
||||
|
||||
sequence.push_front(*what_it);
|
||||
|
||||
for (int i = 0; i < what_it->arity(); ++i)
|
||||
generate(sequence, the_max - 1, last_terminal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned max_depth;
|
||||
std::vector<Node> initializor;
|
||||
bool grow;
|
||||
bool ramped_half_and_half;
|
||||
unsigned current_depth;
|
||||
};
|
||||
|
||||
/**
|
||||
* A template function for ramped half and half initialization of an eoParseTree population
|
||||
* @param pop the population to be created
|
||||
* @param population_size the size of the population to be created
|
||||
* @param init_max_depth the initial maximum tree depth
|
||||
* @param initializor A std::vector containing the possible nodes
|
||||
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
template <class FType, class Node>
|
||||
void eoInitRampedHalfAndHalf(eoPop< eoParseTree<FType,Node> > &pop, unsigned int population_size, unsigned int init_max_depth, std::vector<Node> &initializor)
|
||||
{
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
typedef eoPop< EoType > Pop;
|
||||
|
||||
unsigned int M = init_max_depth - 1;
|
||||
unsigned int part_pop_size = population_size / (2*M);
|
||||
unsigned int m=0;
|
||||
|
||||
std::cerr << "EO WARNING: Ramped Half and Half Initialization is now supported by eoParseTreeDepthInit." << std::endl;
|
||||
std::cerr << " This function is now obsolete and might be removed in the future so you should"<< std::endl;
|
||||
std::cerr << " update your code to use: " << std::endl << std::endl;
|
||||
std::cerr << " eoParseTreeDepthInit( _max_depth, _initializer, bool _grow, bool _ramped_half_and_half)" << std::endl << std::endl;
|
||||
|
||||
pop.clear();
|
||||
|
||||
// initialize with Depth's (D) -> 2
|
||||
for(m=init_max_depth; m >= 2; m--)
|
||||
{
|
||||
eoParseTreeDepthInit<FType, Node> grow_initializer(m, initializor, true);
|
||||
Pop grow(part_pop_size, grow_initializer);
|
||||
pop.insert(pop.begin(), grow.begin(), grow.end());
|
||||
|
||||
eoParseTreeDepthInit<FType, Node> full_initializer(m, initializor, false);
|
||||
Pop full(part_pop_size, full_initializer);
|
||||
pop.insert(pop.begin(), full.begin(), full.end());
|
||||
}
|
||||
|
||||
bool g = true;
|
||||
while (pop.size() < population_size)
|
||||
{
|
||||
eoParseTreeDepthInit<FType, Node> initializer(init_max_depth, initializor, g);
|
||||
Pop p(1, initializer);
|
||||
pop.insert(pop.begin(), p.begin(), p.end());
|
||||
g= !g;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
380
trunk/paradiseo-eo/src/gp/eoParseTreeOp.h
Normal file
380
trunk/paradiseo-eo/src/gp/eoParseTreeOp.h
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoParseTreeOp.h : crossover and mutation operator for the eoParseTree class
|
||||
// (c) Maarten Keijzer 2000 for eoSubtreeXOver, eoBranchMutation
|
||||
// (c) Jeroen Eggermont 2001 for other mutation operators
|
||||
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser 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 Lesser 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
|
||||
mak@dhi.dk
|
||||
jeggermo@liacs.nl
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef eoParseTreeOp_h
|
||||
#define eoParseTreeOp_h
|
||||
|
||||
#include <EO.h>
|
||||
#include <eoOp.h>
|
||||
|
||||
#include <gp/eoParseTree.h>
|
||||
|
||||
/** eoSubtreeXOver --> subtree xover
|
||||
\class eoSubtreeXOver eoParseTreeOp.h gp/eoParseTreeOp.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
template<class FType, class Node>
|
||||
class eoSubtreeXOver: public eoQuadOp< eoParseTree<FType, Node> > {
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoSubtreeXOver( unsigned _max_length)
|
||||
: eoQuadOp<EoType>(), max_length(_max_length) {};
|
||||
|
||||
/// the ckassname
|
||||
virtual std::string className() const { return "eoSubtreeXOver"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoSubtreeXOver () {};
|
||||
|
||||
/**
|
||||
* Perform crossover on two individuals
|
||||
* param _eo1 The first parent individual
|
||||
* param _eo2 The second parent individual
|
||||
*/
|
||||
bool operator()(EoType & _eo1, EoType & _eo2 )
|
||||
{
|
||||
int i = rng.random(_eo1.size());
|
||||
int j = rng.random(_eo2.size());
|
||||
|
||||
typename parse_tree<Node>::subtree tmp = _eo1[i];
|
||||
_eo1[i] = _eo2[j]; // insert subtree
|
||||
_eo2[j] = tmp;
|
||||
|
||||
_eo1.pruneTree(max_length);
|
||||
_eo2.pruneTree(max_length);
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
unsigned max_length;
|
||||
};
|
||||
|
||||
/** eoBranchMutation --> replace a subtree with a randomly created subtree
|
||||
\class eoBranchMutation eoParseTreeOp.h gp/eoParseTreeOp.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
template<class FType, class Node>
|
||||
class eoBranchMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _init An instantiation of eoGpDepthInitializer
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoBranchMutation(eoInit<EoType>& _init, unsigned _max_length)
|
||||
: eoMonOp<EoType>(), max_length(_max_length), initializer(_init)
|
||||
{};
|
||||
|
||||
/// the class name
|
||||
virtual std::string className() const { return "eoBranchMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoBranchMutation() {};
|
||||
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
int i = rng.random(_eo1.size());
|
||||
|
||||
EoType eo2;
|
||||
initializer(eo2);
|
||||
|
||||
int j = rng.random(eo2.size());
|
||||
|
||||
_eo1[i] = eo2[j]; // insert subtree
|
||||
|
||||
_eo1.pruneTree(max_length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_length;
|
||||
eoInit<EoType>& initializer;
|
||||
};
|
||||
|
||||
// Additional Mutation operators from
|
||||
// TITLE:"Genetic Programming~An Introduction"
|
||||
// AUTHORS: Banzhaf, Nordin, Keller, Francone
|
||||
// ISBN: 3-920993-58-6
|
||||
// ISBN: 1-55860-510-X
|
||||
//
|
||||
// For the eoParseTree class
|
||||
|
||||
/** eoPointMutation --> replace a Node with a Node of the same arity
|
||||
\class eoPointMutation eoParseTreeOp.h gp/eoParseTreeOp.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
|
||||
template<class FType, class Node>
|
||||
class eoPointMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param _initializor The std::vector of Nodes given to the eoGpDepthInitializer
|
||||
*/
|
||||
eoPointMutation( std::vector<Node>& _initializor)
|
||||
: eoMonOp<EoType>(), initializor(_initializor)
|
||||
{};
|
||||
|
||||
/// the class name
|
||||
virtual std::string className() const { return "eoPointMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoPointMutation() {};
|
||||
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
// select a random node i that is to be mutated
|
||||
int i = rng.random(_eo1.size());
|
||||
// request the arity of the node that is to be replaced
|
||||
int arity = _eo1[i].arity();
|
||||
|
||||
int j=0;
|
||||
|
||||
do
|
||||
{
|
||||
j = rng.random(initializor.size());
|
||||
|
||||
}while ((initializor[j].arity() != arity));
|
||||
|
||||
_eo1[i] = initializor[j];
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
std::vector<Node>& initializor;
|
||||
|
||||
};
|
||||
|
||||
/** eoExpansionMutation --> replace a terminal with a randomly created subtree
|
||||
\class eoExpansionMutation eoParseTreeOp.h gp/eoParseTreeOp.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
|
||||
template<class FType, class Node>
|
||||
class eoExpansionMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType, Node> EoType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param _init An instantiation of eoGpDepthInitializer
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoExpansionMutation(eoInit<EoType>& _init, unsigned _max_length)
|
||||
: eoMonOp<EoType>(), max_length(_max_length), initializer(_init)
|
||||
{};
|
||||
|
||||
/// The class name
|
||||
virtual std::string className() const { return "eoExpansionMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoExpansionMutation() {};
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
int i = rng.random(_eo1.size());
|
||||
// look for a terminal
|
||||
while (_eo1[i].arity() != 0)
|
||||
{
|
||||
i= rng.random(_eo1.size());
|
||||
};
|
||||
|
||||
// create a new tree to
|
||||
EoType eo2;
|
||||
// make sure we get a tree with more than just a terminal
|
||||
do
|
||||
{
|
||||
initializer(eo2);
|
||||
}while(eo2.size() == 1);
|
||||
|
||||
int j = rng.random(eo2.size());
|
||||
// make sure we select a subtree (and not a terminal)
|
||||
while((eo2[j].arity() == 0))
|
||||
{
|
||||
j = rng.random(eo2.size());
|
||||
};
|
||||
|
||||
|
||||
_eo1[i] = eo2[j]; // insert subtree
|
||||
|
||||
_eo1.pruneTree(max_length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_length;
|
||||
eoInit<EoType>& initializer;
|
||||
};
|
||||
|
||||
/** eoCollapseSubtree --> replace a subtree with a randomly chosen terminal
|
||||
\class eoCollapseSubtreeMutation eoParseTreeOp.h gp/eoParseTreeOp.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
|
||||
template<class FType, class Node>
|
||||
class eoCollapseSubtreeMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _init An instantiation of eoGpDepthInitializer
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoCollapseSubtreeMutation(eoInit<EoType>& _init, unsigned _max_length)
|
||||
: eoMonOp<EoType>(), max_length(_max_length), initializer(_init)
|
||||
{};
|
||||
|
||||
/// The class name
|
||||
virtual std::string className() const { return "eoCollapseSubtreeMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoCollapseSubtreeMutation() {};
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
int i = rng.random(_eo1.size());
|
||||
// look for a subtree
|
||||
while ((_eo1[i].arity() == 0) && (_eo1.size() > 1))
|
||||
{
|
||||
i= rng.random(_eo1.size());
|
||||
};
|
||||
|
||||
// create a new tree to
|
||||
EoType eo2;
|
||||
initializer(eo2);
|
||||
|
||||
int j = rng.random(eo2.size());
|
||||
// make sure we select a subtree (and not a terminal)
|
||||
while(eo2[j].arity() != 0)
|
||||
{
|
||||
j = rng.random(eo2.size());
|
||||
};
|
||||
|
||||
_eo1[i] = eo2[j]; // insert subtree
|
||||
|
||||
// we don't have to prune because the subtree is always smaller
|
||||
_eo1.pruneTree(max_length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_length;
|
||||
eoInit<EoType>& initializer;
|
||||
};
|
||||
|
||||
|
||||
/** eoHoistMutation --> replace the individual with one of its subtree's
|
||||
\class eoHoistMutation eoParseTreeOp.h gp/eoParseTreeOp.h
|
||||
\ingroup ParseTree
|
||||
*/
|
||||
|
||||
template<class FType, class Node>
|
||||
class eoHoistMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param none
|
||||
*/
|
||||
eoHoistMutation()
|
||||
: eoMonOp<EoType>()
|
||||
{};
|
||||
|
||||
/// The class name
|
||||
virtual std::string className() const { return "eoHoistMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoHoistMutation() {};
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
|
||||
|
||||
// select a hoist point
|
||||
int i = rng.random(_eo1.size());
|
||||
// and create a new tree
|
||||
EoType eo2(_eo1[i]);
|
||||
|
||||
// we don't have to prune because the new tree is always smaller
|
||||
//_eo1.pruneTree(max_length);
|
||||
|
||||
_eo1 = eo2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
190
trunk/paradiseo-eo/src/gp/eoStParseTreeDepthInit.h
Normal file
190
trunk/paradiseo-eo/src/gp/eoStParseTreeDepthInit.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoStParseTreeDepthInit.h : initializor strongly type GP
|
||||
// (c) Jeroen Eggermont 2001
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser 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 Lesser 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 eoStParseTreeDepthInit_h
|
||||
#define eoStParseTreeDepthInit_h
|
||||
|
||||
#include <EO.h>
|
||||
#include <gp/eoParseTree.h>
|
||||
#include <eoInit.h>
|
||||
#include <eoOp.h>
|
||||
|
||||
|
||||
using namespace gp_parse_tree;
|
||||
|
||||
#define TERMINAL 0
|
||||
|
||||
#define NONTERMINAL 4
|
||||
#define ALL 5
|
||||
|
||||
/**
|
||||
\defgroup StParseTree
|
||||
|
||||
Various functions for strongly typed tree-based Genetic Programming.
|
||||
The StParseTree functions use the same eoParseTree class for the
|
||||
individual but now each node class must have two additional functions.
|
||||
\li int type(void) which returns the return type of the node
|
||||
\li int type(int child) which returns the required type for child 0, 1 or 2
|
||||
|
||||
Pruning strongly typed trees is not possible at the moment.
|
||||
*/
|
||||
|
||||
/** eoStParseTreeDepthInit : the initializer class for strongly typed tree-based genetic programming
|
||||
\class eoStParseTreeDepthInit eoStParseTreeDepthInit.h gp/eoStParseTreeDepthInit.h
|
||||
\ingroup StParseTree
|
||||
*/
|
||||
|
||||
template <class FType, class Node>
|
||||
class eoStParseTreeDepthInit : public eoInit< eoParseTree<FType, Node> >
|
||||
{
|
||||
public :
|
||||
|
||||
typedef eoParseTree<FType, Node> EoType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @parm _max_depth The maximum depth of a tree
|
||||
* @param _initializor A std::vector containing the possible nodes
|
||||
* @param _grow False results in a full tree, True result is a randomly grown tree
|
||||
*/
|
||||
eoStParseTreeDepthInit(
|
||||
unsigned _max_depth,
|
||||
const std::vector<Node>& _node,
|
||||
const int& _return_type,
|
||||
bool _grow = true)
|
||||
:
|
||||
eoInit<EoType>(),
|
||||
max_depth(_max_depth),
|
||||
return_type(_return_type),
|
||||
grow(_grow)
|
||||
{
|
||||
if(_node.empty())
|
||||
{
|
||||
throw std::logic_error("eoStParseTreeDepthInit: uhm, wouldn't you rather give a non-empty set of Nodes?");
|
||||
}
|
||||
|
||||
|
||||
unsigned int i=0;
|
||||
int arity=0;
|
||||
int type=0;
|
||||
std::vector<Node> node_std::vector;
|
||||
for(i=0; i < _node.size(); i++)
|
||||
{
|
||||
arity = _node[i].arity();
|
||||
type = _node[i].type();
|
||||
if(arity==0)
|
||||
{
|
||||
node_std::vector = node[type][TERMINAL];
|
||||
node_std::vector.push_back(_node[i]);
|
||||
node[type][TERMINAL]= node_std::vector;
|
||||
}
|
||||
else
|
||||
//if (arity != 0) // non-terminal
|
||||
{
|
||||
node_std::vector = node[type][NONTERMINAL];
|
||||
node_std::vector.push_back(_node[i]);
|
||||
node[type][NONTERMINAL] = node_std::vector;
|
||||
}
|
||||
node_std::vector = node[type][ALL];
|
||||
node_std::vector.push_back(_node[i]);
|
||||
node[type][ALL] = node_std::vector;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/// My class name
|
||||
virtual std::string className() const { return "eoStParseTreeDepthInit"; };
|
||||
|
||||
/**initialize a tree
|
||||
* @param _tree : the tree to be initialized
|
||||
*/
|
||||
void operator()(EoType& _tree)
|
||||
{
|
||||
std::list<Node> sequence;
|
||||
bool good_tree = false;
|
||||
do
|
||||
{
|
||||
sequence.clear();
|
||||
good_tree = generate(sequence, max_depth, return_type);
|
||||
}while (!good_tree);
|
||||
|
||||
parse_tree<Node> tmp(sequence.begin(), sequence.end());
|
||||
_tree.swap(tmp);
|
||||
}
|
||||
private :
|
||||
bool generate(std::list<Node>& sequence, int the_max, int request_type)
|
||||
{
|
||||
|
||||
int selected=0;
|
||||
bool ok = true;
|
||||
|
||||
if (the_max == 1)
|
||||
{ // generate terminals only
|
||||
if( node[request_type][TERMINAL].empty() ) // no possible terminal node of this type
|
||||
return false; // we have an invalid tree
|
||||
else
|
||||
{
|
||||
selected = rng.random((node[request_type][TERMINAL]).size());
|
||||
sequence.push_front(node[request_type][TERMINAL][selected]);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int arity=0;
|
||||
if (grow)
|
||||
{
|
||||
selected = rng.random((node[request_type][ALL]).size());
|
||||
arity = node[request_type][ALL][selected].arity();
|
||||
sequence.push_front(node[request_type][ALL][selected]);
|
||||
for (int i = 0; i < arity; ++i)
|
||||
ok &= generate(sequence, the_max - 1, node[request_type][ALL][selected].type(i));
|
||||
}
|
||||
else // full
|
||||
{
|
||||
selected = rng.random((node[request_type][NONTERMINAL]).size());
|
||||
arity = node[request_type][NONTERMINAL][selected].arity();
|
||||
sequence.push_front(node[request_type][NONTERMINAL][selected]);
|
||||
for (int i = 0; i < arity; ++i)
|
||||
ok &=generate(sequence, the_max - 1, node[request_type][NONTERMINAL][selected].type(i));
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned max_depth;
|
||||
map < int, map < int, std::vector<Node> > > node;
|
||||
|
||||
int return_type;
|
||||
bool grow;
|
||||
};
|
||||
|
||||
#endif
|
||||
315
trunk/paradiseo-eo/src/gp/eoStParseTreeOp.h
Normal file
315
trunk/paradiseo-eo/src/gp/eoStParseTreeOp.h
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoStParseTreeOp.h : crossover and mutation operators for the strongly typed GP
|
||||
// (c) Jeroen Eggermont 2001 for other mutation operators
|
||||
|
||||
/*
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser 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 Lesser 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
|
||||
mak@dhi.dk
|
||||
jeggermo@liacs.nl
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef eoStParseTreeOp_h
|
||||
#define eoStParseTreeOp_h
|
||||
|
||||
#include <EO.h>
|
||||
#include <eoOp.h>
|
||||
#include <map.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <gp/eoParseTree.h>
|
||||
|
||||
// a help function
|
||||
template <class EOT>
|
||||
void get_possible_nodes(const EOT &_eo, std::vector<int> &possible_nodes, const int type)
|
||||
{
|
||||
int n=0;
|
||||
possible_nodes.clear();
|
||||
// collect the possible crossover points in _eo (nodes with the same type)
|
||||
for(n=0; n < _eo.size(); n++)
|
||||
if (type == _eo[n]->type())
|
||||
possible_nodes.push_back(n);
|
||||
}
|
||||
|
||||
|
||||
/** eoStSubtreeXOver --> subtree xover for strongly typed tree-based genetic programming
|
||||
\class eoStSubtreeXOver eoStParseTreeOp.h gp/eoStParseTreeOp.h
|
||||
\ingroup StParseTree
|
||||
*/
|
||||
template<class FType, class Node>
|
||||
class eoStSubtreeXOver: public eoQuadOp< eoParseTree<FType, Node> > {
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoStSubtreeXOver( unsigned _max_length)
|
||||
: eoQuadOp<EoType>(), max_length(_max_length) {};
|
||||
|
||||
/// the ckassname
|
||||
virtual std::string className() const { return "eoStSubtreeXOver"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoStSubtreeXOver () {};
|
||||
|
||||
/**
|
||||
* Perform crossover on two individuals
|
||||
* param _eo1 The first parent individual
|
||||
* param _eo2 The second parent individual
|
||||
*/
|
||||
bool operator()(EoType & _eo1, EoType & _eo2 )
|
||||
{
|
||||
int i = 0;
|
||||
std::vector<int> nodes;
|
||||
int n = 0;
|
||||
int type = 0;
|
||||
int j = 0;
|
||||
set<int> test;
|
||||
do
|
||||
{
|
||||
do // select a random node in _eo1 as crossover point, and check if we didn't try it already
|
||||
{
|
||||
i = rng.random(_eo1.size());
|
||||
}while(test.count(i) > 0);
|
||||
|
||||
test.insert(i);
|
||||
|
||||
type = _eo1[i]->type();
|
||||
|
||||
get_possible_nodes<EoType>(_eo2, nodes, type);
|
||||
|
||||
}while(nodes.empty() && (test.size() < _eo1.size()));
|
||||
|
||||
if (nodes.empty()) // we failed to select a crossover point but tried all points (test.size() == _eo1.size()).
|
||||
return true; // should this be false ??
|
||||
|
||||
// we did find at least one possible crossover point in _eo2
|
||||
|
||||
n = rng.random(nodes.size());
|
||||
j = nodes[n];
|
||||
|
||||
parse_tree<Node>::subtree tmp = _eo1[i];
|
||||
_eo1[i] = _eo2[j]; // insert subtree
|
||||
_eo2[j] = tmp;
|
||||
|
||||
// we can't prune anymore
|
||||
/*
|
||||
_eo1.pruneTree(max_length);
|
||||
_eo2.pruneTree(max_length);
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
unsigned max_length;
|
||||
};
|
||||
|
||||
/** eoStBranchMutation --> replace a strongly typed subtree with a randomly created strongly typed subtree
|
||||
\class eoStBranchMutation eoStParseTreeOp.h gp/eoStParseTreeOp.h
|
||||
\ingroup StParseTree
|
||||
*/
|
||||
template<class FType, class Node>
|
||||
class eoStBranchMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _init An instantiation of eoGpDepthInitializer
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoStBranchMutation(eoInit<EoType>& _init, unsigned _max_length)
|
||||
: eoMonOp<EoType>(), max_length(_max_length), initializer(_init)
|
||||
{};
|
||||
|
||||
/// the class name
|
||||
virtual std::string className() const { return "eoStBranchMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoStBranchMutation() {};
|
||||
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
int i = rng.random(_eo1.size());
|
||||
std::vector<int> nodes;
|
||||
int type = _eo1[i]->type();
|
||||
int j=0;
|
||||
int n=0;
|
||||
|
||||
EoType eo2;
|
||||
|
||||
do
|
||||
{
|
||||
initializer(eo2);
|
||||
get_possible_nodes(eo2, nodes, type);
|
||||
}while (nodes.empty());
|
||||
|
||||
n = rng.random(nodes.size());
|
||||
j = nodes[n];
|
||||
|
||||
_eo1[i] = eo2[j]; // insert subtree
|
||||
|
||||
// no more pruning
|
||||
/*
|
||||
_eo1.pruneTree(max_length);
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_length;
|
||||
eoInit<EoType>& initializer;
|
||||
};
|
||||
|
||||
|
||||
/** eoStPointMutation --> replace a Node with a Node of the same arity and type
|
||||
\class eoStPointMutation eoStParseTreeOp.h gp/eoStParseTreeOp.h
|
||||
\ingroup StParseTree
|
||||
*/
|
||||
template<class FType, class Node>
|
||||
class eoStPointMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param _initializor The std::vector of Nodes given to the eoGpDepthInitializer
|
||||
*/
|
||||
eoStPointMutation( std::vector<Node>& _node)
|
||||
: eoMonOp<EoType>()
|
||||
{
|
||||
unsigned int i=0;
|
||||
int arity=0;
|
||||
int type=0;
|
||||
std::vector<Node> node_std::vector;
|
||||
for(i=0; i < _node.size(); i++)
|
||||
{
|
||||
arity = _node[i].arity();
|
||||
type = _node[i].type();
|
||||
|
||||
node_std::vector = node[type][arity];
|
||||
node_std::vector.push_back(_node[i]);
|
||||
node[type][arity]= node_std::vector;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
/// the class name
|
||||
virtual std::string className() const { return "eoStPointMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoStPointMutation() {};
|
||||
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
// select a random node i that is to be mutated
|
||||
int i = rng.random(_eo1.size());
|
||||
int arity = _eo1[i].arity();
|
||||
int type = _eo1[i]->type();
|
||||
int j = rng.random(node[type][arity].size());
|
||||
|
||||
|
||||
_eo1[i] = node[type][arity][j];
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
map < int, map < int, std::vector<Node> > > node;
|
||||
};
|
||||
|
||||
|
||||
/** eoStHoistMutation --> replace the individual with one of its strongly typed subtree's
|
||||
\class eoStHoistMutation eoStParseTreeOp.h gp/eoStParseTreeOp.h
|
||||
\ingroup StParseTree
|
||||
*/
|
||||
template<class FType, class Node>
|
||||
class eoStHoistMutation: public eoMonOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType,Node> EoType;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _init An instantiation of eoStDepthInit
|
||||
* @param _max_length the maximum size of an individual
|
||||
*/
|
||||
eoStHoistMutation(eoInit<EoType>& _init, unsigned _max_length)
|
||||
: eoMonOp<EoType>(), max_length(_max_length), initializer(_init)
|
||||
{};
|
||||
|
||||
/// the class name
|
||||
virtual std::string className() const { return "eoStHoistMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoStHoistMutation() {};
|
||||
|
||||
/**
|
||||
* Mutate an individual
|
||||
* @param _eo1 The individual that is to be changed
|
||||
*/
|
||||
bool operator()(EoType& _eo1 )
|
||||
{
|
||||
|
||||
std::vector<int> nodes;
|
||||
// get the type of the current tree
|
||||
int type = _eo1[ _eo1.size() - 1 ]->type();
|
||||
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
initializer(eo2);
|
||||
get_possible_nodes(eo2, nodes, type);
|
||||
}while (nodes.empty());
|
||||
|
||||
// select a subtree-node to replace the current tree
|
||||
int n = rng.random(nodes.size());
|
||||
int i = nodes[n];
|
||||
|
||||
EoType eo2(_eo1[i]);
|
||||
|
||||
_eo1 = eo2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_length;
|
||||
eoInit<EoType>& initializer;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
313
trunk/paradiseo-eo/src/gp/node_pool.h
Normal file
313
trunk/paradiseo-eo/src/gp/node_pool.h
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/**
|
||||
|
||||
* Pool allocator for the subtree and parse tree classes (homebrew and not compliant to ANSI allocator requirements)
|
||||
* (c) copyright Maarten Keijzer 1999, 2000
|
||||
|
||||
* Permission to copy, use, modify, sell and distribute this software is granted provided
|
||||
* this copyright notice appears in all copies. This software is provided "as is" without
|
||||
* express or implied warranty, and with no claim as to its suitability for
|
||||
* any purpose.
|
||||
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifndef node_pool_h
|
||||
#define node_pool_h
|
||||
|
||||
class MemPool
|
||||
{
|
||||
public :
|
||||
|
||||
MemPool(unsigned int sz) : esize(sz<sizeof(Link)? sizeof(Link) : sz) {}
|
||||
~MemPool()
|
||||
{
|
||||
Chunk* n = chunks;
|
||||
while(n)
|
||||
{
|
||||
Chunk* p = n;
|
||||
n = n->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
void* allocate()
|
||||
{
|
||||
if (head == 0) grow();
|
||||
Link* p = head;
|
||||
head = p->next;
|
||||
return static_cast<void*>(p);
|
||||
}
|
||||
|
||||
void deallocate(void* b)
|
||||
{
|
||||
Link* p = static_cast<Link*>(b);
|
||||
p->next = head;
|
||||
head = p;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
void grow()
|
||||
{
|
||||
Chunk* n = new Chunk;
|
||||
n->next = chunks;
|
||||
chunks = n;
|
||||
|
||||
const int nelem = Chunk::size/esize;
|
||||
char* start = n->mem;
|
||||
char* last = &start[(nelem-1)*esize];
|
||||
for (char* p = start; p < last; p += esize)
|
||||
{
|
||||
reinterpret_cast<Link*>(p)->next =
|
||||
reinterpret_cast<Link*>(p + esize);
|
||||
}
|
||||
|
||||
reinterpret_cast<Link*>(last)->next = 0;
|
||||
head = reinterpret_cast<Link*>(start);
|
||||
}
|
||||
|
||||
struct Link
|
||||
{
|
||||
Link* next;
|
||||
};
|
||||
|
||||
struct Chunk
|
||||
{
|
||||
enum {size = 8 * 1024 - 16};
|
||||
Chunk* next;
|
||||
char mem[size];
|
||||
};
|
||||
|
||||
Chunk* chunks;
|
||||
const unsigned int esize;
|
||||
Link* head;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class Node_alloc
|
||||
{
|
||||
public :
|
||||
|
||||
T* allocate(void)
|
||||
{
|
||||
T* t = static_cast<T*>(mem.allocate());
|
||||
t = new (t) T;
|
||||
return t;
|
||||
}
|
||||
|
||||
T* construct(const T& org)
|
||||
{
|
||||
T* t = static_cast<T*>(mem.allocate());
|
||||
t = new (t) T(org);
|
||||
return t;
|
||||
}
|
||||
|
||||
void deallocate(T* t)
|
||||
{
|
||||
t->~T(); // call destructor
|
||||
mem.deallocate(static_cast<void*>(t));
|
||||
}
|
||||
|
||||
private :
|
||||
static MemPool mem;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class Standard_alloc
|
||||
{
|
||||
public :
|
||||
Standard_alloc() {}
|
||||
|
||||
T* allocate(size_t arity = 1)
|
||||
{
|
||||
if (arity == 0)
|
||||
return 0;
|
||||
|
||||
return new T [arity];
|
||||
}
|
||||
|
||||
T* construct(size_t arity, T* org)
|
||||
{
|
||||
if (arity == 0)
|
||||
return 0;
|
||||
|
||||
T* t = new T [arity];
|
||||
|
||||
for (int i = 0; i < arity; ++i)
|
||||
{
|
||||
t = T(org[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(T* t, size_t arity = 1)
|
||||
{
|
||||
if (arity == 0)
|
||||
return ;
|
||||
|
||||
delete [] t;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Standard_Node_alloc
|
||||
{
|
||||
public :
|
||||
Standard_Node_alloc() {}
|
||||
|
||||
T* allocate(void)
|
||||
{
|
||||
return new T;// [arity];
|
||||
}
|
||||
|
||||
T* construct(const T& org)
|
||||
{
|
||||
return new T(org);
|
||||
}
|
||||
|
||||
void deallocate(T* t)
|
||||
{
|
||||
delete t;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Tree_alloc
|
||||
{
|
||||
public :
|
||||
Tree_alloc() {}
|
||||
|
||||
T* allocate(size_t arity)
|
||||
{
|
||||
T* t;
|
||||
|
||||
switch(arity)
|
||||
{
|
||||
|
||||
case 0 : return 0;
|
||||
case 1 :
|
||||
{
|
||||
t = static_cast<T*>(mem1.allocate());
|
||||
new (t) T;
|
||||
break;
|
||||
}
|
||||
case 2 :
|
||||
{
|
||||
t = static_cast<T*>(mem2.allocate());
|
||||
new (t) T;
|
||||
new (&t[1]) T;
|
||||
break;
|
||||
}
|
||||
case 3 :
|
||||
{
|
||||
t = static_cast<T*>(mem3.allocate());
|
||||
new (t) T;
|
||||
new (&t[1]) T;
|
||||
new (&t[2]) T;
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
return new T[arity];
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
T* construct(size_t arity, T* org)
|
||||
{
|
||||
T* t;
|
||||
|
||||
switch(arity)
|
||||
{
|
||||
|
||||
case 0 : return 0;
|
||||
case 1 :
|
||||
{
|
||||
t = static_cast<T*>(mem1.allocate());
|
||||
new (t) T(*org);
|
||||
break;
|
||||
}
|
||||
case 2 :
|
||||
{
|
||||
t = static_cast<T*>(mem2.allocate());
|
||||
new (t) T(*org);
|
||||
new (&t[1]) T(org[1]);
|
||||
break;
|
||||
}
|
||||
case 3 :
|
||||
{
|
||||
t = static_cast<T*>(mem3.allocate());
|
||||
new (t) T(*org);
|
||||
new (&t[1]) T(org[1]);
|
||||
new (&t[1]) T(org[2]);
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
t = new T[arity]; // does call default ctor
|
||||
for (int i = 0; i < arity; ++i)
|
||||
{
|
||||
t[i] = T(org[i]); // constructs now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void deallocate(T* t, size_t arity)
|
||||
{
|
||||
switch(arity)
|
||||
{
|
||||
case 0: return;
|
||||
case 3 :
|
||||
{
|
||||
t[2].~T(); t[1].~T(); t[0].~T();
|
||||
mem3.deallocate(static_cast<void*>(t));
|
||||
return;
|
||||
}
|
||||
case 2 :
|
||||
{
|
||||
t[1].~T(); t[0].~T();
|
||||
mem2.deallocate(static_cast<void*>(t));
|
||||
return;
|
||||
}
|
||||
case 1 :
|
||||
{
|
||||
t[0].~T();
|
||||
mem1.deallocate(static_cast<void*>(t));
|
||||
return;
|
||||
}
|
||||
default :
|
||||
{
|
||||
delete [] t;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private :
|
||||
static MemPool mem1;
|
||||
static MemPool mem2;
|
||||
static MemPool mem3;
|
||||
};
|
||||
|
||||
// static (non thread_safe) memory pools
|
||||
template <class T> MemPool Node_alloc<T>::mem = sizeof(T);
|
||||
|
||||
template <class T> MemPool Tree_alloc<T>::mem1 = sizeof(T);
|
||||
template <class T> MemPool Tree_alloc<T>::mem2 = sizeof(T) * 2;
|
||||
template <class T> MemPool Tree_alloc<T>::mem3 = sizeof(T) * 3;
|
||||
|
||||
#endif
|
||||
999
trunk/paradiseo-eo/src/gp/parse_tree.h
Normal file
999
trunk/paradiseo-eo/src/gp/parse_tree.h
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
#ifndef PARSE_TREE_HH
|
||||
#define PARSE_TREE_HH
|
||||
|
||||
/**
|
||||
|
||||
* Parse_tree and subtree classes
|
||||
* (c) copyright Maarten Keijzer 1999, 2000
|
||||
|
||||
* Permission to copy, use, modify, sell and distribute this software is granted provided
|
||||
* this copyright notice appears in all copies. This software is provided "as is" without
|
||||
* express or implied warranty, and with no claim as to its suitability for
|
||||
* any purpose.
|
||||
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices as well as this one are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
|
||||
|
||||
|
||||
Usage information.
|
||||
|
||||
class Node (your node in the tree) must have the following implemented:
|
||||
|
||||
****** Arity ******
|
||||
|
||||
int arity(void) const
|
||||
|
||||
Note: the default constructor of a Node should provide a
|
||||
Node with arity 0!
|
||||
|
||||
****** Evaluation ******
|
||||
|
||||
A parse_tree is evaluated through one of it's apply() members:
|
||||
|
||||
1) parse_tree::apply(RetVal)
|
||||
|
||||
is the simplest evaluation, it will call
|
||||
|
||||
RetVal Node::operator()(RetVal, subtree<Node, RetVal>::const_iterator)
|
||||
|
||||
(Unfortunately the first RetVal argument is mandatory (although you
|
||||
might not need it. This is because MSVC does not support member template
|
||||
functions properly. If it cannot deduce the template arguments (as is
|
||||
the case in templatizing over return value) you are not allowed to
|
||||
specify them. calling tree.apply<double>() would result in a syntax
|
||||
error. That is why you have to call tree.apply(double()) instead.)
|
||||
|
||||
|
||||
2) parse_tree::apply(RetVal v, It values)
|
||||
|
||||
will call:
|
||||
|
||||
RetVal Node::operator()(RetVal, subtree<... , It values)
|
||||
|
||||
where It is whatever type you desire (most of the time
|
||||
this will be a std::vector containing the values of your
|
||||
variables);
|
||||
|
||||
3) parse_tree::apply(RetVal, It values, It2 moreValues)
|
||||
|
||||
will call:
|
||||
|
||||
RetVal Node::operator()(RetVal, subtree<... , It values, It2 moreValues)
|
||||
|
||||
although I do not see the immediate use of this, however...
|
||||
|
||||
4) parse_tree::apply(RetVal, It values, It2 args, It3 adfs)
|
||||
|
||||
that calls:
|
||||
|
||||
RetVal Node::operator()(subtree<... , It values, It2 args, It3 adfs)
|
||||
|
||||
can be useful for implementing adfs.
|
||||
|
||||
|
||||
In general it is a good idea to leave the specifics of the
|
||||
arguments open so that different ways of evaluation remain
|
||||
possible. Implement the simplest eval as:
|
||||
|
||||
template <class It>
|
||||
RetVal operator()(RetVal dummy, It begin) const
|
||||
|
||||
****** Internal Structure ******
|
||||
|
||||
A parse_tree has two template arguments: the Node and the ReturnValue
|
||||
produced by evaluating the node. The structure of the tree is defined
|
||||
through a subtree class that has the same two template arguments.
|
||||
|
||||
The nodes are stored in a tree like :
|
||||
|
||||
node4
|
||||
/ \
|
||||
node3 node2
|
||||
/ \
|
||||
node1 node0
|
||||
|
||||
where nodes 2 and 4 have arity 2 and nodes 0,1 and 3 arity 0 (terminals)
|
||||
|
||||
The nodes are subtrees, containing the structure of the tree, together
|
||||
with its size and depth. They contain a Node, the user defined template
|
||||
argument. To access these nodes from a subtree, use operator-> or operator*.
|
||||
|
||||
The numbers behind the nodes define a reverse-polish or postfix
|
||||
traversel through the tree. The parse_tree defines iterators
|
||||
on the tree such that
|
||||
|
||||
tree.begin() points at the subtree at node0 and
|
||||
tree.back() returns the subtree at node4, the complete tree
|
||||
|
||||
Likewise operator[] is defined on the tree, such that:
|
||||
|
||||
tree[0] will return the subtree at node0, while
|
||||
tree[2] will return the subtree at node2
|
||||
|
||||
Assigments of subtrees is protected so that the code:
|
||||
|
||||
tree[2] = tree[0];
|
||||
|
||||
will not crash and result in a tree structured as:
|
||||
|
||||
node4
|
||||
/ \
|
||||
node3 node0
|
||||
|
||||
Note that the rank numbers no longer specify their place in the tree:
|
||||
|
||||
tree[0] still points at node0, but
|
||||
tree[1] now points to node3 and
|
||||
tree[2] points at the root node4
|
||||
|
||||
Embedded iterators are implemented to iterate over nodes rather
|
||||
than subtrees. So an easy way to copy your tree to a std::vector is:
|
||||
|
||||
std::vector<Node> vec(tree.size());
|
||||
copy(tree.ebegin(), tree.eend(), vec.begin());
|
||||
|
||||
You can also copy it to an std::ostream_iterator with this
|
||||
technique, given that your Node implements an appropriate
|
||||
operator<<. Reinitializing a tree with the std::vector is also
|
||||
simple:
|
||||
|
||||
tree.clear();
|
||||
copy(vec.begin(), vec.end(), back_inserter(tree));
|
||||
|
||||
or from an std::istream:
|
||||
|
||||
copy(std::istream_iterator<T>(my_stream), std::istream_iterator<T>(), back_inserter(tree));
|
||||
|
||||
Note that the back_inserter must be used as there is no
|
||||
resize member in the parse_tree. back_inserter will use
|
||||
the push_back member from the parse_tree
|
||||
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <utility> // for swap
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4786) // disable this nagging warning about the limitations of the mirkosoft debugger
|
||||
#endif
|
||||
|
||||
namespace gp_parse_tree
|
||||
{
|
||||
|
||||
#include "node_pool.h"
|
||||
|
||||
/// This ones defined because gcc does not always implement namespaces
|
||||
template <class T>
|
||||
inline void do_the_swap(T& a, T& b)
|
||||
{
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
template <class T> class parse_tree
|
||||
{
|
||||
public :
|
||||
|
||||
|
||||
class subtree
|
||||
{
|
||||
|
||||
/*
|
||||
a bit nasty way to use a pool allocator (which would otherwise use slooow new and delete)
|
||||
TODO: use the std::allocator interface
|
||||
*/
|
||||
|
||||
#if (defined(__GNUC__) || defined(_MSC_VER)) && !(defined(_MT) || defined(MACOSX) || defined(__APPLE__)) // not multithreaded (or MACOSX - J. Eggermont)
|
||||
Node_alloc<T> node_allocator;
|
||||
Tree_alloc<subtree> tree_allocator;
|
||||
#else
|
||||
Standard_Node_alloc<T> node_allocator;
|
||||
Standard_alloc<subtree> tree_allocator;
|
||||
#endif
|
||||
|
||||
public :
|
||||
|
||||
typedef subtree* iterator;
|
||||
typedef const subtree* const_iterator;
|
||||
|
||||
/* Constructors, assignments */
|
||||
|
||||
subtree(void) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1)
|
||||
{}
|
||||
subtree(const subtree& s)
|
||||
: content(node_allocator.allocate()),
|
||||
args(0),
|
||||
parent(0),
|
||||
_cumulative_size(1),
|
||||
_depth(1),
|
||||
_size(1)
|
||||
{
|
||||
copy(s);
|
||||
}
|
||||
|
||||
subtree(const T& t) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1)
|
||||
{ copy(t); }
|
||||
|
||||
template <class It>
|
||||
subtree(It b, It e) : content(node_allocator.allocate()), args(0), parent(0), _cumulative_size(0), _depth(0), _size(1)
|
||||
{ // initialize in prefix order for efficiency reasons
|
||||
init(b, --e);
|
||||
}
|
||||
|
||||
virtual ~subtree(void) { tree_allocator.deallocate(args, arity()); node_allocator.deallocate(content); }
|
||||
|
||||
subtree& operator=(const subtree& s)
|
||||
{
|
||||
if (s.get_root() == get_root())
|
||||
{ // from the same tree, maybe a child. Don't take any chances
|
||||
subtree anotherS = s;
|
||||
return copy(anotherS);
|
||||
}
|
||||
|
||||
copy(s);
|
||||
updateAfterInsert();
|
||||
return *this;
|
||||
}
|
||||
|
||||
subtree& operator=(const T& t) { copy(t); updateAfterInsert(); return *this; }
|
||||
|
||||
/* Access to the nodes */
|
||||
|
||||
T& operator*(void) { return *content; }
|
||||
const T& operator*(void) const { return *content; }
|
||||
T* operator->(void) { return content; }
|
||||
const T* operator->(void) const { return content; }
|
||||
|
||||
/* Equality, inequality check, Node needs to implement operator== */
|
||||
|
||||
bool operator==(const subtree& other) const
|
||||
{
|
||||
if (! (*content == *other.content))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < arity(); i++)
|
||||
{
|
||||
if (!(args[i] == other.args[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator !=(const subtree& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
/* Arity */
|
||||
int arity(void) const { return content->arity(); }
|
||||
|
||||
/* Evaluation with an increasing amount of user defined arguments */
|
||||
template <class RetVal>
|
||||
void apply(RetVal& v) const { (*content)(v, begin()); }
|
||||
|
||||
template <class RetVal, class It>
|
||||
void apply(RetVal& v, It values) const
|
||||
{
|
||||
(*content)(v, begin(), values);
|
||||
}
|
||||
|
||||
template <class RetVal, class It>
|
||||
void apply_mem_func(RetVal& v, It misc, void (T::* f)(RetVal&, typename subtree::iterator, It))
|
||||
{
|
||||
(content->*f)(v, begin(), misc);
|
||||
}
|
||||
|
||||
|
||||
/* template <class RetVal, class It, class It2>
|
||||
void apply(RetVal& v, It values, It2 moreValues) const
|
||||
{ (*content)(v, begin(), values, moreValues); }
|
||||
|
||||
template <class RetVal, class It, class It2, class It3>
|
||||
void apply(RetVal& v, It values, It2 moreValues, It3 evenMoreValues) const
|
||||
{ (*content)(v, begin(), values, moreValues, evenMoreValues); }
|
||||
*/
|
||||
|
||||
template <class Pred>
|
||||
void find_nodes(std::vector<subtree*>& result, Pred& p)
|
||||
{
|
||||
if (p(*content))
|
||||
{
|
||||
result.push_back(this);
|
||||
}
|
||||
|
||||
for (int i = 0; i < arity(); ++i)
|
||||
{
|
||||
args[i].find_nodes(result, p);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Pred>
|
||||
void find_nodes(std::vector<const subtree*>& result, Pred& p) const
|
||||
{
|
||||
if (p(*content))
|
||||
{
|
||||
result.push_back(this);
|
||||
}
|
||||
|
||||
for (int i = 0; i < arity(); ++i)
|
||||
{
|
||||
args[i].find_nodes(result, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterators */
|
||||
|
||||
iterator begin(void) { return args; }
|
||||
const_iterator begin(void) const { return args; }
|
||||
|
||||
iterator end(void) { return args + arity(); }
|
||||
const_iterator end(void) const { return args + arity(); }
|
||||
|
||||
subtree& operator[](int i) { return *(begin() + i); }
|
||||
const subtree& operator[](int i) const { return *(begin() + i); }
|
||||
|
||||
/* Some statistics */
|
||||
|
||||
size_t size(void) const { return _size; }
|
||||
|
||||
size_t cumulative_size(void) const { return _cumulative_size; }
|
||||
size_t depth(void) const { return _depth; }
|
||||
|
||||
const subtree& select_cumulative(size_t which) const
|
||||
{ return imp_select_cumulative(which); }
|
||||
|
||||
subtree& select_cumulative(size_t which)
|
||||
{ return const_cast<subtree&>(imp_select_cumulative(which)); }
|
||||
|
||||
subtree& get_node(size_t which)
|
||||
{ return const_cast<subtree&>(imp_get_node(which));}
|
||||
const subtree& get_node(size_t which) const
|
||||
{ return imp_get_node(which); }
|
||||
|
||||
subtree* get_parent(void) { return parent; }
|
||||
const subtree* get_parent(void) const { return parent; }
|
||||
|
||||
void clear(void)
|
||||
{ tree_allocator.deallocate(args, arity()); args = 0; *content = T(); parent = 0; _cumulative_size = 0; _depth = 0; _size = 0; }
|
||||
|
||||
void swap(subtree& y)
|
||||
{
|
||||
do_the_swap(content, y.content);
|
||||
do_the_swap(args, y.args);
|
||||
|
||||
adopt();
|
||||
y.adopt();
|
||||
|
||||
do_the_swap(parent, y.parent);
|
||||
|
||||
do_the_swap(_cumulative_size, y._cumulative_size);
|
||||
do_the_swap(_depth, y._depth);
|
||||
do_the_swap(_size, y._size);
|
||||
updateAfterInsert();
|
||||
}
|
||||
|
||||
protected :
|
||||
|
||||
virtual void updateAfterInsert(void)
|
||||
{
|
||||
_depth = 0;
|
||||
_size = 1;
|
||||
_cumulative_size = 0;
|
||||
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
_size += it->size();
|
||||
_cumulative_size += it->_cumulative_size;
|
||||
_depth = it->_depth > _depth? it->_depth: _depth;
|
||||
}
|
||||
_cumulative_size += _size;
|
||||
_depth++;
|
||||
|
||||
if (parent)
|
||||
parent->updateAfterInsert();
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
const subtree& imp_select_cumulative(size_t which) const
|
||||
{
|
||||
if (which >= (_cumulative_size - size()))
|
||||
return *this;
|
||||
// else
|
||||
|
||||
for (int i = arity() - 1; i >= 0; --i)
|
||||
{
|
||||
if (which < args[i]._cumulative_size)
|
||||
return args[i].imp_select_cumulative(which);
|
||||
which -= args[i]._cumulative_size;
|
||||
}
|
||||
|
||||
return *this; // error!
|
||||
}
|
||||
|
||||
const subtree& imp_get_node(size_t which) const
|
||||
{
|
||||
if (which == size() - 1)
|
||||
return *this;
|
||||
|
||||
for (int i = arity() - 1; i >= 0; --i)
|
||||
{
|
||||
unsigned c_size = args[i].size();
|
||||
if (which < c_size)
|
||||
return args[i].imp_get_node(which);
|
||||
which -= c_size;
|
||||
}
|
||||
|
||||
return *this; // error!
|
||||
}
|
||||
|
||||
const subtree* get_root(void) const
|
||||
{
|
||||
if (parent == 0)
|
||||
return this;
|
||||
// else
|
||||
|
||||
return parent->get_root();
|
||||
}
|
||||
subtree& copy(const subtree& s)
|
||||
{
|
||||
int old_arity = arity();
|
||||
|
||||
int new_arity = s.arity();
|
||||
|
||||
if (new_arity != old_arity)
|
||||
{
|
||||
tree_allocator.deallocate(args, old_arity);
|
||||
|
||||
args = tree_allocator.allocate(new_arity);
|
||||
}
|
||||
|
||||
switch(new_arity)
|
||||
{
|
||||
case 3 : args[2].copy(s.args[2]); args[2].parent = this; // no break!
|
||||
case 2 : args[1].copy(s.args[1]); args[1].parent = this;
|
||||
case 1 : args[0].copy(s.args[0]); args[0].parent = this;
|
||||
case 0 : break;
|
||||
default :
|
||||
{
|
||||
for (int i = 0; i < new_arity; ++i)
|
||||
{
|
||||
args[i].copy(s.args[i]);
|
||||
args[i].parent = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*content = *s.content;
|
||||
_size = s._size;
|
||||
_depth = s._depth;
|
||||
_cumulative_size = s._cumulative_size;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
subtree& copy(const T& t)
|
||||
{
|
||||
int oldArity = arity();
|
||||
|
||||
if (content != &t)
|
||||
*content = t;
|
||||
else
|
||||
oldArity = -1;
|
||||
|
||||
int ar = arity();
|
||||
|
||||
if (ar != oldArity)
|
||||
{
|
||||
if (oldArity != -1)
|
||||
tree_allocator.deallocate(args, oldArity);
|
||||
|
||||
args = tree_allocator.allocate(ar);
|
||||
|
||||
//if (ar > 0)
|
||||
// args = new subtree [ar];
|
||||
//else
|
||||
// args = 0;
|
||||
}
|
||||
|
||||
adopt();
|
||||
updateAfterInsert();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void disown(void)
|
||||
{
|
||||
switch(arity())
|
||||
{
|
||||
case 3 : args[2].parent = 0; // no break!
|
||||
case 2 : args[1].parent = 0;
|
||||
case 1 : args[0].parent = 0; break;
|
||||
case 0 : break;
|
||||
default :
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
it->parent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void adopt(void)
|
||||
{
|
||||
switch(arity())
|
||||
{
|
||||
case 3 : args[2].parent = this; // no break!
|
||||
case 2 : args[1].parent = this;
|
||||
case 1 : args[0].parent = this; break;
|
||||
case 0 : break;
|
||||
default :
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
it->parent = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class It>
|
||||
void init(It b, It& last)
|
||||
{
|
||||
*this = *last;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (last == b && arity() > 0)
|
||||
{
|
||||
throw "subtree::init()";
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < arity(); ++i)
|
||||
{
|
||||
args[i].parent = 0;
|
||||
args[i].init(b, --last);
|
||||
args[i].parent = this;
|
||||
}
|
||||
|
||||
updateAfterInsert();
|
||||
}
|
||||
|
||||
T* content;
|
||||
subtree* args;
|
||||
subtree* parent;
|
||||
|
||||
size_t _cumulative_size;
|
||||
size_t _depth;
|
||||
size_t _size;
|
||||
};
|
||||
|
||||
// Continuing with parse_tree
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
/* Constructors and Assignments */
|
||||
|
||||
parse_tree(void) : _root(), pushed() {}
|
||||
parse_tree(const parse_tree& org) : _root(org._root), pushed(org.pushed) { }
|
||||
parse_tree(const subtree& sub) : _root(sub), pushed() { }
|
||||
|
||||
template <class It>
|
||||
parse_tree(It b, It e) : _root(b, e), pushed() {}
|
||||
|
||||
virtual ~parse_tree(void) {}
|
||||
|
||||
parse_tree& operator=(const parse_tree& org) { return copy(org); }
|
||||
parse_tree& operator=(const subtree& sub)
|
||||
{ return copy(sub); }
|
||||
|
||||
|
||||
/* Equality and inequality */
|
||||
|
||||
bool operator==(const parse_tree& other) const
|
||||
{ return _root == other._root; }
|
||||
|
||||
bool operator !=(const parse_tree& other) const
|
||||
{ return !operator==(other); }
|
||||
|
||||
/* Simple tree statistics */
|
||||
|
||||
size_t size(void) const { return _root.size(); }
|
||||
size_t depth(void) const { return _root.depth(); }
|
||||
void clear(void) { _root.clear(); pushed.resize(0); }
|
||||
|
||||
/* Evaluation (application), with an increasing number of user defined arguments */
|
||||
|
||||
template <class RetVal>
|
||||
void apply(RetVal& v) const
|
||||
{ _root.apply(v); }
|
||||
|
||||
template <class RetVal, class It>
|
||||
void apply(RetVal& v, It varValues) const
|
||||
{ _root.apply(v, varValues); }
|
||||
|
||||
template <class RetVal, class It>
|
||||
void apply_mem_func(RetVal& v, It misc, void (T::* f)(RetVal&, typename subtree::iterator, It))
|
||||
{
|
||||
_root.apply_mem_func(v, misc, f);
|
||||
}
|
||||
|
||||
//template <class RetVal, class It, class It2>
|
||||
// void apply(RetVal& v, It varValues, It2 moreValues) const
|
||||
// { _root.apply(v, varValues, moreValues); }
|
||||
|
||||
//template <class RetVal, class It, class It2, class It3>
|
||||
// void apply(RetVal& v, It varValues, It2 moreValues, It3 evenMoreValues) const
|
||||
// { _root.apply(v, varValues, moreValues, evenMoreValues); }
|
||||
|
||||
template <class Pred>
|
||||
void find_nodes(std::vector<subtree*>& result, Pred& p)
|
||||
{
|
||||
_root.find_nodes(result, p);
|
||||
}
|
||||
|
||||
template <class Pred>
|
||||
void find_nodes(std::vector<const subtree*>& result, Pred& p) const
|
||||
{
|
||||
_root.find_nodes(p);
|
||||
}
|
||||
|
||||
/* Customized Swap */
|
||||
void swap(parse_tree<T>& other)
|
||||
{
|
||||
do_the_swap(pushed, other.pushed);
|
||||
_root.swap(other._root);
|
||||
}
|
||||
|
||||
/* Definitions of the iterators */
|
||||
|
||||
class base_iterator
|
||||
{
|
||||
public :
|
||||
|
||||
base_iterator() {}
|
||||
base_iterator(subtree* n) { node = n; }
|
||||
|
||||
base_iterator& operator=(const base_iterator& org)
|
||||
{ node = org.node; return *this; }
|
||||
|
||||
bool operator==(const base_iterator& org) const
|
||||
{ return node == org.node; }
|
||||
bool operator!=(const base_iterator& org) const
|
||||
{ return !operator==(org); }
|
||||
|
||||
base_iterator operator+(size_t n) const
|
||||
{
|
||||
base_iterator tmp = *this;
|
||||
|
||||
for(;n != 0; --n)
|
||||
{
|
||||
++tmp;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
base_iterator& operator++(void)
|
||||
{
|
||||
subtree* parent = node->get_parent();
|
||||
|
||||
if (parent == 0)
|
||||
{
|
||||
node = 0;
|
||||
return *this;
|
||||
}
|
||||
// else
|
||||
typename subtree::iterator it;
|
||||
for (it = parent->begin(); it != parent->end(); ++it)
|
||||
{
|
||||
if (node == &(*it))
|
||||
break;
|
||||
}
|
||||
|
||||
if (it == parent->begin())
|
||||
node = parent;
|
||||
else
|
||||
{
|
||||
node = &(--it)->get_node(0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_iterator operator++(int)
|
||||
{
|
||||
base_iterator tmp = *this;
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
protected :
|
||||
subtree* node;
|
||||
};
|
||||
|
||||
class iterator : public base_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
using base_iterator::node;
|
||||
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef subtree value_type;
|
||||
typedef size_t distance_type;
|
||||
typedef size_t difference_type;
|
||||
typedef subtree* pointer;
|
||||
typedef subtree& reference;
|
||||
|
||||
iterator() : base_iterator() {}
|
||||
iterator(subtree* n): base_iterator(n) {}
|
||||
iterator& operator=(const iterator& org)
|
||||
{ base_iterator::operator=(org); return *this; }
|
||||
|
||||
subtree& operator*(void) { return *node; }
|
||||
subtree* operator->(void) { return node; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class embedded_iterator : public base_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
using base_iterator::node;
|
||||
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef T value_type;
|
||||
typedef size_t distance_type;
|
||||
typedef size_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
|
||||
embedded_iterator() : base_iterator() {}
|
||||
embedded_iterator(subtree* n): base_iterator(n) {}
|
||||
embedded_iterator& operator=(const embedded_iterator& org)
|
||||
{ base_iterator::operator=(org); return *this; }
|
||||
|
||||
T& operator*(void) { return **node; }
|
||||
T* operator->(void) { return &**node; }
|
||||
};
|
||||
|
||||
class base_const_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
base_const_iterator() {}
|
||||
base_const_iterator(const subtree* n) { node = n; }
|
||||
|
||||
base_const_iterator& operator=(const base_const_iterator& org)
|
||||
{ node = org.node; return *this; }
|
||||
|
||||
bool operator==(const base_const_iterator& org) const
|
||||
{ return node == org.node; }
|
||||
bool operator!=(const base_const_iterator& org) const
|
||||
{ return !operator==(org); }
|
||||
|
||||
base_const_iterator& operator++(void)
|
||||
{
|
||||
const subtree* parent = node->get_parent();
|
||||
|
||||
if (parent == 0)
|
||||
{
|
||||
node = 0;
|
||||
return *this;
|
||||
}
|
||||
// else
|
||||
typename subtree::const_iterator it;
|
||||
|
||||
for (it = parent->begin(); it != parent->end(); ++it)
|
||||
{
|
||||
if (node == &(*it))
|
||||
break;
|
||||
}
|
||||
|
||||
if (it == parent->begin())
|
||||
node = parent;
|
||||
else
|
||||
node = &(--it)->get_node(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_const_iterator operator++(int)
|
||||
{
|
||||
base_const_iterator tmp = *this;
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
protected :
|
||||
|
||||
const subtree* node;
|
||||
};
|
||||
|
||||
class const_iterator : public base_const_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
using base_iterator::node;
|
||||
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef const subtree value_type;
|
||||
typedef size_t distance_type;
|
||||
typedef size_t difference_type;
|
||||
typedef const subtree* pointer;
|
||||
typedef const subtree& reference;
|
||||
|
||||
const_iterator() : base_const_iterator() {}
|
||||
const_iterator(const subtree* n): base_const_iterator(n) {}
|
||||
const_iterator& operator=(const const_iterator& org)
|
||||
{ base_const_iterator::operator=(org); return *this; }
|
||||
|
||||
const subtree& operator*(void) { return *node; }
|
||||
const subtree* operator->(void) { return node; }
|
||||
};
|
||||
|
||||
class embedded_const_iterator : public base_const_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
using base_const_iterator::node;
|
||||
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef const T value_type;
|
||||
typedef size_t distance_type;
|
||||
typedef size_t difference_type;
|
||||
typedef const T* pointer;
|
||||
typedef const T& reference;
|
||||
|
||||
embedded_const_iterator() : base_const_iterator() {}
|
||||
embedded_const_iterator(const subtree* n): base_const_iterator(n) {}
|
||||
embedded_const_iterator& operator=(const embedded_const_iterator& org)
|
||||
{ base_const_iterator::operator=(org); return *this; }
|
||||
|
||||
embedded_const_iterator operator+(size_t n) const
|
||||
{
|
||||
embedded_const_iterator tmp = *this;
|
||||
|
||||
for(;n != 0; --n)
|
||||
{
|
||||
++tmp;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const T& operator*(void) const { return **node; }
|
||||
const T* operator->(void) const { return node->operator->(); }
|
||||
};
|
||||
|
||||
/* Iterator access */
|
||||
|
||||
iterator begin(void) { return iterator(&operator[](0)); }
|
||||
const_iterator begin(void) const { return const_iterator(&operator[](0)); }
|
||||
iterator end(void) { return iterator(0); }
|
||||
const_iterator end(void) const { return const_iterator(0);}
|
||||
|
||||
embedded_iterator ebegin(void) { return embedded_iterator(&operator[](0)); }
|
||||
embedded_const_iterator ebegin(void) const { return embedded_const_iterator(&operator[](0)); }
|
||||
embedded_iterator eend(void) { return embedded_iterator(0); }
|
||||
embedded_const_iterator eend(void) const { return embedded_const_iterator(0);}
|
||||
|
||||
bool empty(void) const { return size() == 0; }
|
||||
bool valid(void) const { return pushed.empty(); }
|
||||
|
||||
/* push_back */
|
||||
|
||||
void push_back(const parse_tree<T>& tree)
|
||||
{
|
||||
if (!empty())
|
||||
pushed.push_back(_root);
|
||||
|
||||
_root = tree.back();
|
||||
}
|
||||
|
||||
void push_back(const T& t)
|
||||
{
|
||||
if (!empty())
|
||||
pushed.push_back(_root);
|
||||
|
||||
_root = t;
|
||||
|
||||
for (typename subtree::iterator it = _root.begin(); it != _root.end(); it++)
|
||||
{
|
||||
*it = pushed.back();
|
||||
pushed.pop_back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Access to subtrees */
|
||||
|
||||
subtree& back(void) { return _root; }
|
||||
const subtree& back(void) const { return _root; }
|
||||
subtree& root(void) { return _root; }
|
||||
const subtree& root(void) const { return _root; }
|
||||
|
||||
subtree& front(void) { return _root[0]; }
|
||||
const subtree& front(void) const { return _root[0]; }
|
||||
|
||||
subtree& operator[](size_t i)
|
||||
{ return const_cast<subtree&>(_root.get_node(i)); }
|
||||
const subtree& operator[](size_t i) const
|
||||
{ return _root.get_node(i); }
|
||||
|
||||
subtree& get_cumulative(size_t i)
|
||||
{ return const_cast<subtree&>(_root.get_cumulative(i)); }
|
||||
const subtree& get_cumulative(size_t i) const
|
||||
{ return get_cumulative(i); }
|
||||
|
||||
private :
|
||||
|
||||
parse_tree& copy(const parse_tree& org)
|
||||
{
|
||||
_root = org._root;
|
||||
pushed = org.pushed;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
parse_tree& copy(const subtree& sub)
|
||||
{ _root = sub; pushed.resize(0); return *this; }
|
||||
|
||||
subtree _root;
|
||||
std::vector<subtree > pushed;
|
||||
}; // end class parse_tree
|
||||
|
||||
|
||||
} // end namespace gp_parse_tree
|
||||
|
||||
namespace std
|
||||
{ // for use with stlport on MSVC
|
||||
|
||||
template <class T> inline
|
||||
std::forward_iterator_tag iterator_category(typename gp_parse_tree::parse_tree<T>::embedded_iterator)
|
||||
{
|
||||
return std::forward_iterator_tag();
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
ptrdiff_t* distance_type(typename gp_parse_tree::parse_tree<T>::embedded_iterator)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
std::forward_iterator_tag iterator_category(typename gp_parse_tree::parse_tree<T>::iterator)
|
||||
{
|
||||
return std::forward_iterator_tag();
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
ptrdiff_t* distance_type(typename gp_parse_tree::parse_tree<T>::iterator)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Put customized swaps also in std...
|
||||
|
||||
template<class T> inline
|
||||
void swap(gp_parse_tree::parse_tree<T>& a, gp_parse_tree::parse_tree<T>& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<class T> inline
|
||||
void iter_swap(std::vector<gp_parse_tree::parse_tree<T> >::iterator a, std::vector<gp_parse_tree::parse_tree<T> > b)
|
||||
{
|
||||
a->swap(*b);
|
||||
}*/
|
||||
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue