# 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 */