From 4ebd212d143d4d48d92b77199bcbcff9f05c8045 Mon Sep 17 00:00:00 2001 From: mac Date: Wed, 16 Feb 2000 15:11:18 +0000 Subject: [PATCH] *** empty log message *** --- eo/src/eoBackInserter.h | 54 ++ eo/src/eoDetTournamentIndiSelector.h | 57 ++ eo/src/eoIndiSelector.h | 134 ++++ eo/src/eoInserter.h | 93 +++ eo/src/eoProportionalGOpSelector.h | 54 ++ eo/src/eoRNG.h | 904 +++++++++++++-------------- eo/src/eoRandomIndiSelector.h | 51 ++ eo/src/eoSequentialGOpSelector.h | 61 ++ eo/src/eoSteadyStateEA.h | 85 +++ eo/src/eoSteadyStateGeneration.h | 88 +++ eo/src/eoSteadyStateInserter.h | 51 ++ eo/src/eoStochTournamentInserter.h | 73 +++ eo/src/eoWrappedOps.h | 221 +++++++ eo/src/rnd_generators.h | 85 +++ eo/src/selectors.h | 313 ++++++++++ 15 files changed, 1872 insertions(+), 452 deletions(-) create mode 100644 eo/src/eoBackInserter.h create mode 100644 eo/src/eoDetTournamentIndiSelector.h create mode 100644 eo/src/eoIndiSelector.h create mode 100644 eo/src/eoInserter.h create mode 100644 eo/src/eoProportionalGOpSelector.h create mode 100644 eo/src/eoRandomIndiSelector.h create mode 100644 eo/src/eoSequentialGOpSelector.h create mode 100644 eo/src/eoSteadyStateEA.h create mode 100644 eo/src/eoSteadyStateGeneration.h create mode 100644 eo/src/eoSteadyStateInserter.h create mode 100644 eo/src/eoStochTournamentInserter.h create mode 100644 eo/src/eoWrappedOps.h create mode 100644 eo/src/rnd_generators.h create mode 100644 eo/src/selectors.h diff --git a/eo/src/eoBackInserter.h b/eo/src/eoBackInserter.h new file mode 100644 index 00000000..c7d1de61 --- /dev/null +++ b/eo/src/eoBackInserter.h @@ -0,0 +1,54 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoInserter.h + Abstract population insertion operator, which is used by the eoGeneralOps + to insert the results in the (intermediate) population. This file also + contains the definitions of a derived classes that implements a back inserter, + probably the only efficient inserter for populations of type vector. + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com) and GeNeura Team, 1999, 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 + */ + +#ifndef eoBackInserter_h +#define eoBackInserter_h + +#include "eoInserter.h" + +/** + * eoBackInserter: Interface class that enables an operator to insert + new individuals at the back of the new population. +*/ +template +class eoBackInserter : public eoPopInserter +{ + public : + + eoBackInserter(void) : eoPopInserter() {} + + void insert(const EOT& _eot) + { + pop().push_back(_eot); + } + + string className(void) const { return "eoBackInserter"; } + +}; + +#endif \ No newline at end of file diff --git a/eo/src/eoDetTournamentIndiSelector.h b/eo/src/eoDetTournamentIndiSelector.h new file mode 100644 index 00000000..45ca2132 --- /dev/null +++ b/eo/src/eoDetTournamentIndiSelector.h @@ -0,0 +1,57 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoDetTournamentIndiSelector.h + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com) and GeNeura Team, 1999, 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 + */ + +#ifndef eoDetTournamentIndiSelector_h +#define eoDetTournamentIndiSelector_h + +#include "eoIndiSelector.h" +#include "selectors.h" + + +/** + * eoDetTournamentIndiSelector: selects children through a deterministic_tournament +*/ +template +class eoDetTournamentIndiSelector : public eoPopIndiSelector +{ + public : + + eoDetTournamentIndiSelector(int _tournamentSize) + : eoPopIndiSelector(), + tournamentSize(_tournamentSize) + {} + + virtual ~eoDetTournamentIndiSelector(void) {} + + const EOT& do_select(void) + { + return *deterministic_tournament(begin(), end(), tournamentSize); + } + + private : + + int tournamentSize; +}; + +#endif \ No newline at end of file diff --git a/eo/src/eoIndiSelector.h b/eo/src/eoIndiSelector.h new file mode 100644 index 00000000..c534404c --- /dev/null +++ b/eo/src/eoIndiSelector.h @@ -0,0 +1,134 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoIndiSelector.h + Abstract selection operator, which is used by the eoGeneralOps + to obtain individuals from a source population. It also gives a + direct descended eoPopIndiSelector that can be used to + initialize objects with an eoPop. For most uses use eoPopIndividualSelector + rather than eoIndividualSelector to derive from. + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com) and GeNeura Team, 1999, 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 + */ + +#ifndef eoIndiSelector_h +#define eoIndiSelector_h + +/** + * eoIndividualSelector: This class defines the interface +*/ +template +class eoIndiSelector +{ +public : + + eoIndiSelector() {} + + virtual ~eoIndiSelector(void) {} + + virtual size_t size(void) const = 0; + virtual const EOT& operator[](size_t) const = 0; + + virtual const EOT& select(void) = 0; + + virtual vector select(size_t _how_many) + { // default implementation just calls select a couple of times + // this can be overridden in favour of a more efficient implementation + vector result(_how_many); + + for (int i = 0; i < _how_many; ++i) + { + result[i] = &select(); + } + + return result; + } +}; + +/** + * eoPopIndiSelector: Intermediate class for dispensing populations + various useful things can be done with this class: + you can specify how many of the population can ever be dispensed to the + operators, but you can also specify a preference to the first guy being + dispensed. This is useful if you want to perform the operator on a specific + individual. +*/ +template +class eoPopIndiSelector : public eoIndiSelector +{ + public : + eoPopIndiSelector(void) : pop(0), firstChoice(-1), last(0), eoIndiSelector() {} + + virtual ~eoPopIndiSelector(void) {} + + struct eoUnitializedException{}; + + /** Initialization function + */ + eoPopIndiSelector& operator()(const eoPop& _pop, int _end = -1, int _myGuy = -1) + { + pop = &_pop; + last = _end; + + if (last < 0 || last > pop->size()) + { + last = pop->size(); + } + + firstChoice = _myGuy; + return *this; + } + + size_t size(void) const { valid(); return last; } + const EOT& operator[](size_t _i) const { valid(); return pop->operator[](_i); } + + eoPop::const_iterator begin(void) const { valid(); return pop->begin(); } + eoPop::const_iterator end(void) const { valid(); return pop->end(); } + + + /// select does the work. Note that it is not virtual. It calls do_select that needs to be implemented by the derived classes + const EOT& select(void) + { + valid(); + if (firstChoice < 0 || firstChoice >= size()) + { + return do_select(); // let the child figure out what to do + } + + const EOT& result = pop->operator[](firstChoice); + firstChoice = -1; + return result; + } + + virtual const EOT& do_select(void) = 0; + + private : + + void valid(void) const + { + if (pop == 0) + throw eoUnitializedException(); + } + + const eoPop* pop; // need a pointer as this the pop argument can be re-instated + int last; + int firstChoice; +}; + +#endif \ No newline at end of file diff --git a/eo/src/eoInserter.h b/eo/src/eoInserter.h new file mode 100644 index 00000000..a799beb8 --- /dev/null +++ b/eo/src/eoInserter.h @@ -0,0 +1,93 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoInserter.h + Abstract population insertion operator, which is used by the eoGeneralOps + to insert the results in the (intermediate) population. It also contains + a direct descended eoPopInserter that defines a convenient inbetween class + for working with eoPop. The user will most likely derive from eoPopInserter + rather than eoInserter. + + (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 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 + */ + +#ifndef eoInserter_h +#define eoInserter_h + +#include "eoObject.h" + +/** + * eoInserter: Interface class that enables an operator to insert + new individuals into the (intermediate) population. +*/ +template +class eoInserter : public eoObject +{ + public : + virtual ~eoInserter() {} + + struct eoInserterException{}; + + virtual void insert(const EOT&) = 0; // can throw an eoInserterException +}; + +/** + * eoPopInserter: In-between class that defines an initialization + * of the eoIndividualInserter. +*/ +template +class eoPopInserter : public eoInserter +{ + public : + + eoPopInserter(void) : thePop(0), eoInserter() {} + + /// Binds the population to this class. This is an initialization routine used by breeders + eoInserter& operator()(eoPop& _pop) + { + thePop = &_pop; + return *this; + } + + protected : + + eoPop& pop(void) const { valid(); return *thePop; } + + private : + + void valid(void) const + { + if (thePop == 0) + throw eoInserterException(); + } + + // Need a pointer as the inserter should be able to bind to different populations. + // This is caused by the 'one template parameter only' convention in EO. + + eoPop* thePop; + + // If eoGOpBreeder could be templatized over the inserter and the selector, + // the pop could be a ref as this class could be created every time it is applied + // and subsequently would get the population through the constructor + +}; + + + +#endif diff --git a/eo/src/eoProportionalGOpSelector.h b/eo/src/eoProportionalGOpSelector.h new file mode 100644 index 00000000..6a1b2d97 --- /dev/null +++ b/eo/src/eoProportionalGOpSelector.h @@ -0,0 +1,54 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoProportionalGOpSelector.h + Proportional Generalized Operator Selector. + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com), GeNeura Team 1998, 1999, 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 +*/ + +#ifndef eoProportionalGOpSelector_h +#define eoProportionalGOpSelector_h + +//----------------------------------------------------------------------------- + +#include "eoGOpSelector.h" + +/** eoProportionalGOpSel: do proportional selection, returns one of the + operators +*/ +template +class eoProportionalGOpSel : public eoGOpSelector +{ +public : + eoProportionalGOpSel() : eoGOpSelector() {} + + /** Returns the operator proportionally selected */ + virtual eoGeneralOp& selectOp() + { + unsigned what = rng.roulette_wheel(getRates()); + return *operator[](what); + } + + /// + virtual string className() const { return "eoGOpSelector"; }; +}; + +#endif + diff --git a/eo/src/eoRNG.h b/eo/src/eoRNG.h index 8957755c..59417fc6 100644 --- a/eo/src/eoRNG.h +++ b/eo/src/eoRNG.h @@ -1,452 +1,452 @@ -/* -* Random number generator adapted from (see comments below) -* -* The random number generator is modified into a class -* by Maarten Keijzer (mak@dhi.dk). Also added the Box-Muller -* transformation to generate normal deviates. -* - 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 -*/ - -/* ************ DOCUMENTATION IN ORIGINAL FILE *********************/ - -// This is the ``Mersenne Twister'' random number generator MT19937, which -// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) -// starting from any odd seed in 0..(2^32 - 1). This version is a recode -// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by -// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in -// July-August 1997). -// -// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha -// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to -// generate 300 million random numbers; after recoding: 24.0 sec. for the same -// (i.e., 46.5% of original time), so speed is now about 12.5 million random -// number generations per second on this machine. -// -// According to the URL -// (and paraphrasing a bit in places), the Mersenne Twister is ``designed -// with consideration of the flaws of various existing generators,'' has -// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally -// equidistributed, and ``has passed many stringent tests, including the -// die-hard test of G. Marsaglia and the load test of P. Hellekalek and -// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 -// to 5012 bytes of static data, depending on data type sizes, and the code -// is quite short as well). It generates random numbers in batches of 624 -// at a time, so the caching and pipelining of modern systems is exploited. -// It is also divide- and mod-free. -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Library 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 Library General Public License for more details. You should have -// received a copy of the GNU Library 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. -// -// The code as Shawn received it included the following notice: -// -// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When -// you use this, send an e-mail to with -// an appropriate reference to your work. -// -// It would be nice to CC: when you write. -// - -// -// uint32 must be an unsigned integer type capable of holding at least 32 -// bits; exactly 32 should be fastest, but 64 is better on an Alpha with -// GCC at -O3 optimization so try your options and see what's best for you -// - -/* ************ END DOCUMENTATION IN ORIGINAL FILE *********************/ - - -#ifndef EO_RANDOM_NUMBER_GENERATOR -#define EO_RANDOM_NUMBER_GENERATOR - -#include - -#include -#include - -// TODO: check for various compilers if this is exactly 32 bits -// Unfortunately MSVC's preprocessor does not comprehends sizeof() -// so neat preprocessing tricks will not work - -typedef unsigned long uint32; // Compiler and platform dependent! - -//----------------------------------------------------------------------------- -// eoRng -//----------------------------------------------------------------------------- -/** -eoRng is a persitent class that uses the ``Mersenne Twister'' random number generator MT19937 -for generating random numbers. The various member functions implement useful functions -for evolutionary algorithms. Included are: rand(), random(), flip() and normal(). - -Note for people porting EO to other platforms: please make sure that the typedef -uint32 in the file eoRng.h is exactly 32 bits long. It may be longer, but not -shorter. If it is longer, file compatibility between EO on different platforms -may be broken. -*/ -class eoRng : public eoObject, public eoPersistent -{ -public : - /** - ctor takes a random seed; if you want another seed, use reseed - @see reseed - */ - - eoRng(uint32 s = (uint32) time(0) ) : state(0), next(0), left(-1), cached(false), N(624), M(397), K(0x9908B0DFU) { - state = new uint32[N+1]; - initialize(s); - } - - ~eoRng(void) - { - delete [] state; - } - - /** - Re-initializes the Random Number Generator. - */ - void reseed(uint32 s) - { - initialize(s); - } - - /** - uniform(m = 1.0) returns a random double in the range [0, m) - */ - double uniform(double m = 1.0) - { // random number between [0, m] - return m * double(rand()) / double(rand_max()); - } - - /** - random() returns a random integer in the range [0, m) - */ - uint32 random(uint32 m) - { - return uint32(uniform() * double(m)); - } - - /** - flip() tosses a biased coin such that flip(x/100.0) will - returns true x% of the time - */ - bool flip(float bias) - { - return uniform() < bias; - } - - /** - normal() zero mean gaussian deviate with standard deviation of 1 - */ - double normal(void); // gaussian mutation, stdev 1 - - /** - normal(stdev) zero mean gaussian deviate with user defined standard deviation - */ - double normal(double stdev) - { - return stdev * normal(); - } - - /** - normal(mean, stdev) user defined mean gaussian deviate with user defined standard deviation - */ - double normal(double mean, double stdev) - { - return mean + normal(stdev); - } - - /** - rand() returns a random number in the range [0, rand_max) - */ - uint32 rand(); - - /** - rand_max() the maximum returned by rand() - */ - uint32 rand_max(void) const { return (uint32) 0xffffffff; } - - /** - roulette_wheel(vec, total = 0) does a roulette wheel selection - on the input vector vec. If the total is not supplied, it is - calculated. It returns an integer denoting the selected argument. - */ - template - int roulette_wheel(const std::vector& vec, T total = 0) - { - if (total == 0) - { // count - for (unsigned i = 0; i < vec.size(); ++i) - total += vec[i]; - } - - float change = uniform() * total; - - int i = 0; - - while (change > 0) - { - change -= vec[i++]; - } - - return --i; - } - - /// - void printOn(ostream& _os) const - { - for (int i = 0; i < N; ++i) - { - _os << state[i] << ' '; - } - _os << int(next - state) << ' '; - _os << left << ' ' << cached << ' ' << cacheValue; - } - - /// - void readFrom(istream& _is) - { - for (int i = 0; i < N; ++i) - { - _is >> state[i]; - } - - int n; - _is >> n; - next = state + n; - - _is >> left; - _is >> cached; - _is >> cacheValue; - } - - -private : - uint32 restart(void); - void initialize(uint32 seed); - - uint32* state; // the array for the state - uint32* next; - int left; - - bool cached; - float cacheValue; - - const int N; - const int M; - const uint32 K; // a magic constant - - /** - Private copy ctor and assignment operator to make sure that - nobody accidentally copies the random number generator. - If you want similar RNG's, make two RNG's and initialize - them with the same seed. - */ - eoRng (const eoRng&); // no implementation - eoRng& operator=(const eoRng&); // dito -}; - -/** - The one and only global eoRng object -*/ -static eoRng rng; - -/** - The class uniform_generator can be used in the STL generate function - to easily generate random floats and doubles between [0, _max). _max - defaults to 1.0 -*/ -template class uniform_generator -{ - public : - uniform_generator(T _max = T(1.0), eoRng& _rng = rng) : maxim(_max), uniform(_rng) {} - - virtual T operator()(void) { return (T) uniform.uniform(maxim); } - private : - T maxim; - eoRng& uniform; -}; - -/** - The class random_generator can be used in the STL generate function - to easily generate random ints between [0, _max). -*/ -template class random_generator -{ - public : - random_generator(int _max, eoRng& _rng = rng) : maxim(_max), random(_rng) {} - - virtual T operator()(void) { return (T) random.random(max); } - - private : - T maxim; - eoRng& random; -}; - -/** - The class normal_generator can be used in the STL generate function - to easily generate gaussian distributed floats and doubles. The user - can supply a standard deviation which defaults to 1. -*/ -template class normal_generator -{ - public : - normal_generator(T _stdev = T(1.0), eoRng& _rng = rng) : stdev(_stdev), normal(_rng) {} - - virtual T operator()(void) { return (T) normal.normal(stdev); } - - private : - T stdev; - eoRng& normal; -}; - -// Implementation of some eoRng members.... Don't mind the mess, it does work. - - -#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u -#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u -#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u -#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v - -inline void eoRng::initialize(uint32 seed) - { - // - // We initialize state[0..(N-1)] via the generator - // - // x_new = (69069 * x_old) mod 2^32 - // - // from Line 15 of Table 1, p. 106, Sec. 3.3.4 of Knuth's - // _The Art of Computer Programming_, Volume 2, 3rd ed. - // - // Notes (SJC): I do not know what the initial state requirements - // of the Mersenne Twister are, but it seems this seeding generator - // could be better. It achieves the maximum period for its modulus - // (2^30) iff x_initial is odd (p. 20-21, Sec. 3.2.1.2, Knuth); if - // x_initial can be even, you have sequences like 0, 0, 0, ...; - // 2^31, 2^31, 2^31, ...; 2^30, 2^30, 2^30, ...; 2^29, 2^29 + 2^31, - // 2^29, 2^29 + 2^31, ..., etc. so I force seed to be odd below. - // - // Even if x_initial is odd, if x_initial is 1 mod 4 then - // - // the lowest bit of x is always 1, - // the next-to-lowest bit of x is always 0, - // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... , - // the 3rd-from-lowest bit of x 4-cycles ... 0 1 1 0 0 1 1 0 ... , - // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 0 1 1 1 1 0 ... , - // ... - // - // and if x_initial is 3 mod 4 then - // - // the lowest bit of x is always 1, - // the next-to-lowest bit of x is always 1, - // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... , - // the 3rd-from-lowest bit of x 4-cycles ... 0 0 1 1 0 0 1 1 ... , - // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 1 1 1 1 0 0 ... , - // ... - // - // The generator's potency (min. s>=0 with (69069-1)^s = 0 mod 2^32) is - // 16, which seems to be alright by p. 25, Sec. 3.2.1.3 of Knuth. It - // also does well in the dimension 2..5 spectral tests, but it could be - // better in dimension 6 (Line 15, Table 1, p. 106, Sec. 3.3.4, Knuth). - // - // Note that the random number user does not see the values generated - // here directly since restart() will always munge them first, so maybe - // none of all of this matters. In fact, the seed values made here could - // even be extra-special desirable if the Mersenne Twister theory says - // so-- that's why the only change I made is to restrict to odd seeds. - // - - left = -1; - - register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = state; - register int j; - - for(left=0, *s++=x, j=N; --j; - *s++ = (x*=69069U) & 0xFFFFFFFFU); - } - - -inline uint32 eoRng::restart(void) -{ - register uint32 *p0=state, *p2=state+2, *pM=state+M, s0, s1; - register int j; - - left=N-1, next=state+1; - - for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++) - *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); - - for(pM=state, j=M; --j; s0=s1, s1=*p2++) - *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); - - s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); - s1 ^= (s1 >> 11); - s1 ^= (s1 << 7) & 0x9D2C5680U; - s1 ^= (s1 << 15) & 0xEFC60000U; - return(s1 ^ (s1 >> 18)); -} - - -inline uint32 eoRng::rand(void) - { - uint32 y; - - if(--left < 0) - return(restart()); - - y = *next++; - y ^= (y >> 11); - y ^= (y << 7) & 0x9D2C5680U; - y ^= (y << 15) & 0xEFC60000U; - return(y ^ (y >> 18)); - } - -inline double eoRng::normal(void) -{ - if (cached) - { - cached = false; - return cacheValue; - } - - float rSquare, factor, var1, var2; - - do - { - var1 = 2.0 * uniform() - 1.0; - var2 = 2.0 * uniform() - 1.0; - - rSquare = var1 * var1 + var2 * var2; - } - while (rSquare >= 1.0 || rSquare == 0.0); - - factor = sqrt(-2.0 * log(rSquare) / rSquare); - - cacheValue = var1 * factor; - cached = true; - - return (var2 * factor); -} - -#endif +/* +* Random number generator adapted from (see comments below) +* +* The random number generator is modified into a class +* by Maarten Keijzer (mak@dhi.dk). Also added the Box-Muller +* transformation to generate normal deviates. +* + 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 +*/ + +/* ************ DOCUMENTATION IN ORIGINAL FILE *********************/ + +// This is the ``Mersenne Twister'' random number generator MT19937, which +// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) +// starting from any odd seed in 0..(2^32 - 1). This version is a recode +// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by +// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in +// July-August 1997). +// +// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha +// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to +// generate 300 million random numbers; after recoding: 24.0 sec. for the same +// (i.e., 46.5% of original time), so speed is now about 12.5 million random +// number generations per second on this machine. +// +// According to the URL +// (and paraphrasing a bit in places), the Mersenne Twister is ``designed +// with consideration of the flaws of various existing generators,'' has +// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally +// equidistributed, and ``has passed many stringent tests, including the +// die-hard test of G. Marsaglia and the load test of P. Hellekalek and +// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 +// to 5012 bytes of static data, depending on data type sizes, and the code +// is quite short as well). It generates random numbers in batches of 624 +// at a time, so the caching and pipelining of modern systems is exploited. +// It is also divide- and mod-free. +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library 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 Library General Public License for more details. You should have +// received a copy of the GNU Library 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. +// +// The code as Shawn received it included the following notice: +// +// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When +// you use this, send an e-mail to with +// an appropriate reference to your work. +// +// It would be nice to CC: when you write. +// + +// +// uint32 must be an unsigned integer type capable of holding at least 32 +// bits; exactly 32 should be fastest, but 64 is better on an Alpha with +// GCC at -O3 optimization so try your options and see what's best for you +// + +/* ************ END DOCUMENTATION IN ORIGINAL FILE *********************/ + + +#ifndef EO_RANDOM_NUMBER_GENERATOR +#define EO_RANDOM_NUMBER_GENERATOR + +#include + +#include +#include + +// TODO: check for various compilers if this is exactly 32 bits +// Unfortunately MSVC's preprocessor does not comprehends sizeof() +// so neat preprocessing tricks will not work + +typedef unsigned long uint32; // Compiler and platform dependent! + +//----------------------------------------------------------------------------- +// eoRng +//----------------------------------------------------------------------------- +/** +eoRng is a persitent class that uses the ``Mersenne Twister'' random number generator MT19937 +for generating random numbers. The various member functions implement useful functions +for evolutionary algorithms. Included are: rand(), random(), flip() and normal(). + +Note for people porting EO to other platforms: please make sure that the typedef +uint32 in the file eoRng.h is exactly 32 bits long. It may be longer, but not +shorter. If it is longer, file compatibility between EO on different platforms +may be broken. +*/ +class eoRng : public eoObject, public eoPersistent +{ +public : + /** + ctor takes a random seed; if you want another seed, use reseed + @see reseed + */ + + eoRng(uint32 s = (uint32) time(0) ) : state(0), next(0), left(-1), cached(false), N(624), M(397), K(0x9908B0DFU) { + state = new uint32[N+1]; + initialize(s); + } + + ~eoRng(void) + { + delete [] state; + } + + /** + Re-initializes the Random Number Generator. + */ + void reseed(uint32 s) + { + initialize(s); + } + + /** + uniform(m = 1.0) returns a random double in the range [0, m) + */ + double uniform(double m = 1.0) + { // random number between [0, m] + return m * double(rand()) / double(rand_max()); + } + + /** + random() returns a random integer in the range [0, m) + */ + uint32 random(uint32 m) + { + return uint32(uniform() * double(m)); + } + + /** + flip() tosses a biased coin such that flip(x/100.0) will + returns true x% of the time + */ + bool flip(float bias) + { + return uniform() < bias; + } + + /** + normal() zero mean gaussian deviate with standard deviation of 1 + */ + double normal(void); // gaussian mutation, stdev 1 + + /** + normal(stdev) zero mean gaussian deviate with user defined standard deviation + */ + double normal(double stdev) + { + return stdev * normal(); + } + + /** + normal(mean, stdev) user defined mean gaussian deviate with user defined standard deviation + */ + double normal(double mean, double stdev) + { + return mean + normal(stdev); + } + + /** + rand() returns a random number in the range [0, rand_max) + */ + uint32 rand(); + + /** + rand_max() the maximum returned by rand() + */ + uint32 rand_max(void) const { return (uint32) 0xffffffff; } + + /** + roulette_wheel(vec, total = 0) does a roulette wheel selection + on the input vector vec. If the total is not supplied, it is + calculated. It returns an integer denoting the selected argument. + */ + template + int roulette_wheel(const std::vector& vec, T total = 0) + { + if (total == 0) + { // count + for (int i = 0; i < vec.size(); ++i) + total += vec[i]; + } + + float change = uniform() * total; + + int i = 0; + + while (change > 0) + { + change -= vec[i++]; + } + + return --i; + } + + /// + void printOn(ostream& _os) const + { + for (int i = 0; i < N; ++i) + { + _os << state[i] << ' '; + } + _os << int(next - state) << ' '; + _os << left << ' ' << cached << ' ' << cacheValue; + } + + /// + void readFrom(istream& _is) + { + for (int i = 0; i < N; ++i) + { + _is >> state[i]; + } + + int n; + _is >> n; + next = state + n; + + _is >> left; + _is >> cached; + _is >> cacheValue; + } + + +private : + uint32 restart(void); + void initialize(uint32 seed); + + uint32* state; // the array for the state + uint32* next; + int left; + + bool cached; + float cacheValue; + + const int N; + const int M; + const uint32 K; // a magic constant + + /** + Private copy ctor and assignment operator to make sure that + nobody accidentally copies the random number generator. + If you want similar RNG's, make two RNG's and initialize + them with the same seed. + */ + eoRng (const eoRng&); // no implementation + eoRng& operator=(const eoRng&); // dito +}; + +/** + The one and only global eoRng object +*/ +static eoRng rng; + +/** + The class uniform_generator can be used in the STL generate function + to easily generate random floats and doubles between [0, _max). _max + defaults to 1.0 +*/ +template class uniform_generator +{ + public : + uniform_generator(T _max = T(1.0), eoRng& _rng = rng) : maxim(_max), uniform(_rng) {} + + virtual T operator()(void) { return (T) uniform.uniform(maxim); } + private : + T maxim; + eoRng& uniform; +}; + +/** + The class random_generator can be used in the STL generate function + to easily generate random ints between [0, _max). +*/ +template class random_generator +{ + public : + random_generator(int _max, eoRng& _rng = rng) : maxim(_max), random(_rng) {} + + virtual T operator()(void) { return (T) random.random(max); } + + private : + T maxim; + eoRng& random; +}; + +/** + The class normal_generator can be used in the STL generate function + to easily generate gaussian distributed floats and doubles. The user + can supply a standard deviation which defaults to 1. +*/ +template class normal_generator +{ + public : + normal_generator(T _stdev = T(1.0), eoRng& _rng = rng) : stdev(_stdev), normal(_rng) {} + + virtual T operator()(void) { return (T) normal.normal(stdev); } + + private : + T stdev; + eoRng& normal; +}; + +// Implementation of some eoRng members.... Don't mind the mess, it does work. + + +#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u +#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u +#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u +#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v + +inline void eoRng::initialize(uint32 seed) + { + // + // We initialize state[0..(N-1)] via the generator + // + // x_new = (69069 * x_old) mod 2^32 + // + // from Line 15 of Table 1, p. 106, Sec. 3.3.4 of Knuth's + // _The Art of Computer Programming_, Volume 2, 3rd ed. + // + // Notes (SJC): I do not know what the initial state requirements + // of the Mersenne Twister are, but it seems this seeding generator + // could be better. It achieves the maximum period for its modulus + // (2^30) iff x_initial is odd (p. 20-21, Sec. 3.2.1.2, Knuth); if + // x_initial can be even, you have sequences like 0, 0, 0, ...; + // 2^31, 2^31, 2^31, ...; 2^30, 2^30, 2^30, ...; 2^29, 2^29 + 2^31, + // 2^29, 2^29 + 2^31, ..., etc. so I force seed to be odd below. + // + // Even if x_initial is odd, if x_initial is 1 mod 4 then + // + // the lowest bit of x is always 1, + // the next-to-lowest bit of x is always 0, + // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... , + // the 3rd-from-lowest bit of x 4-cycles ... 0 1 1 0 0 1 1 0 ... , + // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 0 1 1 1 1 0 ... , + // ... + // + // and if x_initial is 3 mod 4 then + // + // the lowest bit of x is always 1, + // the next-to-lowest bit of x is always 1, + // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... , + // the 3rd-from-lowest bit of x 4-cycles ... 0 0 1 1 0 0 1 1 ... , + // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 1 1 1 1 0 0 ... , + // ... + // + // The generator's potency (min. s>=0 with (69069-1)^s = 0 mod 2^32) is + // 16, which seems to be alright by p. 25, Sec. 3.2.1.3 of Knuth. It + // also does well in the dimension 2..5 spectral tests, but it could be + // better in dimension 6 (Line 15, Table 1, p. 106, Sec. 3.3.4, Knuth). + // + // Note that the random number user does not see the values generated + // here directly since restart() will always munge them first, so maybe + // none of all of this matters. In fact, the seed values made here could + // even be extra-special desirable if the Mersenne Twister theory says + // so-- that's why the only change I made is to restrict to odd seeds. + // + + left = -1; + + register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = state; + register int j; + + for(left=0, *s++=x, j=N; --j; + *s++ = (x*=69069U) & 0xFFFFFFFFU); + } + + +inline uint32 eoRng::restart(void) +{ + register uint32 *p0=state, *p2=state+2, *pM=state+M, s0, s1; + register int j; + + left=N-1, next=state+1; + + for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++) + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + + for(pM=state, j=M; --j; s0=s1, s1=*p2++) + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + + s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + s1 ^= (s1 >> 11); + s1 ^= (s1 << 7) & 0x9D2C5680U; + s1 ^= (s1 << 15) & 0xEFC60000U; + return(s1 ^ (s1 >> 18)); +} + + +inline uint32 eoRng::rand(void) + { + uint32 y; + + if(--left < 0) + return(restart()); + + y = *next++; + y ^= (y >> 11); + y ^= (y << 7) & 0x9D2C5680U; + y ^= (y << 15) & 0xEFC60000U; + return(y ^ (y >> 18)); + } + +inline double eoRng::normal(void) +{ + if (cached) + { + cached = false; + return cacheValue; + } + + float rSquare, factor, var1, var2; + + do + { + var1 = 2.0 * uniform() - 1.0; + var2 = 2.0 * uniform() - 1.0; + + rSquare = var1 * var1 + var2 * var2; + } + while (rSquare >= 1.0 || rSquare == 0.0); + + factor = sqrt(-2.0 * log(rSquare) / rSquare); + + cacheValue = var1 * factor; + cached = true; + + return (var2 * factor); +} + +#endif diff --git a/eo/src/eoRandomIndiSelector.h b/eo/src/eoRandomIndiSelector.h new file mode 100644 index 00000000..2be2ba4c --- /dev/null +++ b/eo/src/eoRandomIndiSelector.h @@ -0,0 +1,51 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoRandomIndiSelector.h + Selects individuals at random. + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com) and GeNeura Team, 1999, 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 + */ + +#ifndef eoRandomIndiSelector_h +#define eoRandomIndiSelector_h + +#include "eoIndiSelector.h" + +/** + * eoRandomSelector: just selects a random child +*/ +template +class eoRandomIndiSelector : public eoPopIndiSelector +{ + public : + + eoRandomIndiSelector(void) : eoPopIndiSelector() {} + virtual ~eoRandomIndiSelector(void) {} + + /// very complex function that returns just an individual + const EOT& do_select(void) + { + return operator[](rng.random(size())); + } + +}; + +#endif + diff --git a/eo/src/eoSequentialGOpSelector.h b/eo/src/eoSequentialGOpSelector.h new file mode 100644 index 00000000..5d899041 --- /dev/null +++ b/eo/src/eoSequentialGOpSelector.h @@ -0,0 +1,61 @@ +/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoSequentialGOpSelector.h + Sequential Generalized Operator Selector. + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com), GeNeura Team 1998, 1999, 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 +*/ + +#ifndef eoSequentialGOpSelector_h +#define eoSequentialGOpSelector_h + +//----------------------------------------------------------------------------- + +#include "eoGOpSelector.h" +/** eoSequentialGOpSel: do proportional selection, but return a sequence of + operations to be applied one after the other. +*/ +template +class eoSequentialGOpSel : public eoGOpSelector +{ + public : + + virtual eoGeneralOp& selectOp() + { + combined.clear(); + + for (int i = 0; i < size(); ++i) + { + if (operator[](i) == 0) + continue; + + if (rng.flip(getRates()[i])) + combined.addOp(operator[](i)); + } + + return combined; + } + + private : + + eoCombinedOp combined; +}; + +#endif diff --git a/eo/src/eoSteadyStateEA.h b/eo/src/eoSteadyStateEA.h new file mode 100644 index 00000000..fffe659c --- /dev/null +++ b/eo/src/eoSteadyStateEA.h @@ -0,0 +1,85 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// eoSteadyStateEA.h +// (c) GeNeura Team, 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 + */ +//----------------------------------------------------------------------------- + +#ifndef _eoSteadyStateEA_h +#define _eoSteadyStateEA_h + +//----------------------------------------------------------------------------- + +#include "eoSteadyStateGeneration.h" // eoPop +#include + +/** EOSteadyStateEA: + An easy-to-use evolutionary algorithm, just supply + a general operator selector, a selector for choosing the ones + to reproduce and an eoSteadyStateInserter that takes care of evaluating + and inserter the guy/girl in the steady state population. +*/ +template class eoSteadyStateEA: public eoAlgo +{ + public: + /// Constructor. + eoSteadyStateEA( + eoGOpSelector& _opSelector, + eoPopIndiSelector& _selector, + eoSteadyStateInserter& _inserter, + eoTerm& _terminator, + unsigned _steps = 0 ) + : step(_opSelector, _selector, _inserter), + terminator( _terminator) + {}; + + /// Constructor from an already created generation + eoSteadyStateEA(eoSteadyStateGeneration& _gen, + eoTerm& _terminator): + step(_gen), + terminator( _terminator){}; + + /// Apply one generation of evolution to the population. + virtual void operator()(eoPop& pop) { + do { + try + { + step(pop); + } + catch (exception& e) + { + string s = e.what(); + s.append( " in eoSteadyStateEA "); + throw runtime_error( s ); + } + } while ( terminator( pop ) ); + } + + /// Class name. + string className() const { return "eoSteadyStateEA"; } + + private: + eoSteadyStateGeneration step; + eoTerm& terminator; +}; + +//----------------------------------------------------------------------------- + +#endif eoEasyEA_h diff --git a/eo/src/eoSteadyStateGeneration.h b/eo/src/eoSteadyStateGeneration.h new file mode 100644 index 00000000..1c1aeebc --- /dev/null +++ b/eo/src/eoSteadyStateGeneration.h @@ -0,0 +1,88 @@ +// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + +//----------------------------------------------------------------------------- +// eoSteadyStateGeneration.h +// (c) GeNeura Team, 1998 +/* + 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 + */ +//----------------------------------------------------------------------------- + +#ifndef eoSteadyStateGeneration_h +#define eoSteadyStateGeneration_h + +//----------------------------------------------------------------------------- + +#include // eoPop +#include +#include // eoSelect, eoTranform, eoMerge + +#include "eoGOpSelector.h" +#include "eoIndiSelector.h" +#include "eoSteadyStateInserter.h" + +//----------------------------------------------------------------------------- + +/** eoSteadyStateGeneration + * Single step of a steady state evolutionary algorithm. + * Proceeds by updating one individual at a time, by first selecting parents, + * creating one or more children and subsequently overwrite (a) bad individual(s) +*/ +template class eoSteadyStateGeneration: public eoAlgo +{ + public: + /// Constructor. + eoSteadyStateGeneration( + eoGOpSelector& _opSelector, + eoPopIndiSelector& _selector, + eoSteadyStateInserter& _inserter, + unsigned _steps = 0) : + opSelector(_opSelector), + selector(_selector), + inserter(_inserter) , + steps(_steps) {}; + + + /// Apply one generation of evolution to the population. + virtual void operator()(eoPop& pop) + { + unsigned nSteps = steps; + if (nSteps == 0) + { + nSteps = pop.size(); // make a 'generation equivalent' + } + + for (unsigned i = 0; i < nSteps; ++i) + { + opSelector.selectOp()(selector(pop), inserter(pop)); + } + + } + + /// Class name. + string className() const { return "eoSteadyStateGeneration"; } + + private: + eoGOpSelector& opSelector; + eoPopIndiSelector& selector; + eoSteadyStateInserter& inserter; + unsigned steps; +}; + +//----------------------------------------------------------------------------- + +#endif eoGeneration_h diff --git a/eo/src/eoSteadyStateInserter.h b/eo/src/eoSteadyStateInserter.h new file mode 100644 index 00000000..26f299f7 --- /dev/null +++ b/eo/src/eoSteadyStateInserter.h @@ -0,0 +1,51 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoSteadyStateInserter.h + Still abstract population insertion operator that is initialized with + and eoEvalFunc object to be able to evaluate individuals before inserting + them. + + (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 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 + */ + +#ifndef eoSteadyStateInserter_h +#define eoSteadyStateInserter_h + + +#include "eoEvalFunc.h" + +/** + * eoSteadyStateInserter: Interface class that enables an operator to update + * a population with a new individual... it contains an eoEvalFunc object to + * make sure that every individual is evaluated before it is inserted +*/ +template +class eoSteadyStateInserter : public eoPopInserter +{ + public : + eoSteadyStateInserter(eoEvalFunc& _eval) : eval(_eval) , eoPopInserter() {} + + protected : + + eoEvalFunc& eval; +}; + + +#endif \ No newline at end of file diff --git a/eo/src/eoStochTournamentInserter.h b/eo/src/eoStochTournamentInserter.h new file mode 100644 index 00000000..f91b546f --- /dev/null +++ b/eo/src/eoStochTournamentInserter.h @@ -0,0 +1,73 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoStochTournamentInserter.h + Concrete steady state inserter. It is initialized with a population and + inserts individuals in the population based on an inverse stochastic + tournament + + (c) Maarten Keijzer (mkeijzer@mad.scientist.com) and GeNeura Team, 1999, 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 + */ + +#ifndef eoStochTournamentInserter_h +#define eoStochTournamentInserter_h + + +#include "eoSteadyStateInserter.h" +#include "selectors.h" + +/** + * eoDetTournamentInserter: Uses an inverse stochastic tournament to figure + * out who gets overridden by the new individual. It resets the fitness of the + * individual. +*/ +template +class eoStochTournamentInserter : public eoSteadyStateInserter +{ + public : + + eoStochTournamentInserter(eoEvalFunc& _eval, double _t_rate) : t_rate(_t_rate), eoSteadyStateInserter(_eval) + { + if (t_rate < 0.5) + { // warning, error? + t_rate = 0.55; + } + + if (t_rate >= 1.0) + { + t_rate = 0.99; // 1.0 would mean deterministic tournament + } + } + + void insert(const EOT& _eot) + { + EOT& eo = inverse_stochastic_tournament(pop(), t_rate); + eo = _eot; // overwrite loser of tournament + + eo.invalidate(); + eval(eo); // Evaluate after insert + } + + string className(void) const { return "eoStochTournamentInserter"; } + + private : + double t_rate; +}; + +#endif \ No newline at end of file diff --git a/eo/src/eoWrappedOps.h b/eo/src/eoWrappedOps.h new file mode 100644 index 00000000..cc332a0b --- /dev/null +++ b/eo/src/eoWrappedOps.h @@ -0,0 +1,221 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + eoWrappedOps.h + Derived from the General genetic operator, which can be used to wrap any unary or binary + operator. File also contains the eoCombinedOp, needed by the eoSequentialGOpSelector + + (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 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 + */ + +//----------------------------------------------------------------------------- + +#ifndef eoWrappedOps_h +#define eoWrappedOps_h + +//----------------------------------------------------------------------------- + +#include // eoOp, eoMonOp, eoBinOp +#include "eoRNG.h" + +using namespace std; + +/// Wraps monary operators +template +class eoWrappedMonOp : public eoGeneralOp +{ +public : + /// + eoWrappedMonOp(const eoMonOp& _op) : eoGeneralOp(), op(_op) {}; + + /// + virtual ~eoWrappedMonOp() {} + + /// Instantiates the abstract method + void operator()( eoIndiSelector& _in, + eoInserter& _out) const { + EOT result = _in.select(); + op( result ); + _out.insert(result); + } + + /// + virtual string className() const {return "eoWrappedMonOp";}; + + +private : + const eoMonOp& op; +}; + + +/// Wraps binary operators +template +class eoWrappedBinOp : public eoGeneralOp +{ +public : + /// + eoWrappedBinOp(const eoBinOp& _op) : eoGeneralOp(), op(_op) {} + + /// + virtual ~eoWrappedBinOp() {} + + /// Instantiates the abstract method. EOT should have copy ctor. + void operator()(eoIndiSelector& _in, + eoInserter& _out) const { + EOT out1 = _in.select(); + const EOT& out2 = _in.select(); + op(out1, out2); + _out.insert(out1); + } + + /// + virtual string className() const {return "eoWrappedBinOp";}; + +private : + const eoBinOp& op; +}; + +/// Wraps Quadratic operators +template +class eoWrappedQuadraticOp : public eoGeneralOp +{ +public : + /// + eoWrappedQuadraticOp(const eoQuadraticOp& _op) : eoGeneralOp(), op(_op) {} + + /// + virtual ~eoWrappedQuadraticOp() {} + + /// Instantiates the abstract method. EOT should have copy ctor. + void operator()(eoIndiSelector& _in, + eoInserter& _out) const { + EOT out1 = _in.select(); + EOT out2 = _in.select(); + op(out1, out2); + _out.insert(out1); + _out.insert(out2); + } + + /// + virtual string className() const {return "eoWrappedQuadraticOp";}; + +private : + const eoQuadraticOp& op; +}; + +/// Combines several ops +template +class eoCombinedOp : public eoGeneralOp +{ +public : + + /// + eoCombinedOp() : eoGeneralOp() {} + + /// + virtual ~eoCombinedOp() {} + + /// Adds a new operator to the combined Op + void addOp(eoGeneralOp* _op) + { + ops.push_back(_op); + } + + + /// Erases all operators added so far + void clear(void) { + ops.resize(0); + } + + /// Helper class to make sure that stuff that is inserted will be used again with the next operator + template + class eoIndiSelectorInserter : public eoIndiSelector, public eoInserter + { + public : + eoIndiSelectorInserter(eoIndiSelector& _in) + : eoIndiSelector(), eoInserter(), in(_in) + {} + + size_t size() const { return in.size(); } + const EOT& operator[](size_t _n) const { return in[_n]; } + + const EOT& select(void) + { + if (results.empty()) + { + return in.select(); + } + // else we use the previously inserted individual, + // an iterator to it is stored in 'results', but the memory + // is kept by 'intermediate'. + + list::iterator it = *results.begin(); + results.pop_front(); + return *it; + } + + void insert(const EOT& _eot) + { + intermediate.push_front(_eot); + results.push_front(intermediate.begin()); + } + + void fill(eoInserter& _out) + { + typedef list::iterator>::iterator Iterator; + + for (Iterator it = results.begin(); it != results.end(); ++it) + { + _out.insert(**it); + } + + results.clear(); + intermediate.clear(); // reclaim memory + } + + private : + + eoIndiSelector& in; + + // using lists as we need to push and pop a lot + // 'results' are iterators to the contents of 'intermediate' + // to prevent copying to and from intermediate... + list::iterator> results; + list intermediate; + }; + + /// Applies all ops in the combined op + void operator()( eoIndiSelector& _in, + eoInserter& _out ) const { + + eoIndiSelectorInserter in_out(_in); + + for (size_t i = 0; i < ops.size(); ++i) + { + (*ops[i])(in_out, in_out); + } + + in_out.fill(_out); + } + +private : + vector* > ops; +}; + +#endif eoGeneral_h diff --git a/eo/src/rnd_generators.h b/eo/src/rnd_generators.h new file mode 100644 index 00000000..c7beace7 --- /dev/null +++ b/eo/src/rnd_generators.h @@ -0,0 +1,85 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + rnd_generators.h + Some utility functors for generating random generators: + uniform_generator : generates uniform floats or doubles + random_generator : generates unsigneds, ints etc. + normal_generator : normally distributed floats or doubles + + (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 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 + */ + +//----------------------------------------------------------------------------- + +#ifndef eoRND_GENERATORS_H +#define eoRND_GENERATORS_H + +#include "eoRNG.h" + +/** + The class uniform_generator can be used in the STL generate function + to easily generate random floats and doubles between [0, _max). _max + defaults to 1.0 +*/ +template class uniform_generator +{ + public : + uniform_generator(T _max = T(1.0), eoRng& _rng = rng) : maxim(_max), uniform(_rng) {} + + virtual T operator()(void) { return (T) uniform.uniform(maxim); } + private : + T maxim; + eoRng& uniform; +}; + +/** + The class random_generator can be used in the STL generate function + to easily generate random ints between [0, _max). +*/ +template class random_generator +{ + public : + random_generator(int _max, eoRng& _rng = rng) : maxim(_max), random(_rng) {} + + virtual T operator()(void) { return (T) random.random(max); } + + private : + T maxim; + eoRng& random; +}; + +/** + The class normal_generator can be used in the STL generate function + to easily generate gaussian distributed floats and doubles. The user + can supply a standard deviation which defaults to 1. +*/ +template class normal_generator +{ + public : + normal_generator(T _stdev = T(1.0), eoRng& _rng = rng) : stdev(_stdev), normal(_rng) {} + + virtual T operator()(void) { return (T) normal.normal(stdev); } + + private : + T stdev; + eoRng& normal; +}; + +#endif \ No newline at end of file diff --git a/eo/src/selectors.h b/eo/src/selectors.h new file mode 100644 index 00000000..4b0dad6d --- /dev/null +++ b/eo/src/selectors.h @@ -0,0 +1,313 @@ +/* -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- + + ----------------------------------------------------------------------------- + selectors.h + A bunch of useful selector functions. They generally have three forms: + + template + It select(It begin, It end, params, eoRng& gen = rng); + + template + const EOT& select(const eoPop& pop, params, eoRng& gen = rng); + + template + EOT& select(eoPop& pop, params, eoRng& gen = rng); + + where select is one of: roulette_wheel, deterministic_tournament + and stochastic_tournament (at the moment). + + (c) Maarten Keijzer (mak@dhi.dk) and GeNeura Team, 1999, 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 + */ + +#ifndef SELECT__H +#define SELECT__H + +#include "eoRNG.h" +#include "eoException.h" + +template +bool minimizing_fitness() +{ + EOT eo1; // Assuming people don't do anything fancy in the default constructor! + EOT eo2; + + /* Dear user, when the two line below do not compile you are most + likely not working with scalar fitness values. In that case we're sorry + but you cannot use lottery or roulette_wheel selection... + */ + eo1.fitness(0.0); // tried to cast it to an EOT::Fitness, but for some reason GNU barfs on this + eo2.fitness(1.0); + + return eo2 < eo1; // check whether we have a minimizing fitness +}; + +inline double scale_fitness(const std::pair& _minmax, double _value) +{ + if (_minmax.first == _minmax.second) + { + return 0.0; // no differences in fitness, population converged! + } + // else + + return (_value - _minmax.first) / (_minmax.second - _minmax.first); +} + +template +double sum_fitness(It begin, It end) +{ + double sum = 0.0; + + for (; begin != end; ++begin) + { + double v = static_cast(begin->fitness()); + if (v < 0.0) + throw eoNegativeFitnessException(); + sum += v; + } + + return sum; +} + +template +double sum_fitness(const eoPop& _pop) +{ + return sum_fitness(_pop.begin(), _pop.end()); +} + +template +double sum_fitness(const eoPop& _pop, std::pair& _minmax) +{ + eoPop::const_iterator it = _pop.begin(); + + _minmax.first = it->fitness(); + _minmax.second = it++->fitness(); + + for(; it != _pop.end(); ++it) + { + double v = static_cast(it->fitness()); + + _minmax.first = std::min(_minmax.first, v); + _minmax.second = std::max(_minmax.second, v); + + rawTotal += v; + } + + if (minimizing_fitness()) + { + std::swap(_minmax.first, _minmax.second); + } + + scaledTotal = 0.0; + + // unfortunately a second loop is neccessary to scale the fitness + for (it = _pop.begin(); it != _pop.end(); ++it) + { + double v = scale_fitness(static_cast(it->fitness())); + + scaledTotal += v; + } +} + +template +It roulette_wheel(It _begin, It _end, double total, eoRng& _gen = rng) +{ + float roulette = _gen.uniform(total); + + It i = _begin; + + while (roulette > 0.0) + { + roulette -= static_cast(*(i++)); + } + + return --i; +} + +template +const EOT& roulette_wheel(const eoPop& _pop, double total, eoRng& _gen = rng) +{ + float roulette = _gen.uniform(total); + + eoPop::const_iterator i = _pop.begin(); + + while (roulette > 0.0) + { + roulette -= static_cast((i++)->fitness()); + } + + return *--i; +} + +template +EOT& roulette_wheel(eoPop& _pop, double total, eoRng& _gen = rng) +{ + float roulette = _gen.uniform(total); + + eoPop::iterator i = _pop.begin(); + + while (roulette > 0.0) + { + roulette -= static_cast((i++)->fitness()); + } + + return *--i; +} + +template +It deterministic_tournament(It _begin, It _end, unsigned _t_size, eoRng& _gen = rng) +{ + It best = _begin + _gen.random(_end - _begin); + + for (unsigned i = 0; i < _t_size - 1; ++i) + { + It competitor = _begin + _gen.random(_end - _begin); + + if (*best < *competitor) + { + best = competitor; + } + } + + return best; +} + +template +const EOT& deterministic_tournament(const eoPop& _pop, unsigned _t_size, eoRng& _gen = rng) +{ + return *deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen); +} + +template +EOT& deterministic_tournament(eoPop& _pop, unsigned _t_size, eoRng& _gen = rng) +{ + return *deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen); +} + +template +It inverse_deterministic_tournament(It _begin, It _end, unsigned _t_size, eoRng& _gen = rng) +{ + It worst = _begin + _gen.random(_end - _begin); + + for (unsigned i = 0; i < _t_size - 1; ++i) + { + It competitor = _begin + _gen.random(_end - _begin); + + if (competitor == worst) + { + --i; + continue; // try again + } + + if (*competitor < *worst) + { + worst = competitor; + } + } + + return worst; +} + +template +const EOT& inverse_deterministic_tournament(const eoPop& _pop, unsigned _t_size, eoRng& _gen = rng) +{ + return *inverse_deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen); +} + +template +EOT& inverse_deterministic_tournament(eoPop& _pop, unsigned _t_size, eoRng& _gen = rng) +{ + return *inverse_deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen); +} + +template +It stochastic_tournament(It _begin, It _end, double _t_rate, eoRng& _gen = rng) +{ + It i1 = _begin + _gen.random(_end - _begin); + It i2 = _begin + _gen.random(_end - _begin); + + bool return_better = _gen.flip(_t_rate); + + if (*i1 < *i2) + { + if (return_better) return i2; + // else + + return i1; + } + else + { + if (return_better) return i1; + // else + } + // else + + return i2; +} + +template +const EOT& stochastic_tournament(const eoPop& _pop, double _t_rate, eoRng& _gen = rng) +{ + return *stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen); +} + +template +EOT& stochastic_tournament(eoPop& _pop, double _t_rate, eoRng& _gen = rng) +{ + return *stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen); +} + +template +It inverse_stochastic_tournament(It _begin, It _end, double _t_rate, eoRng& _gen = rng) +{ + It i1 = _begin + _gen.random(_end - _begin); + It i2 = _begin + _gen.random(_end - _begin); + + bool return_worse = _gen.flip(_t_rate); + + if (*i1 < *i2) + { + if (return_worse) return i1; + // else + + return i2; + } + else + { + if (return_worse) return i2; + // else + } + // else + + return i1; +} + +template +const EOT& inverse_stochastic_tournament(const eoPop& _pop, double _t_rate, eoRng& _gen = rng) +{ + return *inverse_stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen); +} + +template +EOT& inverse_stochastic_tournament(eoPop& _pop, double _t_rate, eoRng& _gen = rng) +{ + return *inverse_stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen); +} + + +#endif \ No newline at end of file