added new multi-objective support

This commit is contained in:
maartenkeijzer 2007-08-31 10:57:05 +00:00
commit 553586d55f
12 changed files with 1049 additions and 9 deletions

View file

@ -1,8 +1,8 @@
dnl Process this file with autoconf to produce a configure script.
dnl
dnl Change the version number here
AC_INIT([Evolving Objects], [1.02-cvs1], [eodev-help@sourceforge.net], [eo])
AC_PREREQ(2.53)
AC_INIT([Evolving Objects],[1.02-cvs1],[eodev-help@sourceforge.net],[eo])
AC_PREREQ(2.60)
dnl make sure we are compiling from the correct sources
AC_CONFIG_SRCDIR(src/eoOp.h)
@ -14,7 +14,7 @@ AC_CANONICAL_TARGET
dnl automake initialization
AM_INIT_AUTOMAKE([gnu dist-bzip2 dist-zip])
AM_CONFIG_HEADER(config.h)
AC_CONFIG_HEADERS([config.h])
dnl Checks for programs.
AC_PROG_CC
@ -45,7 +45,7 @@ AC_GNUPLOT
AC_TUTORIAL
dnl create makefiles
AC_OUTPUT(Makefile \
AC_CONFIG_FILES([Makefile \
app/Makefile \
app/mastermind/Makefile \
app/gprop/Makefile \
@ -59,6 +59,7 @@ AC_OUTPUT(Makefile \
src/ga/Makefile \
src/other/Makefile \
src/utils/Makefile \
src/moo/Makefile \
test/Makefile \
tutorial/Makefile \
tutorial/html/Makefile \
@ -69,4 +70,5 @@ AC_OUTPUT(Makefile \
tutorial/Lesson5/Makefile \
tutorial/Templates/Makefile \
tutorial/pdf/Makefile \
win/Makefile)
win/Makefile])
AC_OUTPUT

View file

@ -1,6 +1,6 @@
# Makefile.am for eo/src
SUBDIRS = es ga gp do utils other
SUBDIRS = es ga gp do utils other moo
lib_LIBRARIES = libeo.a

56
eo/src/moo/CMakeLists.txt Normal file
View file

@ -0,0 +1,56 @@
######################################################################################
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
######################################################################################
### 2) Define the ga target
######################################################################################
SET(EOMOO_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
SET(LIBRARY_OUTPUT_PATH ${EOMOO_LIB_OUTPUT_PATH})
SET (EOMOO_SOURCES eoFrontSorter.cpp )
ADD_LIBRARY(eomoo STATIC ${EOMOO_SOURCES})
######################################################################################
######################################################################################
### 3) Optionnal
######################################################################################
SET(EOMOO_VERSION "1.0.1")
SET_TARGET_PROPERTIES(eomoo PROPERTIES VERSION "${EOMOO_VERSION}")
######################################################################################
######################################################################################
### 4) Windows advanced config - especially for Microsoft Visual Studio 8
######################################################################################
IF(CMAKE_CXX_COMPILER MATCHES cl)
IF(NOT WITH_SHARED_LIBS)
IF(CMAKE_GENERATOR STREQUAL "Visual Studio 8 2005")
SET(CMAKE_CXX_FLAGS "/nologo /W3 /Gy")
SET(CMAKE_CXX_FLAGS_DEBUG "/MTd /Z7 /Od")
SET(CMAKE_CXX_FLAGS_RELEASE "/MT /O2")
SET(CMAKE_CXX_FLAGS_MINSIZEREL "/MT /O2")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MTd /Z7 /Od")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:CONSOLE")
ENDIF(CMAKE_GENERATOR STREQUAL "Visual Studio 8 2005")
ENDIF(NOT WITH_SHARED_LIBS)
ENDIF(CMAKE_CXX_COMPILER MATCHES cl)
######################################################################################

9
eo/src/moo/Makefile.am Normal file
View file

@ -0,0 +1,9 @@
lib_LIBRARIES = libeomoo.a
libeomoo_a_SOURCES = eoFrontSorter.cpp
pkginclude_HEADERS = eoFrontSorter.h \
eoMOFitness.h
AM_CXXFLAGS = -I$(top_srcdir)/src

View file

@ -0,0 +1,156 @@
#include <moo/eoFrontSorter.h>
using namespace std;
namespace detail {
namespace {
struct CompareOn {
unsigned dim;
CompareOn(unsigned d) : dim(d) {}
bool operator()(const FitnessInfo& a, const FitnessInfo& b) {
return a.fitness[dim] > b.fitness[dim];
}
};
} // end anonymous namespace
void one_objective(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front)
{
std::sort(fitness.begin(), fitness.end(), CompareOn(0));
front.clear();
front.resize(1);
front[0].push_back(fitness[0]);
for (unsigned i = 1; i < fitness.size(); ++i) {
if (fitness[i].fitness[0] < fitness[i-1].fitness[0]) { // keep clones in same front
front.push_back( std::vector<FitnessInfo>() );
}
front.back().push_back( fitness[i] );
}
}
/**
* Optimization for two objectives. Makes the algorithm run in
* complexity O(n log n) where n is the population size
*/
void two_objectives(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front)
{
std::sort(fitness.begin(), fitness.end(), CompareOn(0));
front.clear();
std::vector<FitnessInfo> front_leader;
for (unsigned i = 0; i < fitness.size(); ++i) {
// find front through binary search
vector<FitnessInfo>::iterator it = upper_bound( front_leader.begin(), front_leader.end(), fitness[i], CompareOn(1));
if (it == front_leader.end()) {
front_leader.push_back(fitness[i]);
front.push_back( vector<FitnessInfo>(1, fitness[i]) );
} else {
*it = fitness[i]; // new 'best of front in second dimension'
front[ it - front_leader.begin() ].push_back(fitness[i]); // add to front of nth dominated solutions
}
}
}
bool dominates(const FitnessInfo& a, const FitnessInfo& b) {
bool better_on_one = false;
for (unsigned i = 0; i < a.fitness.size(); ++i) {
if (a.fitness[i] < b.fitness[i]) return false; // worse on at least one other objective
if (a.fitness[i] > b.fitness[i]) better_on_one = true;
}
return better_on_one;
}
void m_objectives(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front) {
unsigned i;
std::vector<std::vector<unsigned> > S(fitness.size()); // which individuals does guy i dominate
std::vector<unsigned> n(fitness.size()); // how many individuals dominate guy i
unsigned j;
for (i = 0; i < fitness.size(); ++i)
{
for (j = 0; j < fitness.size(); ++j)
{
if ( dominates(fitness[i], fitness[j]) )
{ // i dominates j
S[i].push_back(j); // add j to i's domination list
}
else if (dominates(fitness[j], fitness[i]))
{ // j dominates i, increment count for i, add i to the domination list of j
n[i]++;
}
}
}
front.clear();
front.resize(1);
// get the first front out
for (i = 0; i < fitness.size(); ++i)
{
if (n[i] == 0)
{
front.back().push_back( fitness[i] );
}
}
while (!front.back().empty())
{
front.push_back(vector<FitnessInfo>());
vector<FitnessInfo>& last_front = front[front.size()-2];
// Calculate which individuals are in the next front;
for (i = 0; i < last_front.size(); ++i)
{
for (j = 0; j < S[ last_front[i].index ].size(); ++j)
{
unsigned dominated_individual = S[ last_front[i].index ][j];
n[dominated_individual]--; // As we remove individual i -- being part of the current front -- it no longer dominates j
if (n[dominated_individual] == 0) // it should be in the current front
{
front.back().push_back( fitness[dominated_individual] );
}
}
}
}
front.pop_back(); // last front is empty;
}
void front_sorter_impl(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front_indices) {
switch (fitness[0].fitness.size())
{
case 1:
{
one_objective(fitness, front_indices);
return;
}
case 2:
{
two_objectives(fitness, front_indices);
return;
}
default :
{
m_objectives(fitness, front_indices);
}
}
}
} // namespace detail

View file

@ -0,0 +1,85 @@
/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
-----------------------------------------------------------------------------
eoNDSorting.h
(c) Maarten Keijzer, Marc Schoenauer, 2001
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
Marc.Schoenauer@polytechnique.fr
mkeijzer@dhi.dk
*/
//-----------------------------------------------------------------------------
#ifndef eoFrontSorter_h
#define eoFrontSorter_h
#include <EO.h>
#include <algorithm>
#include <eoPop.h>
#include <cassert>
namespace detail {
// small helper structs to store the multi-objective information. To be used in the implementation
struct FitnessInfo {
std::vector<double> fitness; // preprocessed fitness -> all maximizing
unsigned index; // index into population
FitnessInfo() {}
FitnessInfo(const std::vector<double>& fitness_, unsigned index_) : fitness(fitness_), index(index_) {}
};
extern void front_sorter_impl(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& fronts);
} // namespace detail
/**
* Reassembles population into a set of fronts;
*/
template <class EOT>
class eoFrontSorter : public eoUF< const eoPop<EOT>&, const std::vector< std::vector<detail::FitnessInfo> >& >
{
std::vector<detail::FitnessInfo > fitness;
std::vector< std::vector<detail::FitnessInfo> > fronts;
public :
typedef typename EOT::Fitness::fitness_traits Traits;
typedef std::vector< std::vector<detail::FitnessInfo> > front_t;
const std::vector<std::vector<detail::FitnessInfo> >& operator()(const eoPop<EOT>& _pop)
{
fitness.resize(_pop.size());
for (unsigned i = 0; i < _pop.size(); ++i) {
std::vector<double> f;
for (unsigned j = 0; j < Traits::nObjectives(); ++j) {
if (Traits::maximizing(j) != 0) f.push_back( Traits::maximizing(j) * _pop[i].fitness()[j]);
}
fitness[i] = detail::FitnessInfo(f, i);
}
detail::front_sorter_impl(fitness, fronts);
return fronts;
}
};
#endif

174
eo/src/moo/eoMOFitness.h Normal file
View file

@ -0,0 +1,174 @@
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
//-----------------------------------------------------------------------------
// eoMOFitness.h
// (c) Maarten Keijzer and Marc Schoenauer, 2007
/*
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: mak@dhi.dk
Marc.Schoenauer@inria.fr
*/
//-----------------------------------------------------------------------------
#ifndef _eoMOFitness_h
#define _eoMOFitness_h
#include <math.h>
#include <vector>
#include <stdexcept>
#include <iostream>
/**
* eoMOFitnessTraits: a traits class to specify
* the number of objectives and which one are maximizing or not
* See test/t-eoParetoFitness for its use.
*
* If you define your own, make sure you make the functions static!
*/
class eoMOFitnessTraits
{
public :
static unsigned nObjectives() { return 2; }
static double maximizing(int which) { return 1; } // by default: all are maximizing, zero will lead to ignored fitness, negative minimizes
};
/**
eoMOFitness class: std::vector of doubles with overloaded comparison operators. Comparison is done
on 'worth'. This worth needs to be set elsewhere. The template argument FitnessTraits defaults to eMOFitnessTraits, which
can be replaces at will by any other class that implements the static functions defined therein.
Note that the comparison defines a partial order, so that
!(a < b) && !(b <a) does not neccessarily imply that (a==b)
The other way around does hold.
*/
template <class FitnessTraits = eoMOFitnessTraits>
class eoMOFitness : public std::vector<double>
{
double worth; // used for sorting and selection, by definition, bigger is better
bool validWorth;
public :
typedef FitnessTraits fitness_traits;
eoMOFitness(double def = 0.0) : std::vector<double>(FitnessTraits::nObjectives(),def), validWorth(false) {}
// Ctr from a std::vector<double>
eoMOFitness(std::vector<double> & _v) : std::vector<double>(_v), validWorth(false) {}
/** access to the traits characteristics (so you don't have to write
* a lot of typedef's around
*/
static void setUp(unsigned _n, std::vector<bool> & _b) {FitnessTraits::setUp(_n, _b);}
static bool maximizing(unsigned _i) { return FitnessTraits::maximizing(_i);}
void setWorth(double worth_) {
worth = worth_;
validWorth = true;
}
double getWorth() const {
if (!validWorth) {
throw std::runtime_error("invalid worth");
}
return worth;
}
/// Partial order based on Pareto-dominance
//bool operator<(const eoMOFitness<FitnessTraits>& _other) const
bool dominates(const eoMOFitness<FitnessTraits>& _other) const
{
bool dom = false;
const std::vector<double>& performance = *this;
const std::vector<double>& otherperformance = _other;
for (unsigned i = 0; i < FitnessTraits::nObjectives(); ++i)
{
double maxim = FitnessTraits::maximizing(i);
double aval = maxim * performance[i];
double bval = maxim * otherperformance[i];
if (aval != bval)
{
if (aval < bval)
{
return false; // cannot dominate
}
// else aval < bval
dom = true; // for the moment: goto next objective
}
//else they're equal in this objective, goto next
}
return dom;
}
/// compare *not* on dominance, but on worth
bool operator<(const eoMOFitness<FitnessTraits>& _other) const
{
return getWorth() > _other.getWorth();
}
bool operator>(const eoMOFitness<FitnessTraits>& _other) const
{
return _other < *this;
}
bool operator<=(const eoMOFitness<FitnessTraits>& _other) const
{
return getWorth() >= _other.getWorth();
}
bool operator>=(const eoMOFitness<FitnessTraits>& _other) const
{
return _other <= *this;
}
bool operator==(const eoMOFitness<FitnessTraits>& _other) const
{ // check if they're all within tolerance
return getWorth() == _other.getWorth();
}
bool operator!=(const eoMOFitness<FitnessTraits>& _other) const
{ return ! operator==(_other); }
friend std::ostream& operator<<(std::ostream& os, const eoMOFitness<FitnessTraits>& fitness)
{
for (unsigned i = 0; i < fitness.size(); ++i)
{
os << fitness[i] << ' ';
}
os << fitness.validWorth << ' ' << fitness.worth;
return os;
}
friend std::istream& operator>>(std::istream& is, eoMOFitness<FitnessTraits>& fitness)
{
fitness = eoMOFitness<FitnessTraits>();
for (unsigned i = 0; i < fitness.size(); ++i)
{
is >> fitness[i];
}
is >> fitness.validWorth >> fitness.worth;
return is;
}
};
#endif

View file

@ -0,0 +1,123 @@
#ifndef eoNSGA_II_Replacement_h
#define eoNSGA_II_Replacement_h
#include <moo/eoFrontSorter.h>
#include <eoReplacement.h>
/** @brief Fast Elitist Non-Dominant Sorting Genetic Algorithm
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_std::vector will give the right order
*/
template <class EOT>
class eoNSGA_II_Replacement : public eoReplacement<EOT>
{
public:
void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
unsigned origSize = parents.size();
std::copy(offspring.begin(), offspring.end(), std::back_inserter(parents));
typename eoFrontSorter<EOT>::front_t front = sorter(parents);
for (unsigned i = 0; i < front.size(); ++i) {
assign_worths(front[i], front.size() - i, parents);
}
// sort on worth (assuming eoMOFitness)
std::sort(parents.begin(), parents.end());
// truncate
parents.resize(origSize);
}
eoFrontSorter<EOT> sorter;
private:
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;
}
};
/// _cf points into the elements that consist of the current front
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, eoPop<EOT>& parents) {
typedef typename EOT::Fitness::fitness_traits traits;
unsigned i;
unsigned nObjectives = traits::nObjectives(); //_pop[_cf[0]].fitness().size();
std::vector<double> niche_distance(front.size());
for (unsigned o = 0; o < nObjectives; ++o)
{
std::vector<std::pair<double, unsigned> > performance(front.size());
for (i =0; i < front.size(); ++i)
{
performance[i].first = front[i].fitness[o];
performance[i].second = i;
}
std::sort(performance.begin(), performance.end(), compare_nodes()); // a lambda operator would've been nice here
std::vector<double> nc(front.size(), 0.0);
for (i = 1; i < front.size()-1; ++i)
{ // and yet another level of indirection
nc[performance[i].second] = performance[i+1].first - performance[i-1].first;
}
// set boundary at max_dist + 1 (so it will get chosen over all the others
//nc[performance[0].second] += 0;
nc[performance.back().second] += std::numeric_limits<double>::infinity(); // best on objective
for (i = 0; i < nc.size(); ++i)
{
niche_distance[i] += nc[i];
}
}
// now we've got niche_distances, scale them between (0, 1), making sure that infinities get maximum rank
double max = 0;
for (unsigned i = 0; i < niche_distance[i]; ++i) {
if (niche_distance[i] != std::numeric_limits<double>::infinity()) {
max = std::max(max, niche_distance[i]);
}
}
for (unsigned i = 0; i < front.size(); ++i) {
double dist = niche_distance[i];
if (dist == std::numeric_limits<double>::infinity()) {
dist = 1.0;
} else {
dist /= (1+max);
}
unsigned idx = front[i].index;
typename EOT::Fitness f = parents[idx].fitness();
f.setWorth(rank + dist);
//std::cout << "Base rank " << rank << " dist " << dist << " result " << (rank+dist) << std::endl;
parents[idx].fitness(f);
}
}
};
#endif

View file

@ -0,0 +1,150 @@
#ifndef eoNSGA_IIa_Replacement_h
#define eoNSGA_IIa_Replacement_h
#include <moo/eoFrontSorter.h>
#include <eoReplacement.h>
/** @brief Fast Elitist Non-Dominant Sorting Genetic Algorithm
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_std::vector will give the right order
*/
template <class EOT>
class eoNSGA_IIa_Replacement : public eoReplacement<EOT>
{
public:
void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
unsigned origSize = parents.size();
std::copy(offspring.begin(), offspring.end(), std::back_inserter(parents));
typename eoFrontSorter<EOT>::front_t front = sorter(parents);
unsigned rank = parents.size();
for (unsigned i = 0; i < front.size(); ++i) {
rank = assign_worths(front[i], rank, parents);
}
// sort on worth (assuming eoMOFitness)
std::sort(parents.begin(), parents.end());
// truncate
parents.resize(origSize);
}
private:
eoFrontSorter<EOT> sorter;
double distance(const std::vector<double>& f1, const std::vector<double>& f2, const std::vector<double>& range) {
double dist = 0;
for (unsigned i = 0; i < f1.size(); ++i) {
double d = (f1[i] - f2[i])/range[i];
dist += d*d;
}
return dist;
}
unsigned assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, eoPop<EOT>& parents) {
unsigned nDim = front[0].fitness.size();
// find boundary points
std::vector<unsigned> processed(nDim);
for (unsigned i = 1; i < front.size(); ++i) {
for (unsigned dim = 0; dim < nDim; ++dim) {
if (front[i].fitness[dim] > front[processed[dim]].fitness[dim]) {
processed[dim] = i;
}
}
}
// assign fitness to processed
for (unsigned i = 0; i < processed.size(); ++i) {
typename EOT::Fitness f = parents[ front[ processed[i] ].index].fitness();
f.setWorth(rank);
parents[ front[ processed[i] ].index ].fitness(f);
}
rank--;
// calculate ranges
std::vector<double> mins(nDim, std::numeric_limits<double>::infinity());
for (unsigned dim = 0; dim < nDim; ++dim) {
for (unsigned i = 0; i < nDim; ++i) {
mins[dim] = std::min( mins[dim], front[ processed[i] ].fitness[dim] );
}
}
std::vector<double> range(nDim);
for (unsigned dim = 0; dim < nDim; ++dim) {
range[dim] = front[ processed[dim] ].fitness[dim] - mins[dim];
}
// calculate distances
std::vector<double> distances(front.size(), std::numeric_limits<double>::infinity());
unsigned selected = 0;
// select based on maximum distance to nearest processed point
for (unsigned i = 0; i < front.size(); ++i) {
for (unsigned k = 0; k < processed.size(); ++k) {
if (i==processed[k]) {
distances[i] = -1.0;
continue;
}
double d = distance( front[i].fitness, front[ processed[k] ].fitness, range );
if (d < distances[i]) {
distances[i] = d;
}
}
if (distances[i] > distances[selected]) {
selected = i;
}
}
while (processed.size() < front.size()) {
// set worth
typename EOT::Fitness f = parents[ front[selected].index ].fitness();
f.setWorth(rank--);
parents[ front[selected].index ].fitness(f);
distances[selected] = -1;
processed.push_back(selected);
selected = 0;
for (unsigned i = 0; i < front.size(); ++i) {
if (distances[i] < 0) continue;
double d = distance(front[i].fitness, front[processed.back()].fitness, range);
if (d < distances[i]) {
distances[i] = d;
}
if (distances[i] > distances[selected]) {
selected = i;
}
}
}
return rank;
}
};
#endif

