EvolvingObjects
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 
00047 template<class EOT> class eoUniformMutation: public eoMonOp<EOT>
00048 {
00049  public:
00058   eoUniformMutation(const double& _epsilon, const double& _p_change = 1.0):
00059     homogeneous(true), bounds(eoDummyVectorNoBounds), epsilon(1, _epsilon),
00060     p_change(1, _p_change) {}
00061 
00068   eoUniformMutation(eoRealVectorBounds & _bounds,
00069                     const double& _epsilon, const double& _p_change = 1.0):
00070     homogeneous(false), bounds(_bounds), epsilon(_bounds.size(), _epsilon),
00071     p_change(_bounds.size(), _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           epsilon[i] *= _epsilon*bounds.range(i);
00077   }
00078 
00085   eoUniformMutation(eoRealVectorBounds & _bounds,
00086                     const std::vector<double>& _epsilon,
00087                     const std::vector<double>& _p_change):
00088     homogeneous(false), bounds(_bounds), epsilon(_epsilon),
00089     p_change(_p_change) {}
00090 
00092   virtual std::string className() const { return "eoUniformMutation"; }
00093 
00098   bool operator()(EOT& _eo)
00099     {
00100       bool hasChanged=false;
00101       if (homogeneous)             // implies no bounds object
00102         for (unsigned lieu=0; lieu<_eo.size(); lieu++)
00103           {
00104             if (rng.flip(p_change[0]))
00105               {
00106                 _eo[lieu] += 2*epsilon[0]*rng.uniform()-epsilon[0];
00107                 hasChanged = true;
00108               }
00109           }
00110       else
00111         {
00112           // sanity check ?
00113           if (_eo.size() != bounds.size())
00114             throw std::runtime_error("Invalid size of indi in eoUniformMutation");
00115 
00116           for (unsigned lieu=0; lieu<_eo.size(); lieu++)
00117             if (rng.flip(p_change[lieu]))
00118               {
00119                 // check the bounds
00120                 double emin = _eo[lieu]-epsilon[lieu];
00121                 double emax = _eo[lieu]+epsilon[lieu];
00122                 if (bounds.isMinBounded(lieu))
00123                   emin = std::max(bounds.minimum(lieu), emin);
00124                 if (bounds.isMaxBounded(lieu))
00125                   emax = std::min(bounds.maximum(lieu), emax);
00126                 _eo[lieu] = emin + (emax-emin)*rng.uniform();
00127                 hasChanged = true;
00128               }
00129         }
00130       return hasChanged;
00131     }
00132 
00133 private:
00134   bool homogeneous;   // == no bounds passed in the ctor
00135   eoRealVectorBounds & bounds;
00136   std::vector<double> epsilon;     // the ranges for mutation
00137   std::vector<double> p_change;    // the proba that each variable is modified
00138 };
00139 
00148 template<class EOT> class eoDetUniformMutation: public eoMonOp<EOT>
00149 {
00150  public:
00158   eoDetUniformMutation(const double& _epsilon, const unsigned& _no = 1):
00159     homogeneous(true), bounds(eoDummyVectorNoBounds),
00160     epsilon(1, _epsilon), no(_no) {}
00161 
00168   eoDetUniformMutation(eoRealVectorBounds & _bounds,
00169                        const double& _epsilon, const unsigned& _no = 1):
00170     homogeneous(false), bounds(_bounds),
00171     epsilon(_bounds.size(), _epsilon), no(_no)
00172   {
00173     // scale to the range - if any
00174     for (unsigned i=0; i<bounds.size(); i++)
00175       if (bounds.isBounded(i))
00176           epsilon[i] *= _epsilon*bounds.range(i);
00177   }
00178 
00185   eoDetUniformMutation(eoRealVectorBounds & _bounds,
00186                        const std::vector<double>& _epsilon,
00187                        const unsigned& _no = 1):
00188     homogeneous(false), bounds(_bounds), epsilon(_epsilon), no(_no)
00189   {
00190     // scale to the range - if any
00191     for (unsigned i=0; i<bounds.size(); i++)
00192       if (bounds.isBounded(i))
00193           epsilon[i] *= _epsilon[i]*bounds.range(i);
00194   }
00195 
00197   virtual std::string className() const { return "eoDetUniformMutation"; }
00198 
00203   bool operator()(EOT& _eo)
00204     {
00205       if (homogeneous)
00206         for (unsigned i=0; i<no; i++)
00207           {
00208             unsigned lieu = rng.random(_eo.size());
00209             // actually, we should test that we don't re-modify same variable!
00210             _eo[lieu] = 2*epsilon[0]*rng.uniform()-epsilon[0];
00211           }
00212       else
00213         {
00214           // sanity check ?
00215           if (_eo.size() != bounds.size())
00216             throw std::runtime_error("Invalid size of indi in eoDetUniformMutation");
00217           for (unsigned i=0; i<no; i++)
00218             {
00219               unsigned lieu = rng.random(_eo.size());
00220               // actually, we should test that we don't re-modify same variable!
00221 
00222               // check the bounds
00223               double emin = _eo[lieu]-epsilon[lieu];
00224               double emax = _eo[lieu]+epsilon[lieu];
00225               if (bounds.isMinBounded(lieu))
00226                 emin = std::max(bounds.minimum(lieu), emin);
00227               if (bounds.isMaxBounded(lieu))
00228                 emax = std::min(bounds.maximum(lieu), emax);
00229               _eo[lieu] = emin + (emax-emin)*rng.uniform();
00230             }
00231         }
00232       return true;
00233     }
00234 
00235 private:
00236   bool homogeneous;   //  == no bounds passed in the ctor
00237   eoRealVectorBounds & bounds;
00238   std::vector<double> epsilon;     // the ranges of mutation
00239   unsigned no;
00240 };
00241 
00242 
00243 // two arithmetical crossovers
00244 
00253 template<class EOT> class eoSegmentCrossover: public eoQuadOp<EOT>
00254 {
00255  public:
00265   eoSegmentCrossover(const double& _alpha = 0.0) :
00266     bounds(eoDummyVectorNoBounds), alpha(_alpha), range(1+2*_alpha) {}
00267 
00276   eoSegmentCrossover(eoRealVectorBounds & _bounds,
00277                      const double& _alpha = 0.0) :
00278     bounds(_bounds), alpha(_alpha), range(1+2*_alpha) {}
00279 
00281   virtual std::string className() const { return "eoSegmentCrossover"; }
00282 
00288   bool operator()(EOT& _eo1, EOT& _eo2)
00289     {
00290       unsigned i;
00291       double r1, r2, fact;
00292       double alphaMin = -alpha;
00293       double alphaMax = 1+alpha;
00294       if (alpha == 0.0)            // no check to perform
00295         fact = -alpha + rng.uniform(range); // in [-alpha,1+alpha)
00296       else                         // look for the bounds for fact
00297         {
00298           for (i=0; i<_eo1.size(); i++)
00299             {
00300               r1=_eo1[i];
00301               r2=_eo2[i];
00302               if (r1 != r2) {      // otherwise you'll get NAN's
00303                 double rmin = std::min(r1, r2);
00304                 double rmax = std::max(r1, r2);
00305                 double length = rmax - rmin;
00306                 if (bounds.isMinBounded(i))
00307                   {
00308                     alphaMin = std::max(alphaMin, (bounds.minimum(i)-rmin)/length);
00309                     alphaMax = std::min(alphaMax, (rmax-bounds.minimum(i))/length);
00310                   }
00311                 if (bounds.isMaxBounded(i))
00312                   {
00313                     alphaMax = std::min(alphaMax, (bounds.maximum(i)-rmin)/length);
00314                     alphaMin = std::max(alphaMin, (rmax-bounds.maximum(i))/length);
00315                   }
00316               }
00317             }
00318           fact = alphaMin + (alphaMax-alphaMin)*rng.uniform();
00319         }
00320 
00321       for (i=0; i<_eo1.size(); i++)
00322         {
00323           r1=_eo1[i];
00324           r2=_eo2[i];
00325           _eo1[i] = fact * r1 + (1-fact) * r2;
00326           _eo2[i] = (1-fact) * r1 + fact * r2;
00327         }
00328       return true;         // shoudl test if fact was 0 or 1 :-)))
00329     }
00330 
00331 protected:
00332   eoRealVectorBounds & bounds;
00333   double alpha;
00334   double range;                    // == 1+2*alpha
00335 };
00336 
00344 template<class EOT> class eoHypercubeCrossover: public eoQuadOp<EOT>
00345 {
00346  public:
00356   eoHypercubeCrossover(const double& _alpha = 0.0):
00357     bounds(eoDummyVectorNoBounds), alpha(_alpha), range(1+2*_alpha)
00358   {
00359     if (_alpha < 0)
00360       throw std::runtime_error("BLX coefficient should be positive");
00361   }
00362 
00371   eoHypercubeCrossover(eoRealVectorBounds & _bounds,
00372                         const double& _alpha = 0.0):
00373     bounds(_bounds), alpha(_alpha), range(1+2*_alpha)
00374   {
00375     if (_alpha < 0)
00376       throw std::runtime_error("BLX coefficient should be positive");
00377   }
00378 
00380   virtual std::string className() const { return "eoHypercubeCrossover"; }
00381 
00387   bool operator()(EOT& _eo1, EOT& _eo2)
00388     {
00389       bool hasChanged = false;
00390       unsigned i;
00391       double r1, r2, fact;
00392       if (alpha == 0.0)            // no check to perform
00393           for (i=0; i<_eo1.size(); i++)
00394             {
00395               r1=_eo1[i];
00396               r2=_eo2[i];
00397               if (r1 != r2) {      // otherwise do nothing
00398                 fact = rng.uniform(range);       // in [0,1)
00399                 _eo1[i] = fact * r1 + (1-fact) * r2;
00400                 _eo2[i] = (1-fact) * r1 + fact * r2;
00401                 hasChanged = true; // forget (im)possible alpha=0
00402               }
00403             }
00404       else         // check the bounds
00405         // do not try to get a bound on the linear factor, but rather
00406         // on the object variables themselves
00407         for (i=0; i<_eo1.size(); i++)
00408           {
00409             r1=_eo1[i];
00410             r2=_eo2[i];
00411             if (r1 != r2) {        // otherwise do nothing
00412               double rmin = std::min(r1, r2);
00413               double rmax = std::max(r1, r2);
00414 
00415               // compute min and max for object variables
00416               double objMin = -alpha * rmax + (1+alpha) * rmin;
00417               double objMax = -alpha * rmin + (1+alpha) * rmax;
00418 
00419               // first find the limits on the alpha's
00420               if (bounds.isMinBounded(i))
00421                 {
00422                   objMin = std::max(objMin, bounds.minimum(i));
00423                 }
00424               if (bounds.isMaxBounded(i))
00425                 {
00426                   objMax = std::min(objMax, bounds.maximum(i));
00427                 }
00428               // then draw variables
00429               double median = (objMin+objMax)/2.0; // uniform within bounds
00430               // double median = (rmin+rmax)/2.0;  // Bounce on bounds
00431               double valMin = objMin + (median-objMin)*rng.uniform();
00432               double valMax = median + (objMax-median)*rng.uniform();
00433               // don't always put large value in _eo1 - or what?
00434               if (rng.flip(0.5))
00435                 {
00436                   _eo1[i] = valMin;
00437                   _eo2[i] = valMax;
00438                 }
00439               else
00440                 {
00441                   _eo1[i] = valMax;
00442                   _eo2[i] = valMin;
00443                 }
00444               // seomthing has changed
00445               hasChanged = true; // forget (im)possible alpha=0
00446             }
00447           }
00448 
00449     return hasChanged;
00450    }
00451 
00452 protected:
00453   eoRealVectorBounds & bounds;
00454   double alpha;
00455   double range;                    // == 1+2*alphaMin
00456 };
00457 
00458 
00466 template<class EOT> class eoRealUXover: public eoQuadOp<EOT>
00467 {
00468  public:
00473   eoRealUXover(const float& _preference = 0.5): preference(_preference)
00474     {
00475       if ( (_preference <= 0.0) || (_preference >= 1.0) )
00476         std::runtime_error("UxOver --> invalid preference");
00477     }
00478 
00480   virtual std::string className() const { return "eoRealUXover"; }
00481 
00488   bool operator()(EOT& _eo1, EOT& _eo2)
00489     {
00490       if ( _eo1.size() != _eo2.size())
00491             std::runtime_error("UxOver --> chromosomes sizes don't match" );
00492       bool changed = false;
00493       for (unsigned int i=0; i<_eo1.size(); i++)
00494         {
00495           if (rng.flip(preference))
00496             if (_eo1[i] != _eo2[i])
00497               {
00498                 double tmp = _eo1[i];
00499               _eo1[i]=_eo2[i];
00500               _eo2[i] = tmp;
00501               changed = true;
00502             }
00503         }
00504       return changed;
00505     }
00506     private:
00507       float preference;
00508 };
00509 
00510 
00511 //-----------------------------------------------------------------------------
00513 #endif
 All Classes Namespaces Files Functions Variables Typedefs Friends