added new multi-objective support
This commit is contained in:
parent
283026ed5c
commit
553586d55f
12 changed files with 1049 additions and 9 deletions
|
|
@ -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
56
eo/src/moo/CMakeLists.txt
Normal 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
9
eo/src/moo/Makefile.am
Normal 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
|
||||
156
eo/src/moo/eoFrontSorter.cpp
Normal file
156
eo/src/moo/eoFrontSorter.cpp
Normal 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
|
||||
|
||||
85
eo/src/moo/eoFrontSorter.h
Normal file
85
eo/src/moo/eoFrontSorter.h
Normal 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
174
eo/src/moo/eoMOFitness.h
Normal 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
|
||||
123
eo/src/moo/eoNSGA_II_Replacement.h
Normal file
123
eo/src/moo/eoNSGA_II_Replacement.h
Normal 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
|
||||
150
eo/src/moo/eoNSGA_IIa_Replacement.h
Normal file
150
eo/src/moo/eoNSGA_IIa_Replacement.h
Normal 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
|
||||
75
eo/src/moo/eoNSGA_I_Replacement.h
Normal file
75
eo/src/moo/eoNSGA_I_Replacement.h
Normal 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
|
||||
|
||||
|
||||
Reference in a new issue