Refactoring
This commit is contained in:
parent
7e76e6e9c2
commit
a5261fec51
5 changed files with 384 additions and 0 deletions
|
|
@ -79,6 +79,23 @@ class eoFrontSorter : public eoUF< const eoPop<EOT>&, const std::vector< std::ve
|
|||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
26
eo/src/moo/eoMOEval.h
Normal file
26
eo/src/moo/eoMOEval.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#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 :
|
||||
|
||||
eoPopEvalFunc<EOT>& pop_eval;
|
||||
eoPopLoopEval<EOT> default_loop;
|
||||
class eoDummyEval : public eoEvalFunc<EOT> {public: void operator()(EOT &) {} } dummy_eval;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
121
eo/src/moo/eoNSGA_II_Eval.h
Normal file
121
eo/src/moo/eoNSGA_II_Eval.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#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
|
||||
|
||||
*/
|
||||
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) {}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<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
|
||||
147
eo/src/moo/eoNSGA_IIa_Eval.h
Normal file
147
eo/src/moo/eoNSGA_IIa_Eval.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#ifndef eoNSGA_IIa_Eval_h
|
||||
#define eoNSGA_IIa_Eval_h
|
||||
|
||||
#include <moo/eoFrontSorter.h>
|
||||
#include <moo/eoMOEval.h>
|
||||
|
||||
/** @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)! )
|
||||
|
||||
*/
|
||||
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) {}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
unsigned rank = parents.size();
|
||||
for (unsigned i = 0; i < front.size(); ++i) {
|
||||
rank = assign_worths(front[i], rank, pop);
|
||||
}
|
||||
}
|
||||
|
||||
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, std::vector<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
|
||||
73
eo/src/moo/eoNSGA_I_Eval.h
Normal file
73
eo/src/moo/eoNSGA_I_Eval.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#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) {}
|
||||
|
||||
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
|
||||
|
||||
|
||||
Reference in a new issue