From a5261fec51de7b410204eadfa60dc343bb1b1cd3 Mon Sep 17 00:00:00 2001 From: maartenkeijzer Date: Fri, 31 Aug 2007 13:27:40 +0000 Subject: [PATCH] Refactoring --- eo/src/moo/eoFrontSorter.h | 17 ++++ eo/src/moo/eoMOEval.h | 26 +++++++ eo/src/moo/eoNSGA_II_Eval.h | 121 ++++++++++++++++++++++++++++ eo/src/moo/eoNSGA_IIa_Eval.h | 147 +++++++++++++++++++++++++++++++++++ eo/src/moo/eoNSGA_I_Eval.h | 73 +++++++++++++++++ 5 files changed, 384 insertions(+) create mode 100644 eo/src/moo/eoMOEval.h create mode 100644 eo/src/moo/eoNSGA_II_Eval.h create mode 100644 eo/src/moo/eoNSGA_IIa_Eval.h create mode 100644 eo/src/moo/eoNSGA_I_Eval.h diff --git a/eo/src/moo/eoFrontSorter.h b/eo/src/moo/eoFrontSorter.h index d96a3e90..60a4c1e6 100644 --- a/eo/src/moo/eoFrontSorter.h +++ b/eo/src/moo/eoFrontSorter.h @@ -79,6 +79,23 @@ class eoFrontSorter : public eoUF< const eoPop&, const std::vector< std::ve return fronts; } + + const std::vector >& operator()(const std::vector& _pop) + { + fitness.resize(_pop.size()); + for (unsigned i = 0; i < _pop.size(); ++i) { + std::vector 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; + } }; diff --git a/eo/src/moo/eoMOEval.h b/eo/src/moo/eoMOEval.h new file mode 100644 index 00000000..ba3a0f66 --- /dev/null +++ b/eo/src/moo/eoMOEval.h @@ -0,0 +1,26 @@ +#ifndef eoMOEval_h +#define eoMOEval_h + +#include + +template +class eoMOEval : public eoPopEvalFunc { + + protected: + eoMOEval(eoEvalFunc& eval) : default_loop(eval), pop_eval(default_loop) {} + eoMOEval(eoPopEvalFunc& ev) : default_loop(dummy_eval), pop_eval(ev) {} + + void eval(eoPop& parents, eoPop& offspring) { + pop_eval(parents, offspring); + } + + private : + + eoPopEvalFunc& pop_eval; + eoPopLoopEval default_loop; + class eoDummyEval : public eoEvalFunc {public: void operator()(EOT &) {} } dummy_eval; + +}; + + +#endif diff --git a/eo/src/moo/eoNSGA_II_Eval.h b/eo/src/moo/eoNSGA_II_Eval.h new file mode 100644 index 00000000..c3db1970 --- /dev/null +++ b/eo/src/moo/eoNSGA_II_Eval.h @@ -0,0 +1,121 @@ +#ifndef eoNSGA_II_Eval_h +#define eoNSGA_II_Eval_h + +#include +#include + +/** @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 eoNSGA_II_Eval : public eoMOEval +{ + public: + + eoNSGA_II_Eval(eoEvalFunc& eval) : eoMOEval(eval) {} + eoNSGA_II_Eval(eoPopEvalFunc& eval) : eoMOEval(eval) {} + + void operator()(eoPop& parents, eoPop& offspring) { + eval(parents, offspring); + + std::vector 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::front_t front = sorter(pop); + + for (unsigned i = 0; i < front.size(); ++i) { + assign_worths(front[i], front.size() - i, pop); + } + } + + + + + eoFrontSorter sorter; + + private: + typedef std::pair 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& front, unsigned rank, std::vector& parents) { + + typedef typename EOT::Fitness::fitness_traits traits; + unsigned i; + + unsigned nObjectives = traits::nObjectives(); //_pop[_cf[0]].fitness().size(); + + std::vector niche_distance(front.size()); + + for (unsigned o = 0; o < nObjectives; ++o) + { + + std::vector > 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 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::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::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::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 diff --git a/eo/src/moo/eoNSGA_IIa_Eval.h b/eo/src/moo/eoNSGA_IIa_Eval.h new file mode 100644 index 00000000..f7e71b37 --- /dev/null +++ b/eo/src/moo/eoNSGA_IIa_Eval.h @@ -0,0 +1,147 @@ +#ifndef eoNSGA_IIa_Eval_h +#define eoNSGA_IIa_Eval_h + +#include +#include + +/** @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 eoNSGA_IIa_Eval : public eoMOEval +{ + public: + + eoNSGA_IIa_Eval(eoEvalFunc& eval) : eoMOEval(eval) {} + eoNSGA_IIa_Eval(eoPopEvalFunc& eval) : eoMOEval(eval) {} + + + void operator()(eoPop& parents, eoPop& offspring) { + eval(parents, offspring); + + std::vector 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::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 sorter; + + double distance(const std::vector& f1, const std::vector& f2, const std::vector& 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& front, unsigned rank, std::vector& parents) { + + unsigned nDim = front[0].fitness.size(); + + // find boundary points + std::vector 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 mins(nDim, std::numeric_limits::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 range(nDim); + for (unsigned dim = 0; dim < nDim; ++dim) { + range[dim] = front[ processed[dim] ].fitness[dim] - mins[dim]; + } + + // calculate distances + std::vector distances(front.size(), std::numeric_limits::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 diff --git a/eo/src/moo/eoNSGA_I_Eval.h b/eo/src/moo/eoNSGA_I_Eval.h new file mode 100644 index 00000000..27733bd7 --- /dev/null +++ b/eo/src/moo/eoNSGA_I_Eval.h @@ -0,0 +1,73 @@ +#ifndef __eoNSGA_I_Eval_h_ +#define __eoNSGA_I_Eval_h_ + +#include +#include + +/** + The original Non Dominated Sorting algorithm from Srinivas and Deb +*/ +template +class eoNSGA_I_Eval : public eoMOEval +{ +public : + eoNSGA_I_Eval(double nicheWidth, eoEvalFunc& eval) : eoMOEval(eval), nicheSize(nicheWidth) {} + eoNSGA_I_Eval(double nicheWidth, eoPopEvalFunc& eval) : eoMOEval(eval), nicheSize(nicheWidth) {} + + void operator()(eoPop& parents, eoPop& offspring) { + eval(parents, offspring); + + std::vector 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::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& front, unsigned rank, std::vector& 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 sorter; +}; + +#endif + +