# eoRealOp.h

    00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
    00002
    00003 //-----------------------------------------------------------------------------
    00004 // eoRealOp.h
    00005 // (c) Maarten Keijzer 2000 - Marc Schoenauer 2001
    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 eoRealOp_h
    00027 #define eoRealOp_h
    00028
    00029 //-----------------------------------------------------------------------------
    00030
    00031 #include <algorithm>    // swap_ranges
    00032 #include <utils/eoRNG.h>
    00033 #include <es/eoReal.h>
    00034 #include <utils/eoRealVectorBounds.h>
    00035
    00036 //-----------------------------------------------------------------------------
    00037
    00045 template<class EOT> class eoUniformMutation: public eoMonOp<EOT>
    00046 {
    00047  public:
    00056   eoUniformMutation(const double& _epsilon, const double& _p_change = 1.0):
    00057     homogeneous(true), bounds(eoDummyVectorNoBounds), epsilon(1, _epsilon),
    00058     p_change(1, _p_change) {}
    00059
    00066   eoUniformMutation(eoRealVectorBounds & _bounds,
    00067                     const double& _epsilon, const double& _p_change = 1.0):
    00068     homogeneous(false), bounds(_bounds), epsilon(_bounds.size(), _epsilon),
    00069     p_change(_bounds.size(), _p_change)
    00070   {
    00071     // scale to the range - if any
    00072     for (unsigned i=0; i<bounds.size(); i++)
    00073       if (bounds.isBounded(i))
    00074           epsilon[i] *= _epsilon*bounds.range(i);
    00075   }
    00076
    00083   eoUniformMutation(eoRealVectorBounds & _bounds,
    00084                     const std::vector<double>& _epsilon,
    00085                     const std::vector<double>& _p_change):
    00086     homogeneous(false), bounds(_bounds), epsilon(_epsilon),
    00087     p_change(_p_change) {}
    00088
    00090   virtual std::string className() const { return "eoUniformMutation"; }
    00091
    00096   bool operator()(EOT& _eo)
    00097     {
    00098       bool hasChanged=false;
    00099       if (homogeneous)             // implies no bounds object
    00100         for (unsigned lieu=0; lieu<_eo.size(); lieu++)
    00101           {
    00102             if (rng.flip(p_change[0]))
    00103               {
    00104                 _eo[lieu] += 2*epsilon[0]*rng.uniform()-epsilon[0];
    00105                 hasChanged = true;
    00106               }
    00107           }
    00108       else
    00109         {
    00110           // sanity check ?
    00111           if (_eo.size() != bounds.size())
    00112             throw std::runtime_error("Invalid size of indi in eoUniformMutation");
    00113
    00114           for (unsigned lieu=0; lieu<_eo.size(); lieu++)
    00115             if (rng.flip(p_change[lieu]))
    00116               {
    00117                 // check the bounds
    00118                 double emin = _eo[lieu]-epsilon[lieu];
    00119                 double emax = _eo[lieu]+epsilon[lieu];
    00120                 if (bounds.isMinBounded(lieu))
    00121                   emin = std::max(bounds.minimum(lieu), emin);
    00122                 if (bounds.isMaxBounded(lieu))
    00123                   emax = std::min(bounds.maximum(lieu), emax);
    00124                 _eo[lieu] = emin + (emax-emin)*rng.uniform();
    00125                 hasChanged = true;
    00126               }
    00127         }
    00128       return hasChanged;
    00129     }
    00130
    00131 private:
    00132   bool homogeneous;   // == no bounds passed in the ctor
    00133   eoRealVectorBounds & bounds;
    00134   std::vector<double> epsilon;     // the ranges for mutation
    00135   std::vector<double> p_change;    // the proba that each variable is modified
    00136 };
    00137
    00144 template<class EOT> class eoDetUniformMutation: public eoMonOp<EOT>
    00145 {
    00146  public:
    00154   eoDetUniformMutation(const double& _epsilon, const unsigned& _no = 1):
    00155     homogeneous(true), bounds(eoDummyVectorNoBounds),
    00156     epsilon(1, _epsilon), no(_no) {}
    00157
    00164   eoDetUniformMutation(eoRealVectorBounds & _bounds,
    00165                        const double& _epsilon, const unsigned& _no = 1):
    00166     homogeneous(false), bounds(_bounds),
    00167     epsilon(_bounds.size(), _epsilon), no(_no)
    00168   {
    00169     // scale to the range - if any
    00170     for (unsigned i=0; i<bounds.size(); i++)
    00171       if (bounds.isBounded(i))
    00172           epsilon[i] *= _epsilon*bounds.range(i);
    00173   }
    00174
    00181   eoDetUniformMutation(eoRealVectorBounds & _bounds,
    00182                        const std::vector<double>& _epsilon,
    00183                        const unsigned& _no = 1):
    00184     homogeneous(false), bounds(_bounds), epsilon(_epsilon), no(_no)
    00185   {
    00186     // scale to the range - if any
    00187     for (unsigned i=0; i<bounds.size(); i++)
    00188       if (bounds.isBounded(i))
    00189           epsilon[i] *= _epsilon[i]*bounds.range(i);
    00190   }
    00191
    00193   virtual std::string className() const { return "eoDetUniformMutation"; }
    00194
    00199   bool operator()(EOT& _eo)
    00200     {
    00201       if (homogeneous)
    00202         for (unsigned i=0; i<no; i++)
    00203           {
    00204             unsigned lieu = rng.random(_eo.size());
    00205             // actually, we should test that we don't re-modify same variable!
    00206             _eo[lieu] = 2*epsilon[0]*rng.uniform()-epsilon[0];
    00207           }
    00208       else
    00209         {
    00210           // sanity check ?
    00211           if (_eo.size() != bounds.size())
    00212             throw std::runtime_error("Invalid size of indi in eoDetUniformMutation");
    00213           for (unsigned i=0; i<no; i++)
    00214             {
    00215               unsigned lieu = rng.random(_eo.size());
    00216               // actually, we should test that we don't re-modify same variable!
    00217
    00218               // check the bounds
    00219               double emin = _eo[lieu]-epsilon[lieu];
    00220               double emax = _eo[lieu]+epsilon[lieu];
    00221               if (bounds.isMinBounded(lieu))
    00222                 emin = std::max(bounds.minimum(lieu), emin);
    00223               if (bounds.isMaxBounded(lieu))
    00224                 emax = std::min(bounds.maximum(lieu), emax);
    00225               _eo[lieu] = emin + (emax-emin)*rng.uniform();
    00226             }
    00227         }
    00228       return true;
    00229     }
    00230
    00231 private:
    00232   bool homogeneous;   //  == no bounds passed in the ctor
    00233   eoRealVectorBounds & bounds;
    00234   std::vector<double> epsilon;     // the ranges of mutation
    00235   unsigned no;
    00236 };
    00237
    00238
    00239 // two arithmetical crossovers
    00240
    00247 template<class EOT> class eoSegmentCrossover: public eoQuadOp<EOT>
    00248 {
    00249  public:
    00259   eoSegmentCrossover(const double& _alpha = 0.0) :
    00260     bounds(eoDummyVectorNoBounds), alpha(_alpha), range(1+2*_alpha) {}
    00261
    00270   eoSegmentCrossover(eoRealVectorBounds & _bounds,
    00271                      const double& _alpha = 0.0) :
    00272     bounds(_bounds), alpha(_alpha), range(1+2*_alpha) {}
    00273
    00275   virtual std::string className() const { return "eoSegmentCrossover"; }
    00276
    00282   bool operator()(EOT& _eo1, EOT& _eo2)
    00283     {
    00284       unsigned i;
    00285       double r1, r2, fact;
    00286       double alphaMin = -alpha;
    00287       double alphaMax = 1+alpha;
    00288       if (alpha == 0.0)            // no check to perform
    00289         fact = -alpha + rng.uniform(range); // in [-alpha,1+alpha)
    00290       else                         // look for the bounds for fact
    00291         {
    00292           for (i=0; i<_eo1.size(); i++)
    00293             {
    00294               r1=_eo1[i];
    00295               r2=_eo2[i];
    00296               if (r1 != r2) {      // otherwise you'll get NAN's
    00297                 double rmin = std::min(r1, r2);
    00298                 double rmax = std::max(r1, r2);
    00299                 double length = rmax - rmin;
    00300                 if (bounds.isMinBounded(i))
    00301                   {
    00302                     alphaMin = std::max(alphaMin, (bounds.minimum(i)-rmin)/length);
    00303                     alphaMax = std::min(alphaMax, (rmax-bounds.minimum(i))/length);
    00304                   }
    00305                 if (bounds.isMaxBounded(i))
    00306                   {
    00307                     alphaMax = std::min(alphaMax, (bounds.maximum(i)-rmin)/length);
    00308                     alphaMin = std::max(alphaMin, (rmax-bounds.maximum(i))/length);
    00309                   }
    00310               }
    00311             }
    00312           fact = alphaMin + (alphaMax-alphaMin)*rng.uniform();
    00313         }
    00314
    00315       for (i=0; i<_eo1.size(); i++)
    00316         {
    00317           r1=_eo1[i];
    00318           r2=_eo2[i];
    00319           _eo1[i] = fact * r1 + (1-fact) * r2;
    00320           _eo2[i] = (1-fact) * r1 + fact * r2;
    00321         }
    00322       return true;         // shoudl test if fact was 0 or 1 :-)))
    00323     }
    00324
    00325 protected:
    00326   eoRealVectorBounds & bounds;
    00327   double alpha;
    00328   double range;                    // == 1+2*alpha
    00329 };
    00330
    00337 template<class EOT> class eoHypercubeCrossover: public eoQuadOp<EOT>
    00338 {
    00339  public:
    00349   eoHypercubeCrossover(const double& _alpha = 0.0):
    00350     bounds(eoDummyVectorNoBounds), alpha(_alpha), range(1+2*_alpha)
    00351   {
    00352     if (_alpha < 0)
    00353       throw std::runtime_error("BLX coefficient should be positive");
    00354   }
    00355
    00364   eoHypercubeCrossover(eoRealVectorBounds & _bounds,
    00365                         const double& _alpha = 0.0):
    00366     bounds(_bounds), alpha(_alpha), range(1+2*_alpha)
    00367   {
    00368     if (_alpha < 0)
    00369       throw std::runtime_error("BLX coefficient should be positive");
    00370   }
    00371
    00373   virtual std::string className() const { return "eoHypercubeCrossover"; }
    00374
    00380   bool operator()(EOT& _eo1, EOT& _eo2)
    00381     {
    00382       bool hasChanged = false;
    00383       unsigned i;
    00384       double r1, r2, fact;
    00385       if (alpha == 0.0)            // no check to perform
    00386           for (i=0; i<_eo1.size(); i++)
    00387             {
    00388               r1=_eo1[i];
    00389               r2=_eo2[i];
    00390               if (r1 != r2) {      // otherwise do nothing
    00391                 fact = rng.uniform(range);       // in [0,1)
    00392                 _eo1[i] = fact * r1 + (1-fact) * r2;
    00393                 _eo2[i] = (1-fact) * r1 + fact * r2;
    00394                 hasChanged = true; // forget (im)possible alpha=0
    00395               }
    00396             }
    00397       else         // check the bounds
    00398         // do not try to get a bound on the linear factor, but rather
    00399         // on the object variables themselves
    00400         for (i=0; i<_eo1.size(); i++)
    00401           {
    00402             r1=_eo1[i];
    00403             r2=_eo2[i];
    00404             if (r1 != r2) {        // otherwise do nothing
    00405               double rmin = std::min(r1, r2);
    00406               double rmax = std::max(r1, r2);
    00407
    00408               // compute min and max for object variables
    00409               double objMin = -alpha * rmax + (1+alpha) * rmin;
    00410               double objMax = -alpha * rmin + (1+alpha) * rmax;
    00411
    00412               // first find the limits on the alpha's
    00413               if (bounds.isMinBounded(i))
    00414                 {
    00415                   objMin = std::max(objMin, bounds.minimum(i));
    00416                 }
    00417               if (bounds.isMaxBounded(i))
    00418                 {
    00419                   objMax = std::min(objMax, bounds.maximum(i));
    00420                 }
    00421               // then draw variables
    00422               double median = (objMin+objMax)/2.0; // uniform within bounds
    00423               // double median = (rmin+rmax)/2.0;  // Bounce on bounds
    00424               double valMin = objMin + (median-objMin)*rng.uniform();
    00425               double valMax = median + (objMax-median)*rng.uniform();
    00426               // don't always put large value in _eo1 - or what?
    00427               if (rng.flip(0.5))
    00428                 {
    00429                   _eo1[i] = valMin;
    00430                   _eo2[i] = valMax;
    00431                 }
    00432               else
    00433                 {
    00434                   _eo1[i] = valMax;
    00435                   _eo2[i] = valMin;
    00436                 }
    00437               // seomthing has changed
    00438               hasChanged = true; // forget (im)possible alpha=0
    00439             }
    00440           }
    00441
    00442     return hasChanged;
    00443    }
    00444
    00445 protected:
    00446   eoRealVectorBounds & bounds;
    00447   double alpha;
    00448   double range;                    // == 1+2*alphaMin
    00449 };
    00450
    00451
    00457 template<class EOT> class eoRealUXover: public eoQuadOp<EOT>
    00458 {
    00459  public:
    00464   eoRealUXover(const float& _preference = 0.5): preference(_preference)
    00465     {
    00466       if ( (_preference <= 0.0) || (_preference >= 1.0) )
    00467         std::runtime_error("UxOver --> invalid preference");
    00468     }
    00469
    00471   virtual std::string className() const { return "eoRealUXover"; }
    00472
    00479   bool operator()(EOT& _eo1, EOT& _eo2)
    00480     {
    00481       if ( _eo1.size() != _eo2.size())
    00482             std::runtime_error("UxOver --> chromosomes sizes don't match" );
    00483       bool changed = false;
    00484       for (unsigned int i=0; i<_eo1.size(); i++)
    00485         {
    00486           if (rng.flip(preference))
    00487             if (_eo1[i] != _eo2[i])
    00488               {
    00489                 double tmp = _eo1[i];
    00490               _eo1[i]=_eo2[i];
    00491               _eo2[i] = tmp;
    00492               changed = true;
    00493             }
    00494         }
    00495       return changed;
    00496     }
    00497     private:
    00498       float preference;
    00499 };
    00500
    00501
    00502 //-----------------------------------------------------------------------------
    00504 #endif