EvolvingObjects
|
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