View file

@ -0,0 +1,75 @@
#ifndef __EONDSorting_I_h
#define __EONDSorting_I_h
#include <moo/eoFrontSorter.h>
/**
The original Non Dominated Sorting algorithm from Srinivas and Deb
*/
template <class EOT>
class eoNSGA_I_Replacement : public eoReplacement<EOT>
{
public :
eoNSGA_I_Replacement(double _nicheSize) : nicheSize(_nicheSize) {}
void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
unsigned origSize = parents.size();
std::copy(offspring.begin(), offspring.end(), std::back_inserter(parents));
typename eoFrontSorter<EOT>::front_t front = sorter(parents);
for (unsigned i = 0; i < front.size(); ++i) {
assign_worths(front[i], front.size() - i, parents);
}
// sort on worth (assuming eoMOFitness)
std::sort(parents.begin(), parents.end());
// truncate
parents.resize(origSize);
}
private:
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, eoPop<EOT>& parents) {
for (unsigned i = 0; i < front.size(); ++i)
{ // calculate whether the other points lie within the nice
double niche_count = 0;
for (unsigned j = 0; j < front.size(); ++j)
{
if (i == j)
continue;
double dist = 0.0;
for (unsigned k = 0; k < front[j].fitness.size(); ++k)
{
double d = front[i].fitness[k] - front[j].fitness[k];
dist += d*d;
}
if (dist < nicheSize)
{
niche_count += 1.0 - pow(dist / nicheSize,2.);
}
}
unsigned idx = front[i].index;
typename EOT::Fitness f = parents[idx].fitness();
f.setWorth(rank + niche_count);
parents[ idx ].fitness(f);
}
}
private :
double nicheSize;
eoFrontSorter<EOT> sorter;
};
#endif

View file

@ -3,12 +3,12 @@
## Makefile.am for eo/test
##
###############################################################################
LIBEO = $(top_builddir)/src/libeo.a
LIBEOUTILS = $(top_builddir)/src/utils/libeoutils.a
LIBES = $(top_builddir)/src/es/libes.a
LIBGA = $(top_builddir)/src/ga/libga.a
LIBCMA = $(top_builddir)/src/es/libcma.a
LIBMOO = $(top_builddir)/src/moo/libeomoo.a
# PLEASE don't break the line (see create_batch.sh)
check_PROGRAMS = t-eoParetoFitness \
@ -41,7 +41,9 @@ check_PROGRAMS = t-eoParetoFitness \
t-eoCMAES \
t-eoSecondsElapsedContinue\
t-eoRNG \
t-eoEasyPSO
t-eoEasyPSO \
t-eoNSGA \
t-eoFrontSorter
TESTS = $(check_PROGRAMS) \
run_tests # This script can be used to check command-line arguments
@ -49,7 +51,7 @@ TESTS = $(check_PROGRAMS) \
noinst_HEADERS = binary_value.h real_value.h RoyalRoad.h
DEPS = $(LIBGA) $(LIBES) $(LIBCMA) $(LIBEOUTILS) $(LIBEO)
DEPS = $(LIBGA) $(LIBES) $(LIBCMA) $(LIBEOUTILS) $(LIBEO) $(LIBMOO)
INCLUDES = -I$(top_srcdir)/src -I$(srcdir)/../src
LIBS = $(DEPS)
@ -96,3 +98,6 @@ t_eoCMAES_SOURCES = t-eoCMAES.cpp
t_eoRNG_SOURCES = t-eoRNG.cpp
t_eoSecondsElapsedContinue_SOURCES = t-eoSecondsElapsedContinue.cpp
t_eoEasyPSO_SOURCES = t-eoEasyPSO.cpp
t_eoNSGA_SOURCES = t-eoNSGA.cpp
t_eoFrontSorter_SOURCES = t-eoFrontSorter.cpp

