Added gp, example file in t-eoSymreg.cpp
This commit is contained in:
parent
88c32ee09b
commit
c48c1f2c12
3 changed files with 1381 additions and 0 deletions
238
eo/gp/eoParseTree.h
Normal file
238
eo/gp/eoParseTree.h
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
#ifndef EO_PARSE_TREE_H
|
||||
#define EO_PARSE_TREE_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "EO.h"
|
||||
#include "eoOp.h"
|
||||
#include "eoInserter.h"
|
||||
#include "eoIndiSelector.h"
|
||||
#include "parse_tree.h"
|
||||
#include "eoRnd.h"
|
||||
|
||||
using namespace gp_parse_tree;
|
||||
using namespace std;
|
||||
|
||||
template <class FType, class Node>
|
||||
class eoParseTree : public EO<FType>, public parse_tree<Node>
|
||||
{
|
||||
public :
|
||||
|
||||
typedef typename parse_tree<Node>::subtree Type;
|
||||
|
||||
eoParseTree(void) : EO<FType>(), parse_tree<Node>() {}
|
||||
eoParseTree(unsigned _size, eoRnd<Type>& _rnd)
|
||||
: EO<FType>(), parse_tree<Node>(_rnd())
|
||||
{
|
||||
pruneTree(_size);
|
||||
}
|
||||
|
||||
void pruneTree(unsigned _size)
|
||||
{
|
||||
if (_size < 1)
|
||||
return;
|
||||
|
||||
if (size() > _size)
|
||||
{
|
||||
Type* sub = &operator[](size() - 2); // prune tree
|
||||
|
||||
while (sub->size() > _size)
|
||||
{
|
||||
sub = &sub->operator[](0);
|
||||
}
|
||||
|
||||
back() = *sub;
|
||||
}
|
||||
}
|
||||
|
||||
eoParseTree(std::istream& is) : EO<FType>(), parse_tree<Node>()
|
||||
{
|
||||
readFrom(is);
|
||||
}
|
||||
|
||||
string className(void) const { return "eoParseTree"; }
|
||||
|
||||
void printOn(std::ostream& os) const
|
||||
{
|
||||
os << fitness() << ' ';
|
||||
|
||||
std::copy(ebegin(), eend(), ostream_iterator<Node>(os));
|
||||
}
|
||||
|
||||
void readFrom(std::istream& is)
|
||||
{
|
||||
FType fit;
|
||||
|
||||
is >> fit;
|
||||
|
||||
fitness(fit);
|
||||
|
||||
std::copy(istream_iterator<Node>(is), istream_iterator<Node>(), back_inserter(*this));
|
||||
}
|
||||
};
|
||||
|
||||
template <class FType, class Node>
|
||||
std::ostream& operator<<(std::ostream& os, const eoParseTree<FType, Node>& eot)
|
||||
{
|
||||
eot.printOn(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
template <class FType, class Node>
|
||||
std::istream& operator>>(std::istream& is, eoParseTree<FType, Node>& eot)
|
||||
{
|
||||
eot.readFrom(is);
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class FType, class Node>
|
||||
class eoGpDepthInitializer : public eoRnd< eoParseTree<FType, Node>::Type >
|
||||
{
|
||||
public :
|
||||
|
||||
typedef eoParseTree<FType, Node> EoType;
|
||||
|
||||
eoGpDepthInitializer(
|
||||
unsigned _max_depth,
|
||||
const vector<Node>& _initializor,
|
||||
bool _grow = true)
|
||||
:
|
||||
eoRnd<EoType::Type>(),
|
||||
max_depth(_max_depth),
|
||||
initializor(_initializor),
|
||||
grow(_grow)
|
||||
{}
|
||||
|
||||
virtual string className() const { return "eoDepthInitializer"; };
|
||||
|
||||
EoType::Type operator()(void)
|
||||
{
|
||||
list<Node> sequence;
|
||||
|
||||
generate(sequence, max_depth);
|
||||
|
||||
parse_tree<Node> tree(sequence.begin(), sequence.end());
|
||||
|
||||
return tree.root();
|
||||
}
|
||||
|
||||
void generate(list<Node>& sequence, int the_max, int last_terminal = -1)
|
||||
{
|
||||
if (last_terminal == -1)
|
||||
{ // check where the last terminal in the sequence resides
|
||||
vector<Node>::iterator it;
|
||||
for (it = initializor.begin(); it != initializor.end(); ++it)
|
||||
{
|
||||
if (it->arity() > 1)
|
||||
break;
|
||||
}
|
||||
|
||||
last_terminal = it - initializor.begin();
|
||||
}
|
||||
|
||||
if (the_max == 1)
|
||||
{ // generate terminals only
|
||||
vector<Node>::iterator it = initializor.begin() + rng.random(last_terminal);
|
||||
sequence.push_front(*it);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
sequence.push_front(*what_it);
|
||||
|
||||
for (int i = 0; i < what_it->arity(); ++i)
|
||||
generate(sequence, the_max - 1, last_terminal);
|
||||
}
|
||||
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_depth;
|
||||
std::vector<Node> initializor;
|
||||
bool grow;
|
||||
};
|
||||
|
||||
template<class FType, class Node>
|
||||
class eoSubtreeXOver: public eoGeneralOp< eoParseTree<FType, Node> > {
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType, Node> EoType;
|
||||
|
||||
eoSubtreeXOver( unsigned _max_length)
|
||||
: eoGeneralOp<EoType>(), max_length(_max_length) {};
|
||||
|
||||
virtual string className() const { return "eoSubtreeXOver"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoSubtreeXOver () {};
|
||||
|
||||
void operator()(eoIndiSelector<EoType>& _source, eoInserter<EoType>& _sink ) const
|
||||
{
|
||||
EoType eo1 = _source.select();
|
||||
const EoType& eo2 = _source.select();
|
||||
|
||||
int i = rng.random(eo1.size());
|
||||
int j = rng.random(eo2.size());
|
||||
|
||||
eo1[i] = eo2[j]; // insert subtree
|
||||
|
||||
eo1.pruneTree(max_length);
|
||||
|
||||
eo1.invalidate();
|
||||
_sink.insert(eo1);
|
||||
}
|
||||
|
||||
unsigned max_length;
|
||||
};
|
||||
|
||||
template<class FType, class Node>
|
||||
class eoBranchMutation: public eoGeneralOp< eoParseTree<FType, Node> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef eoParseTree<FType, Node> EoType;
|
||||
|
||||
eoBranchMutation(eoRnd<EoType::Type>& _init, unsigned _max_length)
|
||||
: eoGeneralOp<EoType>(), max_length(_max_length), initializer(_init)
|
||||
{};
|
||||
|
||||
virtual string className() const { return "eoBranchMutation"; };
|
||||
|
||||
/// Dtor
|
||||
virtual ~eoBranchMutation() {};
|
||||
|
||||
void operator()(eoIndiSelector<EoType>& _source, eoInserter<EoType>& _sink ) const
|
||||
{
|
||||
EoType eo1 = _source.select();
|
||||
int i = rng.random(eo1.size());
|
||||
|
||||
EoType eo2(eo1[i].size(), initializer); // create random other to cross with
|
||||
|
||||
eo1[i] = eo2.back(); // insert subtree
|
||||
|
||||
eo1.pruneTree(max_length);
|
||||
|
||||
eo1.invalidate();
|
||||
_sink.insert(eo1);
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
unsigned max_length;
|
||||
eoRnd<EoType::Type>& initializer;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
228
eo/gp/node_pool.h
Normal file
228
eo/gp/node_pool.h
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
|
||||
#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 :
|
||||
Node_alloc() {};
|
||||
|
||||
T* allocate(void)
|
||||
{
|
||||
T* t = static_cast<T*>(mem.allocate());
|
||||
t = new (t) T;
|
||||
//t->T(); // call constructor;
|
||||
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];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
915
eo/gp/parse_tree.h
Normal file
915
eo/gp/parse_tree.h
Normal file
|
|
@ -0,0 +1,915 @@
|
|||
#ifndef PARSE_TREE_HH
|
||||
#define PARSE_TREE_HH
|
||||
|
||||
/**
|
||||
|
||||
* Parse_tree and subtree classes
|
||||
* (c) Maarten Keijzer 1999
|
||||
|
||||
* These classes may be used for educational and
|
||||
* other non-commercial purposes only. Even if I
|
||||
* wanted to, I am not at liberty to place this file
|
||||
* under the GNU Lesser Public Library License, as this
|
||||
* would limit my and my institution's freedom to use
|
||||
* this file in closed-source software.
|
||||
|
||||
* This material is provided "as is", with absolutely no warranty expressed
|
||||
* or implied. Any use is at your own risk.
|
||||
*
|
||||
* Permission to use or copy this software for non-commercial purpose is hereby granted
|
||||
* without fee, provided the above notices are retained on all copies.
|
||||
* 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.
|
||||
*
|
||||
|
||||
|
||||
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(void)
|
||||
|
||||
is the simplest evaluation, it will call
|
||||
|
||||
RetVal Node::operator()(subtree<Node, RetVal>::const_iterator)
|
||||
|
||||
2) parse_tree::apply(It values)
|
||||
|
||||
will call:
|
||||
|
||||
RetVal Node::operator()(subtree<... , It values)
|
||||
|
||||
where It is whatever type you desire (most of the time
|
||||
this will be a vector containing the values of your
|
||||
variables);
|
||||
|
||||
3) parse_tree::apply(It values, It2 moreValues)
|
||||
|
||||
will call:
|
||||
|
||||
RetVal Node::operator()(subtree<... , It values, It2 moreValues)
|
||||
|
||||
although I do not see the immediate use of this, however...
|
||||
|
||||
4) parse_tree::apply(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()(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 vector is:
|
||||
|
||||
vector<Node> vec(tree.size());
|
||||
copy(tree.ebegin(), tree.eend(), vec.begin());
|
||||
|
||||
You can also copy it to an ostream_iterator with this
|
||||
technique, given that your Node implements an appropriate
|
||||
operator<<. Reinitializing a tree with the vector is also
|
||||
simple:
|
||||
|
||||
tree.clear();
|
||||
copy(vec.begin(), vec.end(), 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"
|
||||
|
||||
|
||||
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)
|
||||
#if (defined(__GNUC__) || defined(_MSC_VER)) && !defined(_MT)
|
||||
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;
|
||||
//typedef std::vector<subtree >::const_reverse_iterator const_reverse_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(0), _depth(0), _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 way 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);
|
||||
}
|
||||
|
||||
return copy(s);
|
||||
}
|
||||
|
||||
subtree& operator=(const T& t) { return copy(t); }
|
||||
|
||||
/* 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>
|
||||
RetVal apply(RetVal v) const { return (*content)(v, begin()); }
|
||||
|
||||
template <class RetVal, class It>
|
||||
RetVal apply(RetVal v, It values) const { return (*content)(v, begin(), values); }
|
||||
|
||||
template <class RetVal, class It, class It2>
|
||||
RetVal apply(RetVal v, It values, It2 moreValues) const
|
||||
{ return (*content)(v, begin(), values, moreValues); }
|
||||
|
||||
template <class RetVal, class It, class It2, class It3>
|
||||
RetVal apply(RetVal v, It values, It2 moreValues, It3 evenMoreValues) const
|
||||
{ return (*content)(v, begin(), values, moreValues, evenMoreValues); }
|
||||
|
||||
|
||||
/* 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);
|
||||
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();
|
||||
}
|
||||
|
||||
friend void swap(subtree& x, subtree& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
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 oldArity = arity();
|
||||
|
||||
disown();
|
||||
|
||||
int ar = s.arity();
|
||||
|
||||
if (ar != oldArity)
|
||||
{
|
||||
tree_allocator.deallocate(args, oldArity);
|
||||
|
||||
args = tree_allocator.allocate(ar);
|
||||
|
||||
//if (ar > 0)
|
||||
// args = new subtree [ar];
|
||||
//else
|
||||
// args = 0;
|
||||
}
|
||||
|
||||
switch(ar)
|
||||
{
|
||||
case 3 : args[2].copy(s.args[2]); // no break!
|
||||
case 2 : args[1].copy(s.args[1]);
|
||||
case 1 : args[0].copy(s.args[0]); break;
|
||||
case 0 : break;
|
||||
default :
|
||||
{
|
||||
for (int i = 0; i < ar; ++i)
|
||||
{
|
||||
args[i].copy(s.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*content = *s.content;
|
||||
|
||||
adopt();
|
||||
updateAfterInsert();
|
||||
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>
|
||||
RetVal apply(RetVal v) const
|
||||
{ return _root.apply(v); }
|
||||
|
||||
template <class RetVal, class It>
|
||||
RetVal apply(RetVal v, It varValues) const
|
||||
{ return _root.apply(v, varValues); }
|
||||
|
||||
template <class RetVal, class It, class It2>
|
||||
RetVal apply(RetVal v, It varValues, It2 moreValues) const
|
||||
{ return _root.apply(v, varValues, moreValues); }
|
||||
|
||||
template <class RetVal, class It, class It2, class It3>
|
||||
RetVal apply(RetVal v, It varValues, It2 moreValues, It3 evenMoreValues) const
|
||||
{ return _root.apply(v, varValues, moreValues, evenMoreValues); }
|
||||
|
||||
/* 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
|
||||
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 :
|
||||
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 :
|
||||
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
|
||||
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 :
|
||||
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 :
|
||||
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 (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(gp_parse_tree::parse_tree<T>::embedded_iterator)
|
||||
{
|
||||
return std::forward_iterator_tag();
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
ptrdiff_t* distance_type(gp_parse_tree::parse_tree<T>::embedded_iterator)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
std::forward_iterator_tag iterator_category(gp_parse_tree::parse_tree<T>::iterator)
|
||||
{
|
||||
return std::forward_iterator_tag();
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
ptrdiff_t* distance_type(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(vector<gp_parse_tree::parse_tree<T> >::iterator a, vector<gp_parse_tree::parse_tree<T> > b)
|
||||
{
|
||||
a->swap(*b);
|
||||
}
|
||||
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
#endif
|
||||
Reference in a new issue