t-eoGenOp.cpp

00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
00002 
00003 //-----------------------------------------------------------------------------
00004 // eoGenOp.cpp
00005 // (c) Maarten Keijzer and 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: mkeijzer@dhi.dk
00022              Marc.Schoenauer@polytechnique.fr
00023  */
00024 //-----------------------------------------------------------------------------
00025 
00030 #include <sstream>
00031 
00032 #include <eo>
00033 #include <eoPopulator.h>
00034 #include <eoOpContainer.h>
00035 
00036 struct Dummy : public EO<double>
00037 {
00038   typedef double Type;
00039   Dummy(std::string _s="") : s(_s) {}
00040 
00041   void printOn(std::ostream & _os) const
00042   {
00043     EO<double>::printOn(_os);
00044     _os << " - " << s ;
00045   }
00046 
00047   std::string s;
00048 };
00049 
00050 typedef Dummy EOT;
00051 
00052 unsigned int pSize;      // global to be used as marker in the fitness
00053 
00054 // DEFINITIONS of the eoOps
00055 class monop : public eoMonOp<EOT>
00056 {
00057   public :
00058   monop(char * _sig){sig=_sig;}
00059     bool operator()(EOT& _eo)
00060     {
00061       _eo.s = sig + "(" + _eo.s + ")";
00062       _eo.fitness(_eo.fitness()+pSize);
00063       return false;
00064     }
00065   std::string className() const {return sig;}
00066     private:
00067     std::string sig;
00068 };
00069 
00070 class binop: public eoBinOp<EOT>
00071 {
00072   public :
00073     bool operator()(EOT& _eo1, const EOT& _eo2)
00074     {
00075       _eo1.s = "bin(" + _eo1.s + "," + _eo2.s + ")";
00076       double f= (_eo1.fitness()+_eo2.fitness()) * pSize;
00077       _eo1.fitness(_eo1.fitness()+f);
00078       return false;
00079     }
00080   std::string className() const {return "binop";}
00081 };
00082 
00083 class quadop: public eoQuadOp<EOT>
00084 {
00085   public :
00086   std::string className() const {return "quadop";}
00087     bool operator()(EOT& a, EOT& b)
00088     {
00089       EOT oi = a;
00090       EOT oj = b;
00091 
00092       a.s = "quad1(" + oi.s + "," + oj.s + ")";
00093       b.s = "quad2(" + oj.s + "," + oi.s + ")";
00094       double f= (a.fitness()+b.fitness()+2*pSize) * pSize;
00095       a.fitness(a.fitness()+f);
00096       b.fitness(b.fitness()+f);
00097       return false;
00098     }
00099 };
00100 // an eoQuadOp that does nothing
00101 class quadClone: public eoQuadOp<EOT>
00102 {
00103   public :
00104   std::string className() const {return "quadclone";}
00105     bool operator()(EOT& , EOT& ) {return false;}
00106 };
00107 
00108 // User defined General Operator... adapted from Marc's example
00109 
00110 class one2threeOp : public eoGenOp<EOT> // :-)
00111 {
00112   public:
00113     unsigned max_production(void) { return 3; }
00114 
00115     void apply(eoPopulator<EOT>& _plop)
00116     {
00117       EOT& eo = *_plop; // select the guy
00118 
00119       ++_plop; // advance
00120       _plop.insert("v(" + eo.s + ", 1)");
00121       ++_plop;
00122       _plop.insert("v(" + eo.s + ", 2)");
00123       eo.s  =  "v(" + eo.s + ", 0)"; // only now change the thing
00124       // oh right, and invalidate fitnesses
00125     }
00126   virtual std::string className() const {return "one2threeOp";}
00127 };
00128 
00129 
00130 class two2oneOp : public eoGenOp<EOT> // :-)
00131 {
00132   public:
00133     unsigned max_production(void) { return 1; }
00134 
00135     void apply(eoPopulator<EOT>& _plop)
00136     {
00137       EOT& eo = *_plop; // select the guy
00138       const EOT& eo2 = _plop.select();
00139       eo.s  =  "221(" + eo.s + ", " + eo2.s + ")";
00140       // oh right, and invalidate fitnesses
00141     }
00142   virtual std::string className() const {return "two2oneOp";}
00143 };
00144 
00145 class three2threeOp : public eoGenOp<EOT> // :-)
00146 {
00147   public:
00148     unsigned max_production(void) { return 3; }
00149 
00150     void apply(eoPopulator<EOT>& _plop)
00151     {
00152       EOT& eo1 = *_plop; // select 1st guy
00153       EOT& eo2 = *++_plop; // select 2nd guy
00154       EOT& eo3 = *++_plop; // select 3rd guy
00155       EOT a = eo1;
00156       EOT b = eo2;
00157       EOT c = eo3;
00158       std::cout << "les selectionnes: a=" << a << " et b=" << b << " et c=" << c << std::endl;
00159       eo1.s  =  "323-1(" + a.s + ", " + b.s + ", " + c.s + ")";
00160       eo2.s  =  "323-2(" + a.s + ", " + b.s + ", " + c.s + ")";
00161       eo3.s  =  "323-3(" + a.s + ", " + b.s + ", " + c.s + ")";
00162       // oh right, and invalidate fitnesses
00163       std::cout << "les enfants: a=" << eo1 << " et b=" << eo2 << " et c=" << eo3 << std::endl;
00164     }
00165   virtual std::string className() const {return "three2threeOp";}
00166 };
00167 
00168 
00169 // dummy intialization. Re-init if no pSize, resize first if pSize
00170 void init(eoPop<Dummy> & _pop, unsigned _pSize)
00171 {
00172   if (_pSize)
00173     {
00174       _pop.resize(_pSize);
00175     }
00176   else
00177     {
00178       throw std::runtime_error("init pop with 0 size");
00179     }
00180   for (unsigned i=0; i<_pSize; i++)
00181     {
00182         std::ostringstream os;
00183       os << i << std::ends;
00184       _pop[i] = Dummy(os.str());
00185       _pop[i].fitness(i);
00186     }
00187 }
00188 
00189 // ok, now for the real work
00190 int the_main(int argc, char **argv)
00191 {
00192 
00193   eoParser parser(argc, argv);
00194   eoValueParam<unsigned int> parentSizeParam = parser.createParam(unsigned(10), "parentSize", "Parent size",'P');
00195     pSize = parentSizeParam.value(); // global variable
00196 
00197     eoValueParam<uint32_t> seedParam(time(0), "seed", "Random number seed", 'S');
00198     parser.processParam( seedParam );
00199     eo::rng.reseed(seedParam.value());
00200 
00201    // do the following AFTER ALL PARAMETERS HAVE BEEN PROCESSED
00202    // i.e. in case you need parameters somewhere else, postpone these
00203     if (parser.userNeedsHelp())
00204       {
00205         parser.printHelp(std::cout);
00206         exit(1);
00207       }
00208 
00210   monop mon("mon1");
00211   monop clone("clone");
00212   binop bin;
00213   quadop quad;
00214   quadClone quadclone;
00215 
00216   // our own operator
00217   one2threeOp o2t;
00218   two2oneOp t2o;
00219   three2threeOp t2t;
00220 
00221 
00222   // a selector
00223   eoDetTournamentSelect<EOT> select;
00224   // and a recognizable selector for testing the inbedded selector mechanism
00225   eoBestSelect<EOT> selectBest;
00226 
00227   // proportional selection between quad and bin
00228   // so we either do a quad or a bin
00229   eoProportionalOp<EOT> pOp;
00230   pOp.add(quad, 0.1);
00231   pOp.add(bin, 0.1);
00232 
00233   // sequential selection between pOp and mon
00234   eoSequentialOp<EOT> sOp;
00235   sOp.add(pOp, 0.9);
00236   sOp.add(mon, 0.1);
00237 
00238   // with one2three op
00239   eoSequentialOp<EOT> sOp2;
00240   sOp2.add(o2t, 1);
00241   //  sOp2.add(quad, 1);
00242 
00243   // with three2three op
00244   eoSequentialOp<EOT> sOp3;
00245   sOp3.add(t2t, 1);
00246 
00247 //   eoSequentialOp<EOT> sOp3;
00248 //   sOp3.add(t2o, 1);
00249 //   sOp3.add(bin, 1);
00250 //   sOp3.add(quad, 1);
00251   // try adding quads and bins to see what results you'll get
00252 
00253   // now a sequential selection that is a simple "addition"
00254   eoSequentialOp<EOT> sOpQuadPlusMon;
00255   sOpQuadPlusMon.add(quad, 1);
00256   sOpQuadPlusMon.add(mon, 1);
00257 
00258   // this corresponds
00259   eoProportionalOp<EOT> pOpSAGLike;
00260   pOpSAGLike.add(sOpQuadPlusMon, 0.24);
00261   pOpSAGLike.add(quad, 0.56);
00262   pOpSAGLike.add(mon, 0.06);
00263   pOpSAGLike.add(clone, 0.14);
00264 
00265   // init
00266   eoPop<EOT> pop;
00267   eoPop<EOT> offspring;
00268 
00269   init(pop, pSize);
00270 // sort pop so seqPopulator is identical to SelectPopulator(SequentialSelect)
00271   pop.sort();
00272   std::cout << "Population initiale\n" << pop << std::endl;
00273 
00274   // To simulate SGA: first a prop between quadOp and quadClone
00275   eoProportionalOp<EOT> pSGAOp;
00276   pSGAOp.add(quad, 0.8);
00277   pSGAOp.add(quadclone, 0.2);
00278   // sequential selection between pSGAOp and mon
00279   eoSequentialOp<EOT> virtualSGA;
00280   virtualSGA.add(pSGAOp, 1.0);
00281   virtualSGA.add(mon, 0.3);
00282 
00283   eoSeqPopulator<EOT> popit(pop, offspring);  // no selection, a copy of pop
00284 
00285   // until we filled a new population
00286   try
00287     {
00288      while (offspring.size() < pop.size())
00289            {
00290              virtualSGA(popit);
00291              std::cout << "SeqPopulator boucle et incremente\n";
00292        ++popit;
00293            }
00294     }
00295   catch(eoPopulator<EOT>::OutOfIndividuals&)
00296     {
00297       std::cout << "Warning: not enough individuals to handle\n";
00298     }
00299 
00300 
00301   std::swap(pop, offspring);
00302   offspring.clear();
00303 
00304   // ok, now print
00305   std::cout << "Apres virtualSGA \n" << pop << std::endl;
00306   init(pop, pSize);
00307 
00308   std::cout << "=========================================================\n";
00309   std::cout << "Now the eoSelectPopulator version !" << std::endl;
00310 
00311   eoSequentialSelect<EOT> seqSelect;
00312   //   select.init(); should be sorted out: is it the setup method???
00313   eoSelectivePopulator<EOT> it_step3(pop, offspring, seqSelect);
00314 
00315   while (offspring.size() < 2*pop.size())
00316   {
00317     virtualSGA(it_step3);
00318              std::cout << "SelectPopulator boucle et incremente\n";
00319     ++it_step3;
00320   }
00321 
00322   std::swap(pop, offspring);
00323   offspring.clear();
00324 
00325     // ok, now print
00326   std::cout << "Apres SGA-like eoSelectivePopulator\n" << pop << std::endl;
00327 
00328   std::cout << "=========================================================\n";
00329   std::cout << "Now the pure addition !" << std::endl;
00330 
00331   init(pop, pSize);
00332   eoSelectivePopulator<EOT> it_step4(pop, offspring, seqSelect);
00333   while (offspring.size() < 2*pop.size())
00334   {
00335     sOpQuadPlusMon(it_step4);
00336     ++it_step4;
00337   }
00338 
00339   std::swap(pop, offspring);
00340   offspring.clear();
00341 
00342     // ok, now print
00343   std::cout << "Apres Quad+Mon ds un eoSelectivePopulator\n" << pop << std::endl;
00344 
00345   // On teste 1->3
00346   init(pop, pSize);
00347   eoSelectivePopulator<EOT> it_step5(pop, offspring, seqSelect);
00348   while (offspring.size() < 2*pop.size())
00349   {
00350     sOp2(it_step5);
00351     ++it_step5;
00352   }
00353 
00354   std::swap(pop, offspring);
00355   offspring.clear();
00356 
00357     // ok, now print
00358   std::cout << "Apres 1->3 seul ds un eoSelectivePopulator\n" << pop << std::endl;
00359 
00360   // On teste 3->3
00361   init(pop, pSize);
00362   eoSelectivePopulator<EOT> it_step6(pop, offspring, seqSelect);
00363   while (offspring.size() < 2*pop.size())
00364   {
00365     sOp3(it_step6);
00366     ++it_step6;
00367   }
00368 
00369   std::swap(pop, offspring);
00370   offspring.clear();
00371 
00372     // ok, now print
00373   std::cout << "Apres 3->3 seul ds un eoSelectivePopulator\n" << pop << std::endl;
00374 
00375 
00376   return 1;
00377 }
00378 
00379 int main(int argc, char **argv)
00380 {
00381     try
00382     {
00383         the_main(argc, argv);
00384     }
00385     catch(std::exception& e)
00386     {
00387         std::cout << "Exception: " << e.what() << std::endl;
00388     }
00389 
00390 }
00391 
00392 /*
00393 If you want to build an SGA, you will need a copying quad op:
00394 
00395 class quadclone : ...
00396 {
00397   operator(EOT& a, EOT& b)
00398   {
00399     // do nothing
00400   }
00401 
00402 }
00403 
00404 Then the SGA operator will look like:
00405 
00406 quadop quad;
00407 guadclone clone;
00408 
00409 ProportionalGenOp pOp;
00410 pOp.add(quad, 0.8);
00411 pOp.add(clone, 0.2); // so 80% xover rate
00412 
00413 SequentialGenOp sOp;
00414 sOp.add(pOp, 1,0); // always try a xover (clone 20%)
00415 sOp.add(mut, 0.1); // low mutation rate
00416 
00417 will result in an algorithm with:
00418 
00419 p_xover = 0.8
00420 p_mut   = 0.1;
00421 
00422 p_reproduction = 0.2 * 0.9 = 0.18
00423 
00424 this does not add up to 1 because xover and mutation can be applied to a single indi
00425 
00426 So what do you think?
00427 
00428 */

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