From 9bbac485f99064309cb31c21f963d12a47d966db Mon Sep 17 00:00:00 2001 From: maartenkeijzer Date: Tue, 20 Mar 2001 14:34:07 +0000 Subject: [PATCH] Updated eoStat.h to also "do the right thing" when confronted with pareto style fitness --- eo/src/utils/eoMOFitnessStat.h | 4 + eo/src/utils/eoStat.h | 145 +++++++++++++++++++++++++++++---- 2 files changed, 134 insertions(+), 15 deletions(-) diff --git a/eo/src/utils/eoMOFitnessStat.h b/eo/src/utils/eoMOFitnessStat.h index 2c6b105e..27b2d704 100644 --- a/eo/src/utils/eoMOFitnessStat.h +++ b/eo/src/utils/eoMOFitnessStat.h @@ -64,10 +64,14 @@ public : virtual void operator()(const vector& _popPters) { value().resize(_popPters.size()); + for (unsigned i=0; i<_popPters.size(); i++) + { value()[i] = _popPters[i]->fitness()[objective]; + } } private: unsigned int objective; // The objective we're storing + }; #endif diff --git a/eo/src/utils/eoStat.h b/eo/src/utils/eoStat.h index 7d06d833..5877ab54 100644 --- a/eo/src/utils/eoStat.h +++ b/eo/src/utils/eoStat.h @@ -3,7 +3,7 @@ //----------------------------------------------------------------------------- // eoStat.h // (c) Marc Schoenauer, Maarten Keijzer and GeNeura Team, 2000 -/* +/* 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 @@ -30,6 +30,8 @@ #include #include #include +#include // accumulate +#include /** Base class for all statistics that need to be calculated @@ -43,7 +45,7 @@ public: }; /** - The actual class that will be used as base for all statistics + The actual class that will be used as base for all statistics that need to be calculated over the (unsorted) population It is an eoStatBase AND an eoValueParam so it can be used in Monitors. */ @@ -65,7 +67,7 @@ public: }; /** - The actual class that will be used as base for all statistics + The actual class that will be used as base for all statistics that need to be calculated over the sorted population It's an eoSortedStatBase AND an eoValueParam so it can be used in Monitors. */ @@ -76,16 +78,16 @@ public : eoSortedStat(ParamType _value, std::string _desc) : eoValueParam(_value, _desc) {} }; -#include - /** - Average fitness of a population, fitness needs to be scalar. + Average fitness of a population, fitness can be a double, eoMinimizingFitness, eoMaximizingFitness or eoParetoFitness. + In the case of pareto optimization it will calculate the average of each objective. */ template -class eoAverageStat : public eoStat +class eoAverageStat : public eoStat { public : - eoAverageStat(std::string _description = "Average Fitness") : eoStat(0.0, _description) {} + typedef typename EOT::Fitness fitness_type; + eoAverageStat(std::string _description = "Average Fitness") : eoStat(fitness_type(), _description) {} static double sumFitness(double _sum, const EOT& _eot) { @@ -96,11 +98,36 @@ public : eoAverageStat(double _value, std::string _desc) : eoStat(_value, _desc) {} virtual void operator()(const eoPop& _pop) + { + doit(_pop, typename EOT::Fitness()); // specializations for scalar and vector + } +private : + + template + void doit(const eoPop& _pop, eoParetoFitness) + { + value().clear(); + value().resize(_pop[0].fitness().size(), 0.0); + + for (unsigned o = 0; o < value().size(); ++o) + { + for (unsigned i = 0; i < _pop.size(); ++i) + { + value()[o] += _pop[i].fitness()[o]; + } + + value()[o] /= _pop.size(); + } + } + + template + void doit(const eoPop& _pop, T) { double v = std::accumulate(_pop.begin(), _pop.end(), 0.0, eoAverageStat::sumFitness); value() = v / _pop.size(); } + }; /** @@ -125,7 +152,7 @@ public : virtual void operator()(const eoPop& _pop) { SquarePair result = std::accumulate(_pop.begin(), _pop.end(), std::make_pair(0.0, 0.0), eoSecondMomentStats::sumOfSquares); - + double n = _pop.size(); value().first = result.first / n; // average value().second = sqrt( (result.second - n * value().first * value().first) / (n - 1.0)); // stdev @@ -148,15 +175,58 @@ public : if (which > _pop.size()) throw logic_error("fitness requested of element outside of pop"); - value() = _pop[which]->fitness(); + doit(_pop, Fitness()); } private : + + struct CmpFitness + { + CmpFitness(unsigned _which, bool _maxim) : which(_which), maxim(_maxim) {} + + bool operator()(const EOT* a, const EOT* b) + { + if (maxim) + return a->fitness()[which] > b->fitness()[which]; + + return a->fitness()[which] < b->fitness()[which]; + } + + unsigned which; + bool maxim; + }; + + template + void doit(const eoPop& _pop, eoParetoFitness) + { + typedef typename EOT::Fitness::fitness_traits traits; + + value().resize(traits::nObjectives()); + + // copy of pointers, what the heck + vector tmp_pop = _pop; + + for (unsigned o = 0; o < value().size(); ++o) + { + vector::iterator nth = tmp_pop.begin() + which; + std::nth_element(tmp_pop.begin(), nth, tmp_pop.end(), CmpFitness(o, traits::maximizing(o))); + value()[o] = (*nth)->fitness()[o]; + } + } + + // for everything else + template + void doit(const vector& _pop, T) + { + value() = _pop[which]->fitness(); + } + + unsigned which; }; /* Actually, you shouldn't need to sort the population to get the best fitness - MS - 17/11/00 + MS - 17/11/00 template class eoBestFitnessStat : public eoStat @@ -164,7 +234,7 @@ class eoBestFitnessStat : public eoStat public : typedef typename EOT::Fitness Fitness; - eoBestFitnessStat(std::string _description = "Best Fitness") : + eoBestFitnessStat(std::string _description = "Best Fitness") : eoStat(Fitness(), _description) {} virtual void operator()(const eoPop& _pop) @@ -179,12 +249,57 @@ public : Best fitness in the population */ template -class eoBestFitnessStat : public eoNthElementFitnessStat +class eoBestFitnessStat : public eoStat { public : typedef typename EOT::Fitness Fitness; - - eoBestFitnessStat(std::string _description = "Best ") : eoNthElementFitnessStat(0, _description) {} + + eoBestFitnessStat(std::string _description = "Best ") : eoStat(typename EOT::Fitness(), _description) {} + + void operator()(const eoPop& _pop) + { + doit(_pop, typename EOT::Fitness()); + } + +private : + + struct CmpFitness + { + CmpFitness(unsigned _which, bool _maxim) : which(_which), maxim(_maxim) {} + + bool operator()(const EOT& a, const EOT& b) + { + if (maxim) + return a.fitness()[which] < b.fitness()[which]; + + return a.fitness()[which] > b.fitness()[which]; + } + + unsigned which; + bool maxim; + }; + + + template + void doit(const eoPop& _pop, eoParetoFitness) + { + typedef typename EOT::Fitness::fitness_traits traits; + value().resize(traits::nObjectives()); + + for (unsigned o = 0; o < traits::nObjectives(); ++o) + { + eoPop::const_iterator it = max_element(_pop.begin(), _pop.end(), CmpFitness(o, traits::maximizing(o))); + value()[o] = it->fitness()[o]; + } + } + + // default + template + void doit(const eoPop& _pop, T) + { // find the largest elements + value() = _pop.best_element().fitness(); + } + }; template