This repository has been archived on 2026-03-28. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
eodev/eo/src/selectors.h

313 lines
7.8 KiB
C++

/* -*- 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 <class It>
It select(It begin, It end, params, eoRng& gen = rng);
template <class EOT>
const EOT& select(const eoPop<EOT>& pop, params, eoRng& gen = rng);
template <class EOT>
EOT& select(eoPop<EOT>& 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 <class EOT>
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<double, double>& _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 <class It>
double sum_fitness(It begin, It end)
{
double sum = 0.0;
for (; begin != end; ++begin)
{
double v = static_cast<double>(begin->fitness());
if (v < 0.0)
throw eoNegativeFitnessException();
sum += v;
}
return sum;
}
template <class EOT>
double sum_fitness(const eoPop<EOT>& _pop)
{
return sum_fitness(_pop.begin(), _pop.end());
}
template <class EOT>
double sum_fitness(const eoPop<EOT>& _pop, std::pair<double, double>& _minmax)
{
eoPop<EOT>::const_iterator it = _pop.begin();
_minmax.first = it->fitness();
_minmax.second = it++->fitness();
for(; it != _pop.end(); ++it)
{
double v = static_cast<double>(it->fitness());
_minmax.first = std::min(_minmax.first, v);
_minmax.second = std::max(_minmax.second, v);
rawTotal += v;
}
if (minimizing_fitness<EOT>())
{
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<double>(it->fitness()));
scaledTotal += v;
}
}
template <class It>
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<double>(*(i++));
}
return --i;
}
template <class EOT>
const EOT& roulette_wheel(const eoPop<EOT>& _pop, double total, eoRng& _gen = rng)
{
float roulette = _gen.uniform(total);
eoPop<EOT>::const_iterator i = _pop.begin();
while (roulette > 0.0)
{
roulette -= static_cast<double>((i++)->fitness());
}
return *--i;
}
template <class EOT>
EOT& roulette_wheel(eoPop<EOT>& _pop, double total, eoRng& _gen = rng)
{
float roulette = _gen.uniform(total);
eoPop<EOT>::iterator i = _pop.begin();
while (roulette > 0.0)
{
roulette -= static_cast<double>((i++)->fitness());
}
return *--i;
}
template <class It>
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 <class EOT>
const EOT& deterministic_tournament(const eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
{
return *deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen);
}
template <class EOT>
EOT& deterministic_tournament(eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
{
return *deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen);
}
template <class It>
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 <class EOT>
const EOT& inverse_deterministic_tournament(const eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
{
return *inverse_deterministic_tournament<EOT>(_pop.begin(), _pop.end(), _t_size, _gen);
}
template <class EOT>
EOT& inverse_deterministic_tournament(eoPop<EOT>& _pop, unsigned _t_size, eoRng& _gen = rng)
{
return *inverse_deterministic_tournament(_pop.begin(), _pop.end(), _t_size, _gen);
}
template <class It>
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 <class EOT>
const EOT& stochastic_tournament(const eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
{
return *stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
}
template <class EOT>
EOT& stochastic_tournament(eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
{
return *stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
}
template <class It>
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 <class EOT>
const EOT& inverse_stochastic_tournament(const eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
{
return *inverse_stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
}
template <class EOT>
EOT& inverse_stochastic_tournament(eoPop<EOT>& _pop, double _t_rate, eoRng& _gen = rng)
{
return *inverse_stochastic_tournament(_pop.begin(), _pop.end(), _t_rate, _gen);
}
#endif