⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eondsorting.h

📁 这是linux下的进化计算的源代码。 === === === === === === === === === === === ===== check latest news at http:
💻 H
字号:
/** -*- 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 eoNDSorting_h#define eoNDSorting_h#include <EO.h>#include <algorithm>#include <eoPop.h>#include <eoPerf2Worth.h>#include <cassert>/**  Non dominated sorting, it *is a* std::vector of doubles, the integer part is the rank (to which front it belongs),  the fractional part the niching penalty or distance penalty or whatever penalty you want to squeeze into  the bits.*/template <class EOT>class eoNDSorting : public eoPerf2WorthCached<EOT, double>{  public :    using eoPerf2WorthCached<EOT, double>::value;      eoNDSorting(bool nasty_flag_ = false)          : nasty_declone_flag_that_only_is_implemented_for_two_objectives(nasty_flag_)        {}    eoNDSorting()        : nasty_declone_flag_that_only_is_implemented_for_two_objectives(false)        {}    /** Pure virtual function that calculates the 'distance' for each element in the current front        Implement to create your own nondominated sorting algorithm. The size of the returned std::vector        should be equal to the size of the current_front.    */    virtual std::vector<double> niche_penalty(const std::vector<unsigned>& current_front, const eoPop<EOT>& _pop) = 0;    void calculate_worths(const eoPop<EOT>& _pop)    {	// resize the worths beforehand	value().resize(_pop.size());	typedef typename EOT::Fitness::fitness_traits traits;	switch (traits::nObjectives())	{	    case 1:		{		    one_objective(_pop);		    return;		}	    case 2:		{		    two_objectives(_pop);		    return;		}	    default :		{		    m_objectives(_pop);		}	}    }private :    /** used in fast nondominated sorting	DummyEO is just a storage place for fitnesses and	to store the original index    */    class DummyEO : public EO<typename EOT::Fitness>    {      public: unsigned index;    };    void one_objective(const eoPop<EOT>& _pop)    {	unsigned i;	std::vector<DummyEO> tmp_pop;        tmp_pop.resize(_pop.size());        // copy pop to dummy population (only need the fitnesses)        for (i = 0; i < _pop.size(); ++i)        {          tmp_pop[i].fitness(_pop[i].fitness());          tmp_pop[i].index = i;        }	std::sort(tmp_pop.begin(), tmp_pop.end(), std::greater<DummyEO>());        for (i = 0; i < _pop.size(); ++i)        {          value()[tmp_pop[i].index] = _pop.size() - i; // set rank        }	// no point in calculcating niche penalty, as every distinct fitness value has a distinct rank    }    /**     * Optimization for two objectives. Makes the algorithm run in     * complexity O(n log n) where n is the population size     *     * This is the same complexity as for a single objective     * or truncation selection or sorting.     *     * It will perform a sort on the two objectives seperately,     * and from the information on the ranks of the individuals on     * these two objectives, the non-dominated sorting rank is determined.     * There are then three nlogn operations in place: one sort per objective,     * plus a binary search procedure to combine the information about the     * ranks.     *     * After that it is a simple exercise to calculate the distance     * penalty     */    void two_objectives(const eoPop<EOT>& _pop)    {		unsigned i;	typedef typename EOT::Fitness::fitness_traits traits;	assert(traits::nObjectives() == 2);	std::vector<unsigned> sort1(_pop.size()); // index into population sorted on first objective	for (i = 0; i < _pop.size(); ++i)	{	    sort1[i] = i;	}	std::sort(sort1.begin(), sort1.end(), Sorter(_pop));	// Ok, now the meat of the algorithm	unsigned last_front = 0;	double max1 = -1e+20;	for (i = 0; i < _pop.size(); ++i)	{	    max1 = std::max(max1, _pop[i].fitness()[1]);	}	max1 = max1 + 1.0; // add a bit to it so that it is a real upperbound	unsigned prev_front = 0;	std::vector<double> d;	d.resize(_pop.size(), max1); // initialize with the value max1 everywhere	std::vector<std::vector<unsigned> > fronts(_pop.size()); // to store indices into the front	for (i = 0; i < _pop.size(); ++i)	{	    unsigned index = sort1[i];	    // check for clones and delete them	    if (0 && i > 0)	    {		unsigned prev = sort1[i-1];		if ( _pop[index].fitness() == _pop[prev].fitness())		{ // it's a clone, give it the worst rank!		    if (nasty_declone_flag_that_only_is_implemented_for_two_objectives)			//declone			fronts.back().push_back(index);		    else // assign it the rank of the previous		    	fronts[prev_front].push_back(index);		    continue;		}	    }	    double value2 = _pop[index].fitness()[1];	    if (traits::maximizing(1))		value2 = max1 - value2;	    // perform binary search using std::upper_bound, a log n operation for each member	    std::vector<double>::iterator it =		std::upper_bound(d.begin(), d.begin() + last_front, value2);	    unsigned front = unsigned(it - d.begin());	    if (front == last_front) ++last_front;	    assert(it != d.end());	    *it = value2; //update d	    fronts[front].push_back(index); // add it to the front	    prev_front = front;	}	// ok, and finally the niche penalty	for (i = 0; i < fronts.size(); ++i)	{	    if (fronts[i].size() == 0) continue;	    // Now we have the indices to the current front in current_front, do the niching	    std::vector<double> niche_count = niche_penalty(fronts[i], _pop);	    // Check whether the derived class was nice	    if (niche_count.size() != fronts[i].size())	    {	      throw std::logic_error("eoNDSorting: niche and front should have the same size");	    }	    double max_niche = *std::max_element(niche_count.begin(), niche_count.end());	    for (unsigned j = 0; j < fronts[i].size(); ++j)	    {	      value()[fronts[i][j]] = i + niche_count[j] / (max_niche + 1.); // divide by max_niche + 1 to ensure that this front does not overlap with the next	    }	}	// invert ranks to obtain a 'bigger is better' score	rank_to_worth();    }    class Sorter    {	public:	    Sorter(const eoPop<EOT>& _pop) : pop(_pop) {}	    bool operator()(unsigned i, unsigned j) const	    {		typedef typename EOT::Fitness::fitness_traits traits;		double diff = pop[i].fitness()[0] - pop[j].fitness()[0];		if (fabs(diff) < traits::tol())		{		    diff = pop[i].fitness()[1] - pop[j].fitness()[1];		    if (fabs(diff) < traits::tol())			return false;		    if (traits::maximizing(1))			return diff > 0.;		    return diff < 0.;		}		if (traits::maximizing(0))		    return diff > 0.;		return diff < 0.;	    }	    const eoPop<EOT>& pop;    };    void m_objectives(const eoPop<EOT>& _pop)    {      unsigned i;      typedef typename EOT::Fitness::fitness_traits traits;      std::vector<std::vector<unsigned> > S(_pop.size()); // which individuals does guy i dominate      std::vector<unsigned> n(_pop.size(), 0); // how many individuals dominate guy i      unsigned j;      for (i = 0; i < _pop.size(); ++i)      {        for (j = 0; j < _pop.size(); ++j)        {          if (_pop[i].fitness().dominates(_pop[j].fitness()))          { // i dominates j            S[i].push_back(j); // add j to i's domination std::list            //n[j]++; // as i dominates j          }          else if (_pop[j].fitness().dominates(_pop[i].fitness()))          { // j dominates i, increment count for i, add i to the domination std::list of j            n[i]++;            //S[j].push_back(i);          }        }      }      std::vector<unsigned> current_front;      current_front.reserve(_pop.size());      // get the first front out      for (i = 0; i < _pop.size(); ++i)      {        if (n[i] == 0)        {          current_front.push_back(i);        }      }      std::vector<unsigned> next_front;      next_front.reserve(_pop.size());      unsigned front_index = 0; // which front are we processing      while (!current_front.empty())      {        // Now we have the indices to the current front in current_front, do the niching        std::vector<double> niche_count = niche_penalty(current_front, _pop);        // Check whether the derived class was nice        if (niche_count.size() != current_front.size())        {          throw std::logic_error("eoNDSorting: niche and front should have the same size");        }        double max_niche = *std::max_element(niche_count.begin(), niche_count.end());        for (i = 0; i < current_front.size(); ++i)        {          value()[current_front[i]] = front_index + niche_count[i] / (max_niche + 1.); // divide by max_niche + 1 to ensure that this front does not overlap with the next        }        // Calculate which individuals are in the next front;        for (i = 0; i < current_front.size(); ++i)        {          for (j = 0; j < S[current_front[i]].size(); ++j)          {            unsigned dominated_individual = S[current_front[i]][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            {              next_front.push_back(dominated_individual);            }          }        }        front_index++; // go to the next front        swap(current_front, next_front); // make the next front current        next_front.clear(); // clear it for the next iteration      }      rank_to_worth();    }    void rank_to_worth()    {      // now all that's left to do is to transform lower rank into higher worth      double max_fitness = *std::max_element(value().begin(), value().end());      // but make sure it's an integer upper bound, so that all ranks inside the highest integer are the front      max_fitness = ceil(max_fitness);      for (unsigned i = 0; i < value().size(); ++i)      {        value()[i] = max_fitness - value()[i];      }    }    public : bool nasty_declone_flag_that_only_is_implemented_for_two_objectives;};/**  The original Non Dominated Sorting algorithm from Srinivas and Deb*/template <class EOT>class eoNDSorting_I : public eoNDSorting<EOT>{public :  eoNDSorting_I(double _nicheSize, bool nasty_flag_ = false) : eoNDSorting<EOT>(nasty_flag_), nicheSize(_nicheSize) {}  std::vector<double> niche_penalty(const std::vector<unsigned>& current_front, const eoPop<EOT>& _pop)  {        std::vector<double> niche_count(current_front.size(), 0.);        for (unsigned i = 0; i < current_front.size(); ++i)        { // calculate whether the other points lie within the nice          for (unsigned j = 0; j < current_front.size(); ++j)          {            if (i == j)              continue;            double dist = 0.0;            for (unsigned k = 0; k < _pop[current_front[j]].fitness().size(); ++k)            {              double d = _pop[current_front[i]].fitness()[k] - _pop[current_front[j]].fitness()[k];              dist += d*d;            }            if (dist < nicheSize)            {              niche_count[i] += 1.0 - pow(dist / nicheSize,2.);            }          }        }        return niche_count;  }  private :  double nicheSize;};/** @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  The crowding distance is calculated as the sum of the distances to  the nearest neighbours. As we need to return the penalty value, we  have to invert that and invert it again in the base class, but such  is life, sigh*/template <class EOT>class eoNDSorting_II : public eoNDSorting<EOT>{  public:    eoNDSorting_II(bool nasty_flag_ = false) : eoNDSorting<EOT>(nasty_flag_) {}  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  std::vector<double> niche_penalty(const std::vector<unsigned>& _cf, const eoPop<EOT>& _pop)  {    typedef typename EOT::Fitness::fitness_traits traits;    unsigned i;    std::vector<double> niche_count(_cf.size(), 0.);    unsigned nObjectives = traits::nObjectives(); //_pop[_cf[0]].fitness().size();    for (unsigned o = 0; o < nObjectives; ++o)    {      std::vector<std::pair<double, unsigned> > performance(_cf.size());      for (i =0; i < _cf.size(); ++i)      {        performance[i].first = _pop[_cf[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(niche_count.size(), 0.0);      for (i = 1; i < _cf.size()-1; ++i)      { // and yet another level of indirection        nc[performance[i].second] = performance[i+1].first - performance[i-1].first;      }      double max_dist = *std::max_element(nc.begin(), nc.end());      // set boundary at max_dist + 1 (so it will get chosen over all the others      nc[performance[0].second] = max_dist + 1;      nc[performance.back().second] = max_dist + 1;      for (i = 0; i < nc.size(); ++i)      {        niche_count[i] = (max_dist + 1 - nc[i]);      }    }    return niche_count;  }};#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -