# eoNormalMutation.h

    00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
    00002
    00003 //-----------------------------------------------------------------------------
    00004 // eoNormalMutation.h
    00005 // (c) EEAAX 2001 - Maarten Keijzer 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: Marc.Schoenauer@polytechnique.fr
    00022              mak@dhi.dk
    00023  */
    00024 //-----------------------------------------------------------------------------
    00025
    00026 #ifndef eoNormalMutation_h
    00027 #define eoNormalMutation_h
    00028
    00029 //-----------------------------------------------------------------------------
    00030
    00031 #include <algorithm>    // swap_ranges
    00032 #include <utils/eoRNG.h>
    00033 #include <utils/eoUpdatable.h>
    00034 #include <eoEvalFunc.h>
    00035 #include <es/eoReal.h>
    00036 #include <utils/eoRealBounds.h>
    00037 //-----------------------------------------------------------------------------
    00038
    00048 template<class EOT> class eoNormalVecMutation: public eoMonOp<EOT>
    00049 {
    00050  public:
    00058   eoNormalVecMutation(double _sigma, const double& _p_change = 1.0):
    00059     sigma(_sigma), bounds(eoDummyVectorNoBounds), p_change(_p_change) {}
    00060
    00069   eoNormalVecMutation(eoRealVectorBounds & _bounds,
    00070                     double _sigma, const double& _p_change = 1.0):
    00071     sigma(_bounds.size(), _sigma), bounds(_bounds), p_change(_p_change)
    00072   {
    00073     // scale to the range - if any
    00074     for (unsigned i=0; i<bounds.size(); i++)
    00075       if (bounds.isBounded(i))
    00076           sigma[i] *= _sigma*bounds.range(i);
    00077   }
    00078
    00080   virtual std::string className() const { return "eoNormalVecMutation"; }
    00081
    00086   bool operator()(EOT& _eo)
    00087     {
    00088       bool hasChanged=false;
    00089       for (unsigned lieu=0; lieu<_eo.size(); lieu++)
    00090         {
    00091           if (rng.flip(p_change))
    00092             {
    00093               _eo[lieu] += sigma[lieu]*rng.normal();
    00094               bounds.foldsInBounds(lieu, _eo[lieu]);
    00095               hasChanged = true;
    00096             }
    00097         }
    00098       return hasChanged;
    00099     }
    00100
    00101 private:
    00102   std::vector<double> sigma;
    00103   eoRealVectorBounds & bounds;
    00104   double p_change;
    00105 };
    00106
    00116 template<class EOT> class eoNormalMutation
    00117     : public eoMonOp<EOT>
    00118 {
    00119 public:
    00127   eoNormalMutation(double & _sigma, const double& _p_change = 1.0):
    00128     sigma(_sigma), bounds(eoDummyVectorNoBounds), p_change(_p_change) {}
    00129
    00136   eoNormalMutation(eoRealVectorBounds & _bounds,
    00137                     double _sigma, const double& _p_change = 1.0):
    00138     sigma(_sigma), bounds(_bounds), p_change(_p_change) {}
    00139
    00141   virtual std::string className() const { return "eoNormalMutation"; }
    00142
    00147   bool operator()(EOT& _eo)
    00148     {
    00149       bool hasChanged=false;
    00150       for (unsigned lieu=0; lieu<_eo.size(); lieu++)
    00151         {
    00152           if (rng.flip(p_change))
    00153             {
    00154               _eo[lieu] += sigma*rng.normal();
    00155               bounds.foldsInBounds(lieu, _eo[lieu]);
    00156               hasChanged = true;
    00157             }
    00158         }
    00159       return hasChanged;
    00160     }
    00161
    00163   double & Sigma() {return sigma;}
    00164
    00165 private:
    00166   double & sigma;
    00167   eoRealVectorBounds & bounds;
    00168   double p_change;
    00169 };
    00170
    00177 template<class EOT> class eoOneFifthMutation :
    00178   public eoNormalMutation<EOT>, public eoUpdatable
    00179 {
    00180 public:
    00181
    00182     using eoNormalMutation< EOT >::Sigma;
    00183
    00184     typedef typename EOT::Fitness Fitness;
    00185
    00195   eoOneFifthMutation(eoEvalFunc<EOT> & _eval, double & _sigmaInit,
    00196                      unsigned _windowSize = 10, double _updateFactor=0.83,
    00197                      double _threshold=0.2):
    00198     eoNormalMutation<EOT>(_sigmaInit), eval(_eval),
    00199     threshold(_threshold), updateFactor(_updateFactor),
    00200     nbMut(_windowSize, 0), nbSuccess(_windowSize, 0), genIndex(0)
    00201   {
    00202     // minimal check
    00203     if (updateFactor>=1)
    00204       throw std::runtime_error("Update factor must be < 1 in eoOneFifthMutation");
    00205   }
    00206
    00208   virtual std::string className() const { return "eoOneFifthMutation"; }
    00209
    00216   bool operator()(EOT & _eo)
    00217     {
    00218       if (_eo.invalid())           // due to some crossover???
    00219         eval(_eo);
    00220       Fitness oldFitness = _eo.fitness(); // save old fitness
    00221
    00222       // call standard operator - then count the successes
    00223       if (eoNormalMutation<EOT>::operator()(_eo)) // _eo has been modified
    00224         {
    00225           _eo.invalidate();        // don't forget!!!
    00226           nbMut[genIndex]++;
    00227           eval(_eo);               // compute fitness of offspring
    00228
    00229           if (_eo.fitness() > oldFitness)
    00230             nbSuccess[genIndex]++;          // update counter
    00231         }
    00232       return false;                // because eval has reset the validity flag
    00233     }
    00234
    00238   void update()
    00239   {
    00240     unsigned totalMut = 0;
    00241     unsigned totalSuccess = 0;
    00242     // compute the average stats over the time window
    00243     for ( unsigned i=0; i<nbMut.size(); i++)
    00244       {
    00245         totalMut += nbMut[i];
    00246         totalSuccess += nbSuccess[i];
    00247       }
    00248
    00249     // update sigma accordingly
    00250     double prop = double(totalSuccess) / totalMut;
    00251     if (prop > threshold) {
    00252       Sigma() /= updateFactor;     // increase sigma
    00253     }
    00254     else
    00255       {
    00256         Sigma() *= updateFactor;           // decrease sigma
    00257       }
    00258     genIndex = (genIndex+1) % nbMut.size() ;
    00259     nbMut[genIndex] = nbSuccess[genIndex] = 0;
    00260
    00261   }
    00262
    00263 private:
    00264   eoEvalFunc<EOT> & eval;
    00265   double threshold;                // 1/5 !
    00266   double updateFactor ;            // the multiplicative factor
    00267   std::vector<unsigned> nbMut;     // total number of mutations per gen
    00268   std::vector<unsigned> nbSuccess;         // number of successful mutations per gen
    00269   unsigned genIndex ;              // current index in std::vectors (circular)
    00270 };
    00271
    00272
    00273 //-----------------------------------------------------------------------------
    00275 #endif
    00276