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

Generated on Thu Oct 19 05:06:37 2006 for EO by  doxygen 1.3.9.1