Ok, made an eoParetoFitness class, which meant that I could roll back a few changes in EO.h (phew).

Also changed eoSelectFromWorth etc.
This commit is contained in:
maartenkeijzer 2001-03-16 12:08:26 +00:00
commit d09c216b61
11 changed files with 215 additions and 110 deletions

View file

@ -4,7 +4,7 @@
##
###############################################################################
SUBDIRS = src test win tutorial app
SUBDIRS = src test win app tutorial
#Directory for documents
DOCDIR = ~/public_html/eodocs
#Directory for indices -- not useful for the user
@ -17,10 +17,6 @@ EXTRA_DIST=LICENSE
lib:
pushd src; $(MAKE) all; popd
# The test directory should be run explicitely, to check if nothing is broken
test: test/run_tests test/Makefile
pushd test; touch run_tests; $(MAKE) all; ./run_tests; popd
# so that make doc always compiles the doc ...
doc: doc/eo.cfg
pushd doc; $(MAKE) doc; touch eo.cfg; popd

View file

@ -56,8 +56,8 @@ echo
echo "Now type 'make' to compile $PROG."
echo "And if you have Doxygen installed, type 'make doc' to generate $PROG documentation."
echo
echo "WARNING: Compiling all test programs can take some time."
echo "But you don't have to: you can simply type"
echo " 'make lib'"
echo "and then go in your application dir (or in the tutorial dir)"
echo "and there type 'make'"
#echo "WARNING: Compiling all test programs can take some time."
#echo "But you don't have to: you can simply type"
#echo " 'make lib'"
#echo "and then go in your application dir (or in the tutorial dir)"
#echo "and there type 'make'"

View file

@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(src/eo)
dnl Change the version number here
AM_INIT_AUTOMAKE(eo, 0.9.11)
AM_INIT_AUTOMAKE(eo, 0.9.2)
dnl Checks for maintainer mode
AM_MAINTAINER_MODE

View file

@ -3,7 +3,7 @@
//-----------------------------------------------------------------------------
// EO.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
@ -31,61 +31,6 @@
#include <eoObject.h> // eoObject
#include <eoPersistent.h> // eoPersistent
/// Functions for reading and writing non-scalar fitnesses, should probably go to seperate file
template <class T>
ostream& print_fitness(ostream& _os, const std::vector<T>& vec)
{
_os << vec.size() << ' ';
std::copy(vec.begin(), vec.end(), ostream_iterator<T>(_os));
return _os;
}
/// Functions for reading and writing non-scalar fitnesses, should probably go to seperate file
template <class T, class U>
ostream& print_fitness(ostream& _os, const std::pair<T, U>& pair)
{
return _os << pair.first << ' ' << pair.second;
}
/// Functions for reading and writing non-scalar fitnesses, should probably go to seperate file
template <class T>
ostream& print_fitness(ostream& _os, const T& t)
{ // general, try operator<<
return _os << t;
}
/// Functions for reading and writing non-scalar fitnesses, should probably go to seperate file
template <class T>
istream& read_fitness(istream& _is, vector<T>& vec)
{
unsigned sz;
_is >> sz;
vec.resize(sz);
for (unsigned i = 0; i < vec.size(); ++i)
{
_is >> vec[i];
}
return _is;
}
/// Functions for reading and writing non-scalar fitnesses, should probably go to seperate file
template <class T, class U>
istream& read_fitness(istream& _is, pair<T, U>& pair)
{
_is >> pair.first;
_is >> pair.second;
return _is;
}
/// Functions for reading and writing non-scalar fitnesses, should probably go to seperate file
template <class T>
istream& read_fitness(istream& _is, T& t)
{
_is >> t;
return _is;
}
//-----------------------------------------------------------------------------
/** EO is a base class for evolvable objects, that is, the subjects of
evolution. EOs have only got a fitness, which at the same time needs to be
@ -158,7 +103,7 @@ public:
* @throw runtime_exception If a valid object can't be read.
*/
virtual void readFrom(istream& _is) {
read_fitness(_is, repFitness);
_is >> repFitness;
if (_is)
invalidFitness = false;
else
@ -173,7 +118,7 @@ public:
if (invalid())
_os << "INVALID ";
else
print_fitness(_os, repFitness) << ' '; // trailing space to make reading in that much easier
_os << repFitness << ' '; // trailing space to make reading in that much easier
}
//@}
@ -186,4 +131,3 @@ private:
//-----------------------------------------------------------------------------
#endif EO_H

View file

@ -62,6 +62,8 @@ class eoDominanceMap : public eoUF<const eoPop<EoType>&, void>, public std::vect
fitnesses.clear();
}
bool maximize(unsigned objective) const { return maximizes[objective]; }
/**
Update or create the dominance map
*/

