# eoStat.h

    00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
    00002
    00003 //-----------------------------------------------------------------------------
    00004 // eoStat.h
    00005 // (c) Marc Schoenauer, Maarten Keijzer and GeNeura Team, 2000
    00006 /*
    00007     This library is free software; you can redistribute it and/or
    00008     modify it under the terms of the GNU Lesser General Public
    00009     License as published by the Free Software Foundation; either
    00010     version 2 of the License, or (at your option) any later version.
    00011
    00012     This library is distributed in the hope that it will be useful,
    00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015     Lesser General Public License for more details.
    00016
    00017     You should have received a copy of the GNU Lesser General Public
    00018     License along with this library; if not, write to the Free Software
    00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00020
    00021     Contact: todos@geneura.ugr.es, http://geneura.ugr.es
    00022              Marc.Schoenauer@polytechnique.fr
    00023              mkeijzer@dhi.dk
    00024  */
    00025 //-----------------------------------------------------------------------------
    00026
    00027 #ifndef _eoStat_h
    00028 #define _eoStat_h
    00029
    00030 #include <numeric> // accumulate
    00031
    00032 #include <eoFunctor.h>
    00033 #include <utils/eoParam.h>
    00034 #include <eoPop.h>
    00035 #include <eoParetoFitness.h>
    00036
    00044 template <class EOT>
    00045 class eoStatBase : public eoUF<const eoPop<EOT>&, void>
    00046 {
    00047 public:
    00048   virtual void lastCall(const eoPop<EOT>&) {}
    00049   virtual std::string className(void) const { return "eoStatBase"; }
    00050 };
    00051
    00057 template <class EOT, class T>
    00058 class eoStat : public eoValueParam<T>, public eoStatBase<EOT>
    00059 {
    00060 public:
    00061
    00062     eoStat(T _value, std::string _description)
    00063         : eoValueParam<T>(_value, _description)
    00064         {}
    00065
    00066     virtual std::string className(void) const
    00067         { return "eoStat"; }
    00068 };
    00069
    00070
    00071
    00075 template <class EOT>
    00076 class eoSortedStatBase : public eoUF<const std::vector<const EOT*>&, void>
    00077 {
    00078 public:
    00079   virtual void lastCall(const std::vector<const EOT*>&) {}
    00080   virtual std::string className(void) const { return "eoSortedStatBase"; }
    00081 };
    00082
    00088 template <class EOT, class ParamType>
    00089 class eoSortedStat : public eoSortedStatBase<EOT>, public eoValueParam<ParamType>
    00090 {
    00091 public :
    00092   eoSortedStat(ParamType _value, std::string _desc) : eoValueParam<ParamType>(_value, _desc) {}
    00093   virtual std::string className(void) const { return "eoSortedStat"; }
    00094 };
    00095
    00105 #ifdef _MSC_VER
    00106 template <class EOT> class eoAverageStat : public eoStat<EOT, EOT::Fitness>
    00107 #else
    00108 template <class EOT> class eoAverageStat : public eoStat<EOT, typename EOT::Fitness>
    00109 #endif
    00110 {
    00111 public :
    00112
    00113     using eoStat<EOT, typename EOT::Fitness>::value;
    00114
    00115     typedef typename EOT::Fitness Fitness;
    00116
    00117     eoAverageStat(std::string _description = "Average Fitness")
    00118       : eoStat<EOT, Fitness>(Fitness(), _description) {}
    00119
    00120     static Fitness sumFitness(double _sum, const EOT& _eot){
    00121         _sum += _eot.fitness();
    00122         return _sum;
    00123     }
    00124
    00125     eoAverageStat(double _value, std::string _desc) : eoStat<EOT, double>(_value, _desc) {}
    00126
    00127     virtual void operator()(const eoPop<EOT>& _pop){
    00128       doit(_pop, Fitness()); // specializations for scalar and std::vector
    00129     }
    00130
    00131   virtual std::string className(void) const { return "eoAverageStat"; }
    00132
    00133 private :
    00134
    00135     // Specialization for pareto fitness
    00136     template <class T>
    00137     void doit(const eoPop<EOT>& _pop, eoParetoFitness<T>)
    00138     {
    00139       value().clear();
    00140       value().resize(_pop[0].fitness().size(), 0.0);
    00141
    00142       for (unsigned o = 0; o < value().size(); ++o)
    00143       {
    00144         for (unsigned i = 0; i < _pop.size(); ++i)
    00145         {
    00146           value()[o] += _pop[i].fitness()[o];
    00147         }
    00148
    00149         value()[o] /= _pop.size();
    00150       }
    00151     }
    00152
    00153     // Default behavior
    00154     template <class T>
    00155     void doit(const eoPop<EOT>& _pop, T)
    00156     {
    00157         Fitness v = std::accumulate(_pop.begin(), _pop.end(), Fitness(0.0), eoAverageStat::sumFitness);
    00158
    00159         value() = v / _pop.size();
    00160     }
    00161
    00162 };
    00163
    00167 template <class EOT>
    00168 class eoSecondMomentStats : public eoStat<EOT, std::pair<double, double> >
    00169 {
    00170 public :
    00171
    00172     using eoStat<EOT, std::pair<double, double> >::value;
    00173
    00174     typedef typename EOT::Fitness fitness_type;
    00175
    00176     typedef std::pair<double, double> SquarePair;
    00177
    00178     eoSecondMomentStats(std::string _description = "Average & Stdev")
    00179         : eoStat<EOT, SquarePair>(std::make_pair(0.0,0.0), _description)
    00180         {}
    00181
    00182     static SquarePair sumOfSquares(SquarePair _sq, const EOT& _eo)
    00183     {
    00184         double fitness = _eo.fitness();
    00185
    00186         _sq.first += fitness;
    00187         _sq.second += fitness * fitness;
    00188         return _sq;
    00189     }
    00190
    00191     virtual void operator()(const eoPop<EOT>& _pop)
    00192     {
    00193         SquarePair result = std::accumulate(_pop.begin(), _pop.end(), std::make_pair(0.0, 0.0), eoSecondMomentStats::sumOfSquares);
    00194
    00195         double n = _pop.size();
    00196         value().first = result.first / n; // average
    00197         value().second = sqrt( (result.second - n * value().first * value().first) / (n - 1.0)); // stdev
    00198     }
    00199
    00200   virtual std::string className(void) const { return "eoSecondMomentStats"; }
    00201 };
    00202
    00206 #ifdef _MSC_VER
    00207 template <class EOT>
    00208 class eoNthElementFitnessStat : public eoSortedStat<EOT, EOT::Fitness >
    00209 #else
    00210 template <class EOT>
    00211 class eoNthElementFitnessStat : public eoSortedStat<EOT, typename EOT::Fitness >
    00212 #endif
    00213 {
    00214 public :
    00215     using eoSortedStat<EOT, typename EOT::Fitness >::value;
    00216
    00217     typedef typename EOT::Fitness Fitness;
    00218
    00219     eoNthElementFitnessStat(unsigned _whichElement, std::string _description = "nth element fitness")
    00220       : eoSortedStat<EOT, Fitness>(Fitness(), _description), whichElement(_whichElement) {}
    00221
    00222     virtual void operator()(const std::vector<const EOT*>& _pop)
    00223     {
    00224         if (whichElement > _pop.size())
    00225             throw std::logic_error("fitness requested of element outside of pop");
    00226
    00227         doit(_pop, Fitness());
    00228     }
    00229
    00230   virtual std::string className(void) const { return "eoNthElementFitnessStat"; }
    00231 private :
    00232
    00233     struct CmpFitness
    00234     {
    00235       CmpFitness(unsigned _whichElement, bool _maxim) : whichElement(_whichElement), maxim(_maxim) {}
    00236
    00237       bool operator()(const EOT* a, const EOT* b)
    00238       {
    00239         if (maxim)
    00240           return a->fitness()[whichElement] > b->fitness()[whichElement];
    00241
    00242         return a->fitness()[whichElement] < b->fitness()[whichElement];
    00243       }
    00244
    00245       unsigned whichElement;
    00246       bool maxim;
    00247     };
    00248
    00249     // Specialization for eoParetoFitness
    00250     template <class T>
    00251     void doit(const eoPop<EOT>& _pop, eoParetoFitness<T>)
    00252     {
    00253       typedef typename EOT::Fitness::fitness_traits traits;
    00254
    00255       value().resize(traits::nObjectives());
    00256
    00257       // copy of pointers, what the heck
    00258       std::vector<const EOT*> tmp_pop = _pop;
    00259
    00260       for (unsigned o = 0; o < value().size(); ++o)
    00261       {
    00262         typename std::vector<const EOT*>::iterator nth = tmp_pop.begin() + whichElement;
    00263         std::nth_element(tmp_pop.begin(), nth, tmp_pop.end(), CmpFitness(o, traits::maximizing(o)));
    00264         value()[o] = (*nth)->fitness()[o];
    00265       }
    00266     }
    00267
    00268     // for everything else
    00269     template <class T>
    00270     void doit(const std::vector<const EOT*>& _pop, T)
    00271     {
    00272       value() = _pop[whichElement]->fitness();
    00273     }
    00274
    00275     unsigned whichElement;
    00276 };
    00277
    00278 /* Actually, you shouldn't need to sort the population to get the best fitness
    00279    MS - 17/11/00
    00280
    00281    But then again, if another stat needs sorted fitness anyway, getting the best
    00282    out would be very fast.
    00283    MK - 09/01/03
    00284
    00285 template <class EOT>
    00286 class eoBestFitnessStat : public eoStat<EOT, typename EOT::Fitness >
    00287 {
    00288 public :
    00289     typedef typename EOT::Fitness Fitness;
    00290
    00291     eoBestFitnessStat(std::string _description = "Best Fitness") :
    00292       eoStat<EOT, Fitness>(Fitness(), _description) {}
    00293
    00294     virtual void operator()(const eoPop<EOT>& _pop)
    00295     {
    00296         value() = _pop.nth_element_fitness(0);
    00297     }
    00298
    00299 };
    00300 */
    00301
    00311 #ifdef _MSC_VER
    00312 template <class EOT>
    00313 class eoBestFitnessStat : public eoStat<EOT, EOT::Fitness>
    00314 #else
    00315 template <class EOT>
    00316 class eoBestFitnessStat : public eoStat<EOT, typename EOT::Fitness>
    00317 #endif
    00318 {
    00319 public:
    00320
    00321     using eoStat<EOT, typename EOT::Fitness>::value;
    00322
    00323     typedef typename EOT::Fitness Fitness;
    00324
    00325     eoBestFitnessStat(std::string _description = "Best ")
    00326         : eoStat<EOT, Fitness>(Fitness(), _description)
    00327         {}
    00328
    00329     void operator()(const eoPop<EOT>& _pop) {
    00330         doit(_pop, Fitness() ); // specializations for scalar and std::vector
    00331     }
    00332
    00333     virtual std::string className(void) const { return "eoBestFitnessStat"; }
    00334
    00335
    00336 private :
    00337
    00338     struct CmpFitness
    00339     {
    00340       CmpFitness(unsigned _which, bool _maxim) : which(_which), maxim(_maxim) {}
    00341
    00342       bool operator()(const EOT& a, const EOT& b)
    00343       {
    00344         if (maxim)
    00345           return a.fitness()[which] < b.fitness()[which];
    00346
    00347         return a.fitness()[which] > b.fitness()[which];
    00348       }
    00349
    00350       unsigned which;
    00351       bool maxim;
    00352     };
    00353
    00354     // Specialization for pareto fitness
    00355     template <class T>
    00356     void doit(const eoPop<EOT>& _pop, eoParetoFitness<T>)
    00357     {
    00358       typedef typename EOT::Fitness::fitness_traits traits;
    00359       value().resize(traits::nObjectives());
    00360
    00361       for (unsigned o = 0; o < traits::nObjectives(); ++o)
    00362       {
    00363         typename eoPop<EOT>::const_iterator it = std::max_element(_pop.begin(), _pop.end(), CmpFitness(o, traits::maximizing(o)));
    00364         value()[o] = it->fitness()[o];
    00365       }
    00366     }
    00367
    00368     // default
    00369     template<class T>
    00370     void doit(const eoPop<EOT>& _pop, T)
    00371     { // find the largest elements
    00372       value() = _pop.best_element().fitness();
    00373     }
    00374
    00375 };
    00376
    00377 template <class EOT>
    00378 class eoDistanceStat : public eoStat<EOT, double>
    00379 {
    00380 public:
    00381
    00382     using eoDistanceStat< EOT >::value;
    00383
    00384     eoDistanceStat(std::string _name = "distance")
    00385         : eoStat<EOT, double>(0.0, _name)
    00386         {}
    00387
    00388     template <class T>
    00389     double distance(T a, T b)
    00390     {
    00391         T res = a-b;
    00392         return res < 0? -res : res;
    00393     }
    00394
    00395     double distance(bool a, bool b)
    00396     {
    00397         return (a==b)? 0 : 1;
    00398     }
    00399
    00400     void operator()(const eoPop<EOT>& _pop)
    00401     {
    00402         double& v = value();
    00403         v = 0.0;
    00404
    00405         for (unsigned i = 0; i < _pop.size(); ++i)
    00406         {
    00407             for (unsigned j = 0; j < _pop.size(); ++j)
    00408             {
    00409                 for (unsigned k = 0; k < _pop[i].size(); ++k)
    00410                 {
    00411                     v += distance(_pop[i][k], _pop[j][k]);
    00412                 }
    00413             }
    00414         }
    00415
    00416         double sz = _pop.size();
    00417         v /= sz * sz * _pop[0].size();
    00418     }
    00419   virtual std::string className(void) const { return "eoDistanceStat"; }
    00420
    00421 };
    00422
    00423
    00424
    00425 /*
    00426 template <class EOT>
    00427 class eoStdevStat : public eoStat<EOT, double >
    00428 {
    00429 public :
    00430     typedef typename eoSecondMomentStats<EOT>::SquarePair SquarePair;
    00431
    00432     eoStdevStat(std::string _description = "Stdev") : eoStat<EOT, double>(0.0, _description) {}
    00433
    00434     virtual void operator()(const eoPop<EOT>& _pop)
    00435     {
    00436         SquarePair result = std::accumulate(pop.begin(), pop.end(), std::make_pair(0.0, 0.0), eoSecondMomentStats::sumOfSquares);
    00437
    00438         double n = pop.size();
    00439         value() = sqrt( (result.second - (result.first / n)) / (n - 1.0)); // stdev
    00440     }
    00441 };
    00442 */
    00443 #endif