205
eo/test/t-eoNSGA.cpp Normal file
View file

@ -0,0 +1,205 @@
#include <eo>
#include <moo/eoMOFitness.h>
#include <moo/eoNSGA_I_Replacement.h>
#include <moo/eoNSGA_II_Replacement.h>
#include <moo/eoNSGA_IIa_Replacement.h>
using namespace std;
// Look: overloading the maximization without overhead (thing can be inlined)
class MinimizingFitnessTraits : public eoMOFitnessTraits
{
public :
static double maximizing(int) { return -1; }
};
typedef eoMOFitness<MinimizingFitnessTraits> fitness_type;
const unsigned chromsize=5;
const double minval = -15;
const double maxval = 15;
struct eoDouble : public EO<fitness_type>
{
double value[chromsize];
};
class Mutate : public eoMonOp<eoDouble>
{
bool operator()(eoDouble& _eo)
{
for (unsigned i = 0; i < chromsize; ++i)
{
if (rng.flip(1./chromsize))
_eo.value[i] += rng.normal() * 0.1 * _eo.value[i];
if (_eo.value[i] < minval)
_eo.value[i] = minval;
else if (_eo.value[i] > maxval)
_eo.value[i] = maxval;
}
return true;
}
};
class Eval : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
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);
}
};
class Eval2 : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
vector<double> x(_eo.value, _eo.value + chromsize);
fitness_type f;
for (unsigned i = 0; i < chromsize; ++i)
{
f[0] += x[i] * x[i];
}
f[1] =
3 * x[0] + 2 * x[1]
- x[2]/3 + 0.01*pow(x[3] - x[4], 3);
_eo.fitness(f);
}
};
class Eval3 : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
double x = _eo.value[0];
fitness_type f;
f[0] = x * x;
double y = x-10;
f[1] = y * y;
_eo.fitness(f);
}
};
class Init : public eoInit<eoDouble>
{
void operator()(eoDouble& _eo)
{
_eo.value[0] = rng.uniform();
double range = maxval - minval;
for (unsigned i = 1; i < chromsize; ++i)
_eo.value[i] = rng.uniform() * range + minval;
_eo.invalidate();
}
};
// Test pareto dominance and perf2worth, and while you're at it, test the eoGnuPlot monitor as well
void the_main(int argc, char* argv[])
{
Init init;
Eval eval;
Mutate mutate;
eoParser parser(argc, argv);
eoState state;
unsigned num_gen = parser.createParam(unsigned(50), "num_gen", "number of generations to run", 'g').value();
unsigned pop_size = parser.createParam(unsigned(100), "pop_size", "population size", 'p').value();
bool use_nsga1 = parser.createParam(false, "nsga1", "Use nsga 1").value();
eoPop<eoDouble> pop(pop_size, init);
// binary tournament selection
eoDetTournamentSelect<eoDouble> select;
// One general operator
eoProportionalOp<eoDouble> opsel;
opsel.add(mutate, 1.0);
// the breeder
eoGeneralBreeder<eoDouble> breeder(select, opsel);
// replacement
eoNSGA_IIa_Replacement<eoDouble> nsga1;
eoNSGA_II_Replacement<eoDouble> nsga2;
eoReplacement<eoDouble>& replace = use_nsga1 ? static_cast<eoReplacement<eoDouble>&>(nsga1) : static_cast<eoReplacement<eoDouble>&>(nsga2);
unsigned long generation = 0;
eoGenContinue<eoDouble> gen(num_gen, generation);
eoCheckPoint<eoDouble> cp(gen);
eoMOFitnessStat<eoDouble> fitness0(0, "FirstObjective");
eoMOFitnessStat<eoDouble> fitness1(1, "SecondObjective");
cp.add(fitness0);
cp.add(fitness1);
eoGnuplot1DSnapshot snapshot("pareto");
//snapshot.with(eoGnuplot::Points(3));
cp.add(snapshot);
snapshot.add(fitness0);
snapshot.add(fitness1);
// the algo
eoEasyEA<eoDouble> ea(cp, eval, breeder, replace);
if (parser.userNeedsHelp())
{
parser.printHelp(std::cout);
return;
}
apply<eoDouble>(eval, pop);
eoPop<eoDouble> nothing;
replace(pop, nothing); // calculates worths
ea(pop);
}
int main(int argc, char* argv[])
{
the_main(argc, argv);
return 0;
try
{
the_main(argc, argv);
}
catch (std::exception& e)
{
std::cout << "Exception thrown: " << e.what() << std::endl;
throw e; // make sure it does not pass the test
}
}
// Local Variables:
// mode: C++
// c-file-style: "Stroustrup"
// End: