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

@ -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