View file

@ -32,16 +32,25 @@
#include <eoDominanceMap.h>
/**
Non dominated sorting
Non dominated sorting, it *is a* vector of doubles, the integer part is the rank (to which front it belongs),
the fractional part the niching penalty or distance penalty or whatever penalty you want to squeeze into
the bits.
*/
template <class EOT>
class eoNDSorting : public eoPerf2Worth<EOT, double>
{
public :
eoNDSorting(eoDominanceMap<EOT>& _dominanceMap, double _nicheSize) :
eoPerf2Worth<EOT, double>(), dominanceMap(_dominanceMap), nicheSize(_nicheSize) {}
eoNDSorting(eoDominanceMap<EOT>& _dominanceMap) :
eoPerf2Worth<EOT, double>(), dominanceMap(_dominanceMap) {}
/** Pure virtual function that calculates the 'distance' for each element to the current front
Implement to create your own nondominated sorting algorithm. The size of the returned vector
should be equal to the size of the current_front.
*/
virtual vector<double> niche_penalty(const vector<unsigned>& current_front, const eoPop<EOT>& _pop) = 0;
/// Do the work
void operator()(const eoPop<EOT>& _pop)
{
dominanceMap(_pop);
@ -83,20 +92,20 @@ class eoNDSorting : public eoPerf2Worth<EOT, double>
}
// Now we have the indices to the current front in current_front, do the niching
vector<double> niche_count = niche_penalty(current_front, _pop);
// As I don't have my reference text with me some homespun savagery
if (niche_count.size() != current_front.size())
{
throw logic_error("eoNDSorting: niche and front should have the same size");
}
ranks = dominanceMap.sum_dominants(); // how many do you dominate
double max_rank = *std::max_element(ranks.begin(), ranks.end());
double max_niche = *max_element(niche_count.begin(), niche_count.end());
for (unsigned i = 0; i < current_front.size(); ++i)
{
// punish the ones that dominate the most individuals (sounds strange huh?)
value()[current_front[i]] = dominance_level + ranks[i] / (max_rank + 1);
value()[current_front[i]] = dominance_level + niche_count[i] / (max_niche + 1);
}
dominance_level++; // go to the next front
}
@ -110,10 +119,123 @@ class eoNDSorting : public eoPerf2Worth<EOT, double>
}
const eoDominanceMap<EOT>& map() const;
private :
eoDominanceMap<EOT>& dominanceMap;
};
/**
The original Non Dominated Sorting algorithm from Srinivas and Deb
*/
template <class EOT>
class eoNDSorting_I : public eoNDSorting<EOT>
{
public :
eoNDSorting_I(eoDominanceMap<EOT>& _map, double _nicheSize) : eoNDSorting<EOT>(_map), nicheSize(_nicheSize) {}
vector<double> niche_penalty(const vector<unsigned>& current_front, const eoPop<EOT>& _pop)
{
vector<double> niche_count(current_front.size(), 0.);
for (unsigned i = 0; i < current_front.size(); ++i)
{ // calculate whether the other points lie within the nice
for (unsigned j = 0; j < current_front.size(); ++j)
{
if (i == j)
continue;
double dist = 0.0;
for (unsigned k = 0; k < _pop[current_front[j]].fitness().size(); ++k)
{
double d = _pop[current_front[i]].fitness()[k] - _pop[current_front[j]].fitness()[k];
dist += d*d;
}
if (dist < nicheSize)
{
niche_count[i] += 1.0 - pow(dist / nicheSize,2.);
}
}
}
return niche_count;
}
private :
double nicheSize;
};
/**
Adapted from Deb, Agrawal, Pratab and Meyarivan: A Fast Elitist Non-Dominant Sorting Genetic Algorithm for MultiObjective Optimization: NSGA-II
KanGAL Report No. 200001
Note that this class does not do the sorting per se, but the sorting of it worth_vector will give the right order
The crowding distance is calculated as the sum of the distances to the nearest neighbours. As we need to return the
penalty value, we have to invert that and invert it again in the base class, but such is life, sigh
*/
template <class EOT>
class eoNDSorting_II : public eoNDSorting<EOT>
{
public:
eoNDSorting_II(eoDominanceMap<EOT>& _map) : eoNDSorting<EOT>(_map) {}
typedef std::pair<double, unsigned> double_index_pair;
class compare_nodes
{
public :
bool operator()(const double_index_pair& a, const double_index_pair& b) const
{
return a.first < b.first;
}
};
vector<double> niche_penalty(const vector<unsigned>& _cf, const eoPop<EOT>& _pop)
{
vector<double> niche_count(_cf.size(), 0.);
unsigned nObjectives = _pop[_cf[0]].fitness().size();
for (unsigned o = 0; o < nObjectives; ++o)
{
vector<pair<double, unsigned> > performance(_cf.size());
for (unsigned i =0; i < _cf.size(); ++i)
{
performance[i].first = _pop[_cf[i]].fitness()[o];
performance[i].second = i;
}
sort(performance.begin(), performance.end(), compare_nodes()); // a lambda operator would've been nice here
vector<double> nc(niche_count.size(), 0.0);
for (unsigned i = 1; i < _cf.size()-1; ++i)
{ // and yet another level of indirection
nc[performance[i].second] = performance[i+1].first - performance[i-1].first;
}
double max_dist = *max_element(nc.begin(), nc.end());
// set boundary penalty at 0 (so it will get chosen over all the others
nc[performance[0].second] = 0;
nc[performance.back().second] = 0;
for (unsigned i = 0; i < nc.size(); ++i)
{
niche_count[i] += (max_dist + 1) - nc[i];
}
}
return niche_count;
}
};
#endif

View file

@ -74,8 +74,7 @@ protected:
eoPerf2Worth<EOT, WorthType> & perf2Worth;
#ifndef NDEBUG
vector<typename EOT::Fitness> fitness; // for debugging purposes, to check that the perf2worth and pop are in sync
std::vector<typename EOT::Fitness> fitness;
void check_sync(unsigned index, const EOT& _eo)
{
if (fitness[index] != _eo.fitness())

View file

@ -55,18 +55,20 @@ class eoGnuplot1DSnapshot: public eoFileSnapshot, public eoGnuplot
{
public:
// Ctor
eoGnuplot1DSnapshot(std::string _dirname, unsigned _frequency = 1,
std::string _filename = "gen", std::string _delim = " ") :
eoFileSnapshot(_dirname, _frequency, _filename, _delim),
eoGnuplot(_filename,"set data style points")
eoGnuplot1DSnapshot(std::string _dirname, unsigned _frequency = 1,
std::string _filename = "gen", std::string _delim = " ") :
eoFileSnapshot(_dirname, _frequency, _filename, _delim),
eoGnuplot(_filename,"set data style points"),
pointSize(5)
{}
// Ctor
eoGnuplot1DSnapshot(eoFileSnapshot & _fSnapshot) :
eoFileSnapshot(_fSnapshot),
eoGnuplot(_fSnapshot.baseFileName(),"set data style points")
eoGnuplot1DSnapshot(eoFileSnapshot & _fSnapshot) :
eoFileSnapshot(_fSnapshot),
eoGnuplot(_fSnapshot.baseFileName(),"set data style points"),
pointSize(5)
{}
// Dtor
virtual ~eoGnuplot1DSnapshot(){}
@ -75,10 +77,12 @@ class eoGnuplot1DSnapshot: public eoFileSnapshot, public eoGnuplot
/// Class name.
virtual string className() const { return "eoGnuplot1DSnapshot"; }
private:
unsigned pointSize;
private:
};
// the following should be placed in a separate eoGnuplot1DMonitor.cpp
// the following should be placed in a separate eoGnuplot1DMonitor.cpp
////////////////////////////////////////////////////////////
inline eoMonitor& eoGnuplot1DSnapshot::operator() (void)
@ -96,12 +100,12 @@ inline eoMonitor& eoGnuplot1DSnapshot::operator() (void)
os << "plot";
os << " '" << getFileName().c_str() <<
"' notitle with points ps 5" ;
"' notitle with points ps " << pointSize ;
os << "\n";
os << '\0';
PipeComSend( gpCom, buff );
return (*this);
}
#endif _eoGnuplot1DSnapshot_H

View file

@ -13,9 +13,9 @@ LDADDS = $(top_builddir)/src/utils/libeoutils.a $(top_builddir)/src/libeo.a
CXXFLAGS = -g -Wall
###############################################################################
check_PROGRAMS = t-eoPareto t-eofitness t-eoRandom t-eobin t-eoStateAndParser t-eoCheckpointing t-eoSSGA \
check_PROGRAMS = t-eoParetoFitness t-eoPareto t-eofitness t-eoRandom t-eobin t-eoStateAndParser t-eoCheckpointing t-eoSSGA \
t-eoExternalEO t-eoSymreg t-eo t-eoReplacement t-eoSelect t-eoGenOp t-eoGA t-eoVector
TESTS=run_tests t-eoVector t-eoRandom t-eoSSGA t-eoPareto
TESTS=run_tests t-eoVector t-eoRandom t-eoSSGA t-eoPareto t-eoParetoFitness
# removing temporarily t-eoESFull
#noinst_PROGRAMS = t-eofitness t-eobin t-eoStateAndParser t-eoCheckpointing t-eoExternalEO t-eoESFull t-eoSymreg t-eo t-eoReplacement t-eoSelect t-eoGenOp t-eoGA
@ -128,3 +128,8 @@ t_eoPareto_LDFLAGS = -lm
t_eoPareto_LDADD = $(LDADDS)
###############################################################################
t_eoParetoFitness_SOURCES = t-eoParetoFitness.cpp
t_eoParetoFitness_DEPENDENCIES = $(DEPS) $(top_builddir)/src/ga/libga.a
t_eoParetoFitness_LDFLAGS = -lm
t_eoParetoFitness_LDADD = $(LDADDS)
###############################################################################

View file

@ -3,20 +3,42 @@
//#include <utils/eoMOFitnessStat.h>
#include <eoNDSorting.h>
#include <eoParetoFitness.h>
using namespace std;
typedef vector<double> fitness_type;
class MinimizingFitnessTraits : public eoParetoFitnessTraits
{
public :
static bool maximizing(int) { return false; }
};
typedef eoParetoFitness<MinimizingFitnessTraits> fitness_type;
const unsigned chromsize=3;
const double minval = -5;
const double maxval = 5;
struct eoDouble : public EO<fitness_type>
{
double value;
double value[chromsize];
};
class Mutate : public eoMonOp<eoDouble>
{
bool operator()(eoDouble& _eo)
{
_eo.value += rng.normal() * 0.1 * _eo.value;
for (unsigned i = 0; i < chromsize; ++i)
{
if (rng.flip(1./10.))
_eo.value[i] += rng.normal() * 0.05 * _eo.value[i];
if (_eo.value[i] < minval)
_eo.value[i] = minval;
else if (_eo.value[i] > maxval)
_eo.value[i] = maxval;
}
return true;
}
};
@ -25,10 +47,18 @@ class Eval : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
double v = _eo.value;
fitness_type f(2);
f[1] = v * v;
f[0] = (v - 1.) * (v - 1.);
vector<double> x(_eo.value, _eo.value + chromsize);
fitness_type f;
for (unsigned i = 0; i < chromsize; ++i)
{
if (i < chromsize-1)
{
f[0] += -10.0 * exp(-0.2 * sqrt(x[i]*x[i] + x[i+1]*x[i+1]));
}
f[1] += pow(fabs(x[i]), 0.8) + 5 * pow(sin(x[i]),3.);
}
_eo.fitness(f);
}
@ -38,7 +68,10 @@ class Init : public eoInit<eoDouble>
{
void operator()(eoDouble& _eo)
{
_eo.value = rng.normal() * 10.;
_eo.value[0] = rng.uniform();
for (unsigned i = 1; i < chromsize; ++i)
_eo.value[i] = rng.uniform() * 10. - 5;
_eo.invalidate();
}
};
@ -51,8 +84,8 @@ void the_main()
Eval eval;
Mutate mutate;
unsigned num_gen = 10;
unsigned pop_size = 50;
unsigned num_gen = 500;
unsigned pop_size = 100;
eoPop<eoDouble> pop(pop_size, init);
vector<bool> maximizes(2, false); // minimize both objectives
@ -62,7 +95,8 @@ void the_main()
// Pareto ranking needs a dominance map
//eoParetoRanking<eoDouble> perf2worth(dominance);
eoNDSorting<eoDouble> perf2worth(dominance, 0.0);
//eoNDSorting_I<eoDouble> perf2worth(dominance, 0.5);
eoNDSorting_II<eoDouble> perf2worth(dominance);
// Three selectors
eoDetTournamentWorthSelect<eoDouble> select1(perf2worth, 3);
@ -78,7 +112,7 @@ void the_main()
eoGeneralBreeder<eoDouble> breeder2(select2, opsel);
eoGeneralBreeder<eoDouble> breeder3(select3, opsel);
// Comma replacement
// replacement
eoCommaReplacement<eoDouble> replace;
unsigned long generation = 0;

View file

@ -1,5 +1,4 @@
EXTRA_DIST=eo_win.dsw eo.dsp esfull.dsp t_eobin.dsp t_eoCheckpointing.dsp t_eofitness.dsp \
t_eoFunctor.dsp t_externalEO.dsp t_StateAndParser.dsp t_eoSymreg.dsp
EXTRA_DIST=eo.dsw eo.dsp