fix #10: removed the moo/ directory and eoMO* classes, deprecated by the Paradiseo-MOEO project
This commit is contained in:
parent
1f2de972a6
commit
653bc392ed
15 changed files with 0 additions and 1846 deletions
|
|
@ -1 +0,0 @@
|
|||
Makefile.in
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
######################################################################################
|
||||
### 1) Include the sources
|
||||
######################################################################################
|
||||
|
||||
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
######################################################################################
|
||||
### 2) Define the eomoo target
|
||||
######################################################################################
|
||||
|
||||
SET(EOMOO_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
|
||||
SET(LIBRARY_OUTPUT_PATH ${EOMOO_LIB_OUTPUT_PATH})
|
||||
|
||||
SET (EOMOO_SOURCES eoFrontSorter.cpp
|
||||
eoNSGA_IIa_Eval.cpp
|
||||
eoNSGA_II_Eval.cpp)
|
||||
|
||||
|
||||
ADD_LIBRARY(eomoo STATIC ${EOMOO_SOURCES})
|
||||
INSTALL(TARGETS eomoo ARCHIVE DESTINATION lib COMPONENT libraries)
|
||||
|
||||
FILE(GLOB HDRS *.h)
|
||||
INSTALL(FILES ${HDRS} DESTINATION include/eo/moo COMPONENT headers)
|
||||
|
||||
######################################################################################
|
||||
### 3) Optionnal
|
||||
######################################################################################
|
||||
|
||||
SET(EOMOO_VERSION ${GLOBAL_VERSION})
|
||||
SET_TARGET_PROPERTIES(eomoo PROPERTIES VERSION "${EOMOO_VERSION}")
|
||||
|
||||
######################################################################################
|
||||
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
#ifndef eoEpsMOEA_h
|
||||
#define eoEpsMOEA_h
|
||||
|
||||
#include <eoAlgo.h>
|
||||
#include <moo/eoEpsilonArchive.h>
|
||||
#include <utils/eoStat.h>
|
||||
|
||||
|
||||
template <class EOT>
|
||||
class eoEpsMOEA : public eoAlgo<EOT> {
|
||||
|
||||
public:
|
||||
|
||||
eoEpsMOEA(
|
||||
eoContinue<EOT>& _continuator,
|
||||
eoEvalFunc<EOT>& _eval,
|
||||
eoGenOp<EOT>& _op,
|
||||
const std::vector<double>& eps,
|
||||
unsigned max_archive_size = std::numeric_limits<unsigned>::max()
|
||||
) : continuator(_continuator),
|
||||
eval (_eval),
|
||||
loopEval(_eval),
|
||||
popEval(loopEval),
|
||||
op(_op),
|
||||
archive(eps, max_archive_size)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void operator()(eoPop<EOT>& pop) {
|
||||
|
||||
eoPop<EOT> offspring;
|
||||
popEval(offspring, pop);
|
||||
for (unsigned i = 0; i < pop.size(); ++i) pop[i].fitnessReference().setWorth(1.0);
|
||||
|
||||
do {
|
||||
unsigned nProcessed = 0;
|
||||
|
||||
while (nProcessed < pop.size()) {
|
||||
offspring.clear();
|
||||
|
||||
epsPopulator populator(archive, pop, offspring);
|
||||
op(populator);
|
||||
|
||||
nProcessed += offspring.size();
|
||||
popEval(pop, offspring);
|
||||
|
||||
for (unsigned i = 0; i < offspring.size(); ++i) {
|
||||
offspring[i].fitnessReference().setWorth(1.0);
|
||||
archive(offspring[i]);
|
||||
update_pop(pop, offspring[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// quite expensive to copy the entire archive time and time again, but this will make it work more seamlessly with the rest of EO
|
||||
offspring.clear();
|
||||
archive.appendTo(offspring);
|
||||
|
||||
} while (continuator(offspring)); // check archive
|
||||
|
||||
// return archive
|
||||
pop.clear();
|
||||
archive.appendTo(pop);
|
||||
|
||||
}
|
||||
|
||||
private :
|
||||
void update_pop(eoPop<EOT>& pop, const EOT& offspring) {
|
||||
std::vector<unsigned> dominated;
|
||||
|
||||
for (unsigned i = 0; i < pop.size(); ++i) {
|
||||
int dom = offspring.fitness().check_dominance(pop[i].fitness());
|
||||
switch (dom) {
|
||||
case 1 : // indy dominates this
|
||||
dominated.push_back(i);
|
||||
break;
|
||||
case -1 : // is dominated, do not insert
|
||||
return;
|
||||
case 0: // incomparable
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dominated.size()) {
|
||||
pop[ dominated[ rng.random(dominated.size()) ] ] = offspring;
|
||||
}
|
||||
|
||||
// non-dominated everywhere, overwrite random one
|
||||
pop[ rng.random(pop.size()) ] = offspring;
|
||||
}
|
||||
|
||||
class epsPopulator : public eoPopulator<EOT> {
|
||||
|
||||
using eoPopulator< EOT >::src;
|
||||
|
||||
eoEpsilonArchive<EOT>& archive;
|
||||
bool fromArchive;
|
||||
public:
|
||||
epsPopulator(eoEpsilonArchive<EOT>& arch, const eoPop<EOT>& pop, eoPop<EOT>& res) : eoPopulator<EOT>(pop, res), archive(arch), fromArchive(true) {}
|
||||
|
||||
const EOT& select() {
|
||||
fromArchive = !fromArchive;
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
if (fromArchive && !archive.empty()) {
|
||||
return archive.selectRandom();
|
||||
}
|
||||
|
||||
// tournament selection on population
|
||||
const EOT& eo1 = rng.choice(src);
|
||||
const EOT& eo2 = rng.choice(src);
|
||||
|
||||
if (eo1.fitness().dominates(eo2.fitness())) return eo1;
|
||||
return eo2; // they are drawn at random, so no need to do an extra randomization step
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
eoContinue<EOT>& continuator;
|
||||
|
||||
eoEvalFunc <EOT> & eval ;
|
||||
eoPopLoopEval<EOT> loopEval;
|
||||
|
||||
eoPopEvalFunc<EOT>& popEval;
|
||||
|
||||
eoGenOp<EOT>& op;
|
||||
|
||||
eoEpsilonArchive<EOT> archive;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
#ifndef eoEpsilonArchive_h
|
||||
#define eoEpsilonArchive_h
|
||||
|
||||
#include <moo/eoMOFitness.h>
|
||||
#include <list>
|
||||
|
||||
template <class EOT>
|
||||
class eoEpsilonArchive {
|
||||
|
||||
typedef typename EOT::Fitness::fitness_traits Traits;
|
||||
|
||||
struct Node {
|
||||
EOT element;
|
||||
std::vector<long> discretized;
|
||||
|
||||
Node(const EOT& eo) : element(eo), discretized(Traits::nObjectives()) {}
|
||||
|
||||
dominance::dominance_result check(const Node& other) const {
|
||||
return dominance::check_discrete(discretized, other.discretized);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<Node> archive_t;
|
||||
|
||||
archive_t archive;
|
||||
std::vector<double> inv_eps;
|
||||
|
||||
unsigned max_size;
|
||||
|
||||
public:
|
||||
|
||||
static double direction(unsigned i) { return 1; }
|
||||
static double tol() { return 1e-6; }
|
||||
|
||||
|
||||
eoEpsilonArchive(const std::vector<double>& eps_, unsigned max_size_ = std::numeric_limits<unsigned>::max()) : max_size(max_size_) {
|
||||
inv_eps.resize(eps_.size());
|
||||
for (unsigned i = 0; i < inv_eps.size(); ++i) {
|
||||
inv_eps[i] = 1.0 / eps_[i];
|
||||
}
|
||||
if (inv_eps.size() != Traits::nObjectives()) throw std::logic_error("eoEpsilonArchive: need one epsilon for each objective");
|
||||
}
|
||||
|
||||
bool empty() { return archive.size() == 0; }
|
||||
|
||||
void operator()(const EOT& eo) {
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
// discretize
|
||||
Node node(eo);
|
||||
for (unsigned i = 0; i < eo.fitness().size(); ++i) {
|
||||
double val = Traits::direction(i) * eo.fitness()[i];
|
||||
|
||||
node.discretized[i] = (long) floor(val*inv_eps[i]);
|
||||
}
|
||||
|
||||
using namespace dominance;
|
||||
|
||||
unsigned box = archive.size();
|
||||
// update archive
|
||||
|
||||
|
||||
for (unsigned i = 0; i != archive.size(); ++i) {
|
||||
dominance_result result = node.check(archive[i]); //check<eoEpsilonArchive<EOT> >(node.discretized, archive[i].discretized);
|
||||
|
||||
switch (result) {
|
||||
case first : { // remove dominated archive member
|
||||
std::swap( archive[i], archive.back());
|
||||
archive.pop_back();
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
case second : {
|
||||
return; // new one does not belong in archive
|
||||
}
|
||||
case non_dominated : break; // both non-dominated, put in different boxes
|
||||
case non_dominated_equal : { // in same box
|
||||
box = i;
|
||||
goto exitLoop; // break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exitLoop:
|
||||
// insert
|
||||
if (box >= archive.size()) { // non-dominated, new box
|
||||
archive.push_back(node);
|
||||
} else { // fight it out
|
||||
int dom = node.element.fitness().check_dominance( archive[box].element.fitness() );
|
||||
|
||||
switch (dom) {
|
||||
case 1: archive[box] = node; break;
|
||||
case -1: break;
|
||||
case 0: {
|
||||
double d1 = 0.0;
|
||||
double d2 = 0.0;
|
||||
|
||||
for (unsigned i = 0; i < node.element.fitness().size(); ++i) {
|
||||
double a = Traits::direction(i) * node.element.fitness()[i] * inv_eps[i];
|
||||
double b = Traits::direction(i) * archive[box].element.fitness()[i] * inv_eps[i];
|
||||
|
||||
d1 += pow( a - node.discretized[i], 2.0);
|
||||
d2 += pow( b - node.discretized[i], 2.0);
|
||||
}
|
||||
|
||||
if (d1 > d2) {
|
||||
archive[box] = node;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (archive.size() > max_size) {
|
||||
unsigned idx = rng.random(archive.size());
|
||||
if (idx != archive.size()-1) std::swap(archive[idx], archive.back());
|
||||
archive.pop_back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void appendTo(eoPop<EOT>& pop) const {
|
||||
for (typename archive_t::const_iterator it = archive.begin(); it != archive.end(); ++it) {
|
||||
pop.push_back( it->element );
|
||||
}
|
||||
}
|
||||
|
||||
const EOT& selectRandom() const {
|
||||
int i = rng.random(archive.size());
|
||||
return archive[i].element;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
#include <moo/eoFrontSorter.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace detail {
|
||||
|
||||
void one_objective(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front, double tol)
|
||||
{
|
||||
std::sort(fitness.begin(), fitness.end(), CompareOn(0, tol));
|
||||
|
||||
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, double tol)
|
||||
{
|
||||
std::sort(fitness.begin(), fitness.end(), CompareOn(0, tol));
|
||||
|
||||
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, tol));
|
||||
|
||||
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, double tol) {
|
||||
bool better_on_one = false;
|
||||
|
||||
for (unsigned i = 0; i < a.fitness.size(); ++i) {
|
||||
if (fabs(a.fitness[i] - b.fitness[i]) < tol) continue;
|
||||
|
||||
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, double tol) {
|
||||
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], tol) )
|
||||
{ // i dominates j
|
||||
S[i].push_back(j); // add j to i's domination list
|
||||
}
|
||||
else if (dominates(fitness[j], fitness[i], tol))
|
||||
{ // 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, double tol) {
|
||||
|
||||
switch (fitness[0].fitness.size())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
one_objective(fitness, front_indices, tol);
|
||||
return;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
two_objectives(fitness, front_indices, tol);
|
||||
return;
|
||||
}
|
||||
default :
|
||||
{
|
||||
m_objectives(fitness, front_indices, tol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/** -*- 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_) {}
|
||||
};
|
||||
|
||||
struct CompareOn {
|
||||
unsigned dim;
|
||||
double tol;
|
||||
|
||||
CompareOn(unsigned d, double t) : dim(d), tol(t) {}
|
||||
|
||||
bool operator()(const FitnessInfo& a, const FitnessInfo& b) {
|
||||
return a.fitness[dim] > b.fitness[dim] && fabs(a.fitness[dim] - b.fitness[dim]) > tol;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern void front_sorter_impl(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& fronts, double tol);
|
||||
|
||||
} // 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) {
|
||||
fitness[i] = detail::FitnessInfo(_pop[i].fitness().normalized(), i);
|
||||
}
|
||||
|
||||
detail::front_sorter_impl(fitness, fronts, Traits::tol());
|
||||
|
||||
return fronts;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<detail::FitnessInfo> >& operator()(const std::vector<EOT*>& _pop)
|
||||
{
|
||||
fitness.resize(_pop.size());
|
||||
for (unsigned i = 0; i < _pop.size(); ++i) {
|
||||
fitness[i] = detail::FitnessInfo(_pop[i]->fitness().normalized(), i);
|
||||
}
|
||||
|
||||
detail::front_sorter_impl(fitness, fronts, Traits::tol());
|
||||
|
||||
return fronts;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef eoMOEval_h
|
||||
#define eoMOEval_h
|
||||
|
||||
#include <eoPopEvalFunc.h>
|
||||
|
||||
template <class EOT>
|
||||
class eoMOEval : public eoPopEvalFunc<EOT> {
|
||||
|
||||
protected:
|
||||
eoMOEval(eoEvalFunc<EOT>& eval) : default_loop(eval), pop_eval(default_loop) {}
|
||||
eoMOEval(eoPopEvalFunc<EOT>& ev) : default_loop(dummy_eval), pop_eval(ev) {}
|
||||
|
||||
void eval(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
|
||||
pop_eval(parents, offspring);
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
class eoDummyEval : public eoEvalFunc<EOT> {public: void operator()(EOT &) {} } dummy_eval;
|
||||
eoPopLoopEval<EOT> default_loop;
|
||||
eoPopEvalFunc<EOT>& pop_eval;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
// -*- 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>
|
||||
#include <limits>
|
||||
|
||||
/**
|
||||
* eoMOFitnessTraits: a traits class to specify
|
||||
* the number of objectives and which one are direction or not
|
||||
* See test/t-eoParetoFitness for its use.
|
||||
*
|
||||
* If you define your own, make sure you make the functions static!
|
||||
*/
|
||||
class eoMOFitnessTraits
|
||||
{
|
||||
public :
|
||||
|
||||
/// Number of Objectives
|
||||
static unsigned nObjectives() { return 2; }
|
||||
|
||||
/// by default: all are maximizing, zero will lead to ignored fitness, negative to minimization for that objective
|
||||
static double direction(unsigned which) { return 1; }
|
||||
|
||||
/// tolerance for dominance check (if within this tolerance objective values are considered equal)
|
||||
static double tol() { return 1e-6; }
|
||||
|
||||
};
|
||||
|
||||
namespace dominance {
|
||||
|
||||
template <class Traits>
|
||||
inline double worst_possible_value(unsigned objective) {
|
||||
double dir = Traits::direction(objective);
|
||||
if (dir == 0.) return 0.0;
|
||||
if (dir < 0.) return std::numeric_limits<double>::infinity();
|
||||
return -std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
inline double best_possible_value(unsigned objective) {
|
||||
return -worst_possible_value<Traits>(objective);
|
||||
}
|
||||
|
||||
enum dominance_result { non_dominated_equal, first, second, non_dominated };
|
||||
|
||||
template <class FitnessDirectionTraits>
|
||||
inline dominance_result check(const std::vector<double>& p1, const std::vector<double>& p2, double tolerance) {
|
||||
|
||||
bool all_equal = true;
|
||||
bool a_better_in_one = false;
|
||||
bool b_better_in_one = false;
|
||||
|
||||
for (unsigned i = 0; i < p1.size(); ++i) {
|
||||
|
||||
double maxim = FitnessDirectionTraits::direction(i);
|
||||
double aval = maxim * p1[i];
|
||||
double bval = maxim * p2[i];
|
||||
|
||||
if ( fabs(aval-bval) > tolerance ) {
|
||||
all_equal = false;
|
||||
if (aval > bval) {
|
||||
a_better_in_one = true;
|
||||
|
||||
} else {
|
||||
b_better_in_one = true;
|
||||
}
|
||||
// check if we need to go on
|
||||
|
||||
if (a_better_in_one && b_better_in_one) return non_dominated;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (all_equal) return non_dominated_equal;
|
||||
|
||||
if (a_better_in_one) return first;
|
||||
// else b dominates a (check for non-dominance done above
|
||||
return second;
|
||||
}
|
||||
|
||||
template <class IntType>
|
||||
inline dominance_result check_discrete(const std::vector<IntType>& a, const std::vector<IntType>& b) {
|
||||
|
||||
bool all_equal = true;
|
||||
bool a_better_in_one = false;
|
||||
bool b_better_in_one = false;
|
||||
|
||||
for (unsigned i = 0; i < a.size(); ++i) {
|
||||
|
||||
if ( a[i] != b[i] ) {
|
||||
all_equal = false;
|
||||
if (a[i] > b[i]) {
|
||||
a_better_in_one = true;
|
||||
|
||||
} else {
|
||||
b_better_in_one = true;
|
||||
}
|
||||
// check if we need to go on
|
||||
|
||||
if (a_better_in_one && b_better_in_one) return non_dominated;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (all_equal) return non_dominated_equal;
|
||||
|
||||
if (a_better_in_one) return first;
|
||||
// else b dominates a (check for non-dominance done above
|
||||
return second;
|
||||
}
|
||||
|
||||
template <class FitnessTraits>
|
||||
inline dominance_result check(const std::vector<double>& p1, const std::vector<double>& p2) {
|
||||
return check<FitnessTraits>(p1, p2, FitnessTraits::tol());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace dominance
|
||||
|
||||
/**
|
||||
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 worthValid;
|
||||
public :
|
||||
|
||||
typedef FitnessTraits fitness_traits;
|
||||
|
||||
eoMOFitness() : std::vector<double>(FitnessTraits::nObjectives()), worthValid(false) { reset(); }
|
||||
|
||||
explicit eoMOFitness(double def) : std::vector<double>(FitnessTraits::nObjectives(),def), worthValid(false) {}
|
||||
|
||||
// Ctr from a std::vector<double>
|
||||
explicit eoMOFitness(std::vector<double> & _v) : std::vector<double>(_v), worthValid(false) {}
|
||||
|
||||
virtual ~eoMOFitness() {} // in case someone wants to subclass
|
||||
eoMOFitness(const eoMOFitness<FitnessTraits>& org) { operator=(org); }
|
||||
|
||||
eoMOFitness<FitnessTraits>& operator=(const eoMOFitness<FitnessTraits>& org) {
|
||||
|
||||
std::vector<double>::operator=(org);
|
||||
worth = org.worth;
|
||||
worthValid = org.worthValid;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
||||
for (unsigned i = 0; i < size(); ++i) {
|
||||
this->operator[](i) = dominance::worst_possible_value<FitnessTraits>(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Make the objective 'feasible' by setting it to the best possible value
|
||||
void setFeasible(unsigned objective) { this->operator[](objective) = dominance::best_possible_value<FitnessTraits>(objective); }
|
||||
|
||||
void setWorth(double worth_) {
|
||||
worth = worth_;
|
||||
worthValid = true;
|
||||
}
|
||||
|
||||
double getWorth() const {
|
||||
if (!worthValid) {
|
||||
throw std::runtime_error("invalid worth");
|
||||
}
|
||||
return worth;
|
||||
}
|
||||
|
||||
bool validWorth() const { return worthValid; }
|
||||
void invalidateWorth() { worthValid = false; }
|
||||
|
||||
/// Check on dominance: returns 0 if non-dominated, 1 if this dominates other, -1 if other dominates this
|
||||
int check_dominance(const eoMOFitness<FitnessTraits>& _other) const
|
||||
{
|
||||
dominance::dominance_result dom = dominance::check<FitnessTraits>(*this, _other);
|
||||
|
||||
return dom == dominance::first? 1 : (dom == dominance::second? -1 : 0);
|
||||
}
|
||||
|
||||
/// normalized fitness: all maximizing, removed the irrelevant ones
|
||||
std::vector<double> normalized() const {
|
||||
std::vector<double> f;
|
||||
|
||||
for (unsigned j = 0; j < FitnessTraits::nObjectives(); ++j) {
|
||||
if (FitnessTraits::direction(j) != 0) {
|
||||
f.push_back( FitnessTraits::direction(j) * this->operator[](j));
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/// returns true if this dominates other
|
||||
bool dominates(const eoMOFitness<FitnessTraits>& _other) const
|
||||
{
|
||||
return check_dominance(_other) == 1;
|
||||
}
|
||||
|
||||
/// 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.worthValid << ' ' << 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.worthValid >> fitness.worth;
|
||||
return is;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace dominance {
|
||||
template <class FitnessTraits>
|
||||
inline dominance_result check(const eoMOFitness<FitnessTraits>& p1, const eoMOFitness<FitnessTraits>& p2) {
|
||||
return check<FitnessTraits>(p1, p2, FitnessTraits::tol());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include <limits>
|
||||
#include <moo/eoNSGA_II_Eval.h>
|
||||
|
||||
namespace nsga2 {
|
||||
|
||||
using namespace std;
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<double>& worths) {
|
||||
|
||||
unsigned nObjectives = front[0].fitness.size(); //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 (unsigned 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 (unsigned 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 (unsigned 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.size(); ++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;
|
||||
|
||||
worths[idx] = rank + dist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef eoNSGA_II_Eval_h
|
||||
#define eoNSGA_II_Eval_h
|
||||
|
||||
#include <moo/eoFrontSorter.h>
|
||||
#include <moo/eoMOEval.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
|
||||
|
||||
*/
|
||||
|
||||
namespace nsga2 {
|
||||
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<double>& worths);
|
||||
}
|
||||
|
||||
template <class EOT>
|
||||
class eoNSGA_II_Eval : public eoMOEval<EOT>
|
||||
{
|
||||
public:
|
||||
|
||||
eoNSGA_II_Eval(eoEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
|
||||
eoNSGA_II_Eval(eoPopEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
|
||||
|
||||
virtual void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
|
||||
this->eval(parents, offspring);
|
||||
|
||||
std::vector<EOT*> pop;
|
||||
pop.reserve(parents.size() + offspring.size());
|
||||
for (unsigned i = 0; i < parents.size(); ++i) pop.push_back(&parents[i]);
|
||||
for (unsigned i = 0; i < offspring.size(); ++i) pop.push_back(&offspring[i]);
|
||||
|
||||
typename eoFrontSorter<EOT>::front_t front = sorter(pop);
|
||||
|
||||
// calculate worths
|
||||
std::vector<double> worths(pop.size());
|
||||
for (unsigned i = 0; i < front.size(); ++i) {
|
||||
nsga2::assign_worths(front[i], front.size() - i, worths);
|
||||
}
|
||||
|
||||
// set worths
|
||||
for (unsigned i = 0; i < pop.size(); ++i) {
|
||||
pop[i]->fitnessReference().setWorth( worths[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
eoFrontSorter<EOT> sorter;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
|
||||
#include <limits>
|
||||
#include <moo/eoNSGA_IIa_Eval.h>
|
||||
|
||||
namespace nsga2a {
|
||||
|
||||
double calc_distance(const std::vector<double>& f1, const std::vector<double>& f2) {
|
||||
double dist = 0;
|
||||
for (unsigned i = 0; i < f1.size(); ++i) {
|
||||
double d = (f1[i] - f2[i]);
|
||||
dist += pow(fabs(d), 1./2);
|
||||
//dist += pow(fabs(d), 2.0);
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
unsigned assign_worths(std::vector<detail::FitnessInfo> front, unsigned rank, std::vector<double>& worths) {
|
||||
|
||||
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 and store in boundaries
|
||||
std::vector<detail::FitnessInfo> boundaries;
|
||||
for (unsigned i = 0; i < processed.size(); ++i) {
|
||||
|
||||
worths[ front[ processed[i] ].index] = rank;
|
||||
|
||||
//cout << "Boundary " << i << ' ' << front[processed[i]].index << ' ' << parents[ front[ processed[i] ].index]->fitness() << endl;
|
||||
|
||||
boundaries.push_back( front[ processed[i] ] );
|
||||
}
|
||||
rank--;
|
||||
|
||||
// clean up processed (make unique)
|
||||
sort(processed.begin(), processed.end()); // swap out last first
|
||||
for (unsigned i = 1; i < processed.size(); ++i) {
|
||||
if (processed[i] == processed[i-1]) {
|
||||
std::swap(processed[i], processed.back());
|
||||
processed.pop_back();
|
||||
--i;
|
||||
}
|
||||
}
|
||||
// remove boundaries from front
|
||||
while (processed.size()) {
|
||||
unsigned idx = processed.back();
|
||||
//std::cout << idx << ' ' ;
|
||||
processed.pop_back();
|
||||
std::swap(front.back(), front[idx]);
|
||||
front.pop_back();
|
||||
}
|
||||
//std::cout << std::endl;
|
||||
|
||||
// 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 < boundaries.size(); ++k) {
|
||||
double d = calc_distance( front[i].fitness, boundaries[k].fitness);
|
||||
if (d < distances[i]) {
|
||||
distances[i] = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (distances[i] > distances[selected]) {
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (!front.empty()) {
|
||||
|
||||
detail::FitnessInfo last = front[selected];
|
||||
|
||||
std::swap(front[selected], front.back());
|
||||
front.pop_back();
|
||||
|
||||
std::swap(distances[selected], distances.back());
|
||||
distances.pop_back();
|
||||
|
||||
// set worth
|
||||
worths[last.index] = rank--;
|
||||
|
||||
if (front.empty()) break;
|
||||
|
||||
selected = 0;
|
||||
|
||||
for (unsigned i = 0; i < front.size(); ++i) {
|
||||
double d = calc_distance(front[i].fitness, last.fitness);
|
||||
|
||||
if (d < distances[i]) {
|
||||
distances[i] = d;
|
||||
}
|
||||
|
||||
if (distances[i] >= distances[selected]) {
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rank;
|
||||
}
|
||||
|
||||
unsigned assign_worths2(std::vector<detail::FitnessInfo> front, unsigned rank, std::vector<double>& worths) {
|
||||
|
||||
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 and store in boundaries
|
||||
std::vector<detail::FitnessInfo> boundaries;
|
||||
for (unsigned i = 0; i < processed.size(); ++i) {
|
||||
|
||||
worths[ front[ processed[i] ].index] = rank;
|
||||
|
||||
//cout << "Boundary " << i << ' ' << front[processed[i]].index << ' ' << parents[ front[ processed[i] ].index]->fitness() << endl;
|
||||
|
||||
boundaries.push_back( front[ processed[i] ] );
|
||||
}
|
||||
rank--;
|
||||
|
||||
// clean up processed (make unique)
|
||||
sort(processed.begin(), processed.end()); // swap out last first
|
||||
for (unsigned i = 1; i < processed.size(); ++i) {
|
||||
if (processed[i] == processed[i-1]) {
|
||||
std::swap(processed[i], processed.back());
|
||||
processed.pop_back();
|
||||
--i;
|
||||
}
|
||||
}
|
||||
// remove boundaries from front
|
||||
while (processed.size()) {
|
||||
unsigned idx = processed.back();
|
||||
//std::cout << idx << ' ' ;
|
||||
processed.pop_back();
|
||||
std::swap(front.back(), front[idx]);
|
||||
front.pop_back();
|
||||
}
|
||||
//std::cout << std::endl;
|
||||
|
||||
// calculate distances
|
||||
std::vector< std::vector<double> > distances(front.size(), std::vector<double>(nDim, std::numeric_limits<double>::infinity()));
|
||||
|
||||
double bestsum = 0;
|
||||
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 < boundaries.size(); ++k) {
|
||||
for (unsigned dim = 0; dim < nDim; ++dim) {
|
||||
double d = front[i].fitness[dim] - boundaries[k].fitness[dim];
|
||||
if (d > 0 && d < distances[i][dim]) {
|
||||
distances[i][dim] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double sum = 0;
|
||||
for (unsigned dim = 0; dim < nDim; ++dim) sum += distances[i][dim];
|
||||
|
||||
if (sum > bestsum) {
|
||||
selected = i;
|
||||
bestsum = sum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (!front.empty()) {
|
||||
|
||||
detail::FitnessInfo last = front[selected];
|
||||
|
||||
std::swap(front[selected], front.back());
|
||||
front.pop_back();
|
||||
|
||||
std::swap(distances[selected], distances.back());
|
||||
distances.pop_back();
|
||||
|
||||
// set worth
|
||||
worths[last.index] = rank--;
|
||||
|
||||
if (front.empty()) break;
|
||||
|
||||
selected = 0;
|
||||
bestsum = 0;
|
||||
|
||||
for (unsigned i = 0; i < front.size(); ++i) {
|
||||
double sum = 0;
|
||||
for (unsigned dim = 0; dim < nDim; ++dim) {
|
||||
double d = front[i].fitness[dim] - last.fitness[dim];
|
||||
if (d > 0 && d < distances[i][dim]) {
|
||||
distances[i][dim] = d;
|
||||
}
|
||||
|
||||
sum += distances[i][dim];
|
||||
}
|
||||
|
||||
if (sum > bestsum) {
|
||||
selected = i;
|
||||
bestsum = sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rank;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#ifndef eoNSGA_IIa_Eval_h
|
||||
#define eoNSGA_IIa_Eval_h
|
||||
|
||||
#include <moo/eoFrontSorter.h>
|
||||
#include <moo/eoMOEval.h>
|
||||
#include <cassert>
|
||||
|
||||
/** @brief Fast Elitist Non-Dominant Sorting Genetic Algorithm
|
||||
|
||||
Variant of the NSGA-II, where the ranking is based on a top-down distance based mechanism ( O(n^2)! )
|
||||
|
||||
*/
|
||||
|
||||
namespace nsga2a {
|
||||
extern unsigned assign_worths(std::vector<detail::FitnessInfo> front, unsigned rank, std::vector<double>& worths);
|
||||
}
|
||||
|
||||
template <class EOT>
|
||||
class eoNSGA_IIa_Eval : public eoMOEval<EOT>
|
||||
{
|
||||
public:
|
||||
|
||||
eoNSGA_IIa_Eval(eoEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
|
||||
eoNSGA_IIa_Eval(eoPopEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
|
||||
|
||||
|
||||
virtual void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
|
||||
eval(parents, offspring);
|
||||
|
||||
std::vector<EOT*> pop;
|
||||
pop.reserve(parents.size() + offspring.size());
|
||||
for (unsigned i = 0; i < parents.size(); ++i) pop.push_back(&parents[i]);
|
||||
for (unsigned i = 0; i < offspring.size(); ++i) {
|
||||
pop.push_back(&offspring[i]);
|
||||
}
|
||||
|
||||
typename eoFrontSorter<EOT>::front_t front = sorter(pop);
|
||||
|
||||
std::vector<double> worths(pop.size());
|
||||
unsigned rank = pop.size();
|
||||
for (unsigned i = 0; i < front.size(); ++i) {
|
||||
rank = nsga2a::assign_worths(front[i], rank, worths);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < worths.size(); ++i) {
|
||||
typename EOT::Fitness f = pop[i]->fitness();
|
||||
f.setWorth(worths[i]);
|
||||
pop[i]->fitness(f);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
eoFrontSorter<EOT> sorter;
|
||||
|
||||
// implementation
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#ifndef __eoNSGA_I_Eval_h_
|
||||
#define __eoNSGA_I_Eval_h_
|
||||
|
||||
#include <moo/eoFrontSorter.h>
|
||||
#include <moo/eoMOEval.h>
|
||||
|
||||
/**
|
||||
The original Non Dominated Sorting algorithm from Srinivas and Deb
|
||||
*/
|
||||
template <class EOT>
|
||||
class eoNSGA_I_Eval : public eoMOEval<EOT>
|
||||
{
|
||||
public :
|
||||
eoNSGA_I_Eval(double nicheWidth, eoEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval), nicheSize(nicheWidth) {}
|
||||
eoNSGA_I_Eval(double nicheWidth, eoPopEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval), nicheSize(nicheWidth) {}
|
||||
|
||||
virtual void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
|
||||
eval(parents, offspring);
|
||||
|
||||
std::vector<EOT*> pop;
|
||||
pop.reserve(parents.size() + offspring.size());
|
||||
for (unsigned i = 0; i < parents.size(); ++i) pop.push_back(&parents[i]);
|
||||
for (unsigned i = 0; i < offspring.size(); ++i) pop.push_back(&offspring[i]);
|
||||
|
||||
typename eoFrontSorter<EOT>::front_t front = sorter(pop);
|
||||
|
||||
for (unsigned i = 0; i < front.size(); ++i) {
|
||||
assign_worths(front[i], front.size() - i, pop);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<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
|
||||
|
||||
|
||||
|
|
@ -1,236 +0,0 @@
|
|||
|
||||
#include <eo>
|
||||
|
||||
#include <moo/eoEpsMOEA.h>
|
||||
#include <utils/eoFuncPtrStat.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MinimizingFitnessTraits
|
||||
{
|
||||
public :
|
||||
static unsigned nObjectives() { return 2; }
|
||||
static double direction(unsigned) { return -1; }
|
||||
static double tol() { return 1e-9; }
|
||||
|
||||
static vector<double> eps;
|
||||
};
|
||||
|
||||
vector<double> MinimizingFitnessTraits::eps(2, 0.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 Cross : public eoBinOp<eoDouble> {
|
||||
|
||||
bool operator()(eoDouble& _eo, const eoDouble& eo2)
|
||||
{
|
||||
for (unsigned i = 0; i < chromsize; ++i)
|
||||
{
|
||||
if (rng.flip(0.5)) {
|
||||
_eo.value[i] = eo2.value[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Eval : public eoEvalFunc<eoDouble>
|
||||
{
|
||||
void operator()(eoDouble& _eo)
|
||||
{
|
||||
vector<double> x(_eo.value, _eo.value + chromsize);
|
||||
fitness_type f(0.0);
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
template <class EOT>
|
||||
unsigned get_size(const eoPop<EOT>& pop) {
|
||||
return pop.size();
|
||||
}
|
||||
|
||||
template <class EOT>
|
||||
unsigned counter(const eoPop<EOT>& pop) {
|
||||
static unsigned c = 0;
|
||||
return c++;
|
||||
}
|
||||
|
||||
// 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;
|
||||
Cross cross;
|
||||
|
||||
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();
|
||||
|
||||
eoPop<eoDouble> pop(pop_size, init);
|
||||
|
||||
// binary tournament selection
|
||||
eoDetTournamentSelect<eoDouble> select;
|
||||
|
||||
// One general operator
|
||||
eoProportionalOp<eoDouble> opsel;
|
||||
opsel.add(mutate, 1.0);
|
||||
opsel.add(cross, 1.0);
|
||||
|
||||
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);
|
||||
|
||||
eoGnuplot1DMonitor monitor("sizemon");
|
||||
|
||||
cp.add(monitor);
|
||||
|
||||
eoFuncPtrStat<eoDouble, unsigned> size(get_size<eoDouble>);
|
||||
eoFuncPtrStat<eoDouble, unsigned> counterStat(counter<eoDouble>);
|
||||
|
||||
monitor.add(counterStat);
|
||||
monitor.add(size);
|
||||
|
||||
cp.add(size);
|
||||
cp.add(counterStat);
|
||||
|
||||
// the algo
|
||||
eoEpsMOEA<eoDouble> ea(cp, eval, opsel, MinimizingFitnessTraits::eps );
|
||||
|
||||
if (parser.userNeedsHelp())
|
||||
{
|
||||
parser.printHelp(std::cout);
|
||||
return;
|
||||
}
|
||||
|
||||
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:
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <eo>
|
||||
|
||||
#include <moo/eoMOFitness.h>
|
||||
#include <moo/eoNSGA_I_Eval.h>
|
||||
#include <moo/eoNSGA_II_Eval.h>
|
||||
#include <moo/eoNSGA_IIa_Eval.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MinimizingFitnessTraits
|
||||
{
|
||||
public :
|
||||
static unsigned nObjectives() { return 2; }
|
||||
static double direction(unsigned) { return -1; }
|
||||
static double tol() { return 1e-9; }
|
||||
};
|
||||
|
||||
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 Cross : public eoBinOp<eoDouble> {
|
||||
|
||||
bool operator()(eoDouble& _eo, const eoDouble& eo2)
|
||||
{
|
||||
for (unsigned i = 0; i < chromsize; ++i)
|
||||
{
|
||||
if (rng.flip(0.5)) {
|
||||
_eo.value[i] = eo2.value[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Eval : public eoEvalFunc<eoDouble>
|
||||
{
|
||||
void operator()(eoDouble& _eo)
|
||||
{
|
||||
vector<double> x(_eo.value, _eo.value + chromsize);
|
||||
fitness_type f(0.0);
|
||||
|
||||
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 simple_eval;
|
||||
Mutate mutate;
|
||||
Cross cross;
|
||||
|
||||
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();
|
||||
bool use_nsga2a = parser.createParam(false, "nsga2a", "Use nsga 2a").value();
|
||||
|
||||
eoPop<eoDouble> pop(pop_size, init);
|
||||
|
||||
// binary tournament selection
|
||||
eoDetTournamentSelect<eoDouble> select;
|
||||
|
||||
// One general operator
|
||||
eoProportionalOp<eoDouble> opsel;
|
||||
opsel.add(mutate, 1.0);
|
||||
opsel.add(cross, 1.0);
|
||||
|
||||
// the breeder
|
||||
eoGeneralBreeder<eoDouble> breeder(select, opsel);
|
||||
|
||||
// replacement
|
||||
eoNSGA_IIa_Eval<eoDouble> nsga2a(simple_eval);
|
||||
eoNSGA_II_Eval<eoDouble> nsga2(simple_eval);
|
||||
eoNSGA_I_Eval<eoDouble> nsga1(0.1, simple_eval);
|
||||
eoMOEval<eoDouble>& eval = use_nsga1 ? static_cast<eoMOEval<eoDouble>&>(nsga1) : (use_nsga2a? static_cast<eoMOEval<eoDouble>&>(nsga2a) : static_cast<eoMOEval<eoDouble>&>(nsga2));
|
||||
|
||||
eoPlusReplacement<eoDouble> replace;
|
||||
|
||||
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);
|
||||
|
||||
#ifdef HAVE_GNUPLOT
|
||||
eoGnuplot1DSnapshot snapshot("pareto");
|
||||
//snapshot.with(eoGnuplot::Points(3));
|
||||
|
||||
cp.add(snapshot);
|
||||
|
||||
snapshot.add(fitness0);
|
||||
snapshot.add(fitness1);
|
||||
#endif
|
||||
|
||||
// the algo
|
||||
eoEasyEA<eoDouble> ea(cp, eval, breeder, replace);
|
||||
|
||||
if (parser.userNeedsHelp())
|
||||
{
|
||||
parser.printHelp(std::cout);
|
||||
return;
|
||||
}
|
||||
|
||||
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:
|
||||
Loading…
Add table
Add a link
Reference in a new issue