evoga.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
5  * Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it> *
6  * Gianluca Massera <emmegian@yahoo.it> *
7  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the Free Software *
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
22  ********************************************************************************/
23 
24 #include "evoga.h"
25 #include "evodataviewer.h"
26 #include "logger.h"
27 #include "randomgenerator.h"
28 #include <configurationhelper.h>
29 #include <QVector>
30 #include <QThreadPool>
31 #include <QtConcurrentMap>
32 #include <QtAlgorithms>
33 #include <QTime>
34 #include <QFile>
35 
36 // All the suff below is to avoid warnings on Windows about the use of unsafe
37 // functions. This should be only a temporary workaround, the solution is stop
38 // using C string and file functions...
39 #if defined(_MSC_VER)
40  #pragma warning(push)
41  #pragma warning(disable:4996)
42 #endif
43 
44 namespace farsa {
45 
48 {
49 public:
58  m_ga(ga),
59  m_exp(exp)
60  {
61  }
62 
67  {
68  delete m_exp;
69  }
70 
76  void setGenotype(int id)
77  {
78  m_id = id;
79  m_exp->setNetParameters(m_ga->getGenes(id));
80  }
81 
87  int getGenotypeId() const
88  {
89  return m_id;
90  }
91 
95  void run()
96  {
97  m_exp->doAllTrialsForIndividual(m_id);
98  m_fitness = m_exp->getFitness();
99  }
100 
106  double getFitness() const
107  {
108  return m_fitness;
109  }
110 
117  {
118  return m_exp;
119  }
120 
121 private:
125  Evoga *const m_ga;
126 
130  EvoRobotExperiment *const m_exp;
131 
135  int m_id;
136 
140  double m_fitness;
141 };
142 
147 void runEvaluatorThreadForEvoga(EvaluatorThreadForEvoga* e)
148 {
149  e->run();
150 }
151 
157 {
161  float fitness;
162 
166  int id;
167 };
168 
172 bool operator<(FitnessAndId first, FitnessAndId second)
173 {
174  return (first.fitness < second.fitness);
175 }
176 
177 int Evoga::mrand(int i)
178 {
179  int r;
180 
181  r = rand();
182  r = r % (int) i;
183  return r;
184 
185 }
186 
188 {
189  exp = NULL;
190  mutations = NULL;
191  tfitness = NULL;
192  statfit = NULL;
193  ntfitness = NULL; //used with super ag implementation
194  loadedIndividuals = 1;
195  numThreads = 1;
196  savePopulationEachNGenerations = 0;
197  stopEvolution = false;
198  averageIndividualFitnessOverGenerations = true;
199  isStepByStep = false;
200  mutation = 0.05;
201 }
202 
204 {
205  delete exp;
206  delete[] tfitness;
207  if (statfit != NULL) {
208  for(int i = 0; i < nogenerations; i++) {
209  delete[] statfit[i];
210  }
211  }
212  delete[] statfit;
213  delete[] ntfitness;
214  delete[] mutations;
215 }
216 
217 void Evoga::setSeed(int s)
218 {
219  srand(s);
220  globalRNG->setSeed( s );
221  currentSeed = s;
222 }
223 
224 //return a random value between 0-1
225 double Evoga::drand()
226 {
227  return (double)rand()/(double)RAND_MAX;
228 }
229 
230 double Evoga::getNoise(double minn, double maxn)
231 {
232  double nrange;
233  if(maxn>minn)
234  nrange=maxn-minn;
235  else
236  nrange=minn-maxn;
237 
238  return drand()*nrange+minn;
239 }
240 
241 int Evoga::mutate(int w, double mut)
242 {
243  int b[8];
244  int val;
245  int ii;
246 
247  val = w;
248  for(ii=0;ii < 8;ii++) {
249  b[ii] = val % 2;
250  val = val / 2;
251  }
252  for(ii=0;ii < 8;ii++) {
253  //if (mrand(100) < percmut)
254  if(drand()<mut) {
255  b[ii] =(b[ii]+1)%2; // con questa modifica il bit switcha //mrand(2);
256  }
257  }
258  w = 0;
259  w += b[0] * 1;
260  w += b[1] * 2;
261  w += b[2] * 4;
262  w += b[3] * 8;
263  w += b[4] * 16;
264  w += b[5] * 32;
265  w += b[6] * 64;
266  w += b[7] * 128;
267 
268  return(w);
269 }
270 
271 void Evoga::putGenome(int fromgenome, int tobestgenome)
272 {
273  if (tobestgenome < this->nreproducing) {
274  for (int i = 0; i < this->glen; i++) {
275  bestgenome[tobestgenome][i] = genome[fromgenome][i];
276  }
277  } else {
278  Logger::error("putGenomeError!");
279  }
280 }
281 
282 void Evoga::getGenome(int frombestgenome, int togenome, int mut)
283 {
284  for(int i = 0; i < this->glen; i++) {
285  if (mut == 0) {
286  genome[togenome][i] = bestgenome[frombestgenome][i];
287  } else {
288  if (mutations[i] == Evonet::DEFAULT_VALUE) { //standard mutation
289  genome[togenome][i] = mutate(bestgenome[frombestgenome][i], mutation);
290  } else { //specific mutation
291  genome[togenome][i] = mutate(bestgenome[frombestgenome][i], mutations[i]);
292  }
293  }
294  }
295 }
296 
297 void Evoga::copyGenes(int from, int to, int mut)
298 {
299  for(int i = 0; i < this->glen; i++) {
300  if (mut == 0) {
301  genome[to][i] = genome[from][i];
302  } else {
303  if (mutations[i] == Evonet::DEFAULT_VALUE) { //standard mutation
304  genome[to][i] = mutate(genome[from][i], mutation);
305  } else { //specific mutation
306  genome[to][i] = mutate(genome[from][i], mutations[i]);
307  }
308  }
309  }
310 }
311 
312 //Reproduce individuals with higher ranking
314 {
315  //to do
316  //selecting best fathers
317  int i;
318  int bi,bx;
319  double bn;
320 
321  char sbuffer[64];
322  FILE *fp;
323 
324  //first of all we compute fitness stat
325  this->computeFStat();
326 
327 
328  for(bi=0;bi<this->nreproducing;bi++) {
329  bn=-9999.0;
330  bx=-1; //individual to be copied
331  for(i=0;i< this->popSize;i++) {
332  if(tfitness[i]>bn) {
333  bn=tfitness[i];
334  bx=i;
335  }
336  }
337 
338  this->putGenome(bx,bi);
339 
340  //here we save best genome
341  if ((bi+1)<=this->savebest && cgen< this->nogenerations) {
342  sprintf(sbuffer,"B%dS%d.gen",bi+1,this->currentSeed);
343  if (cgen==0) {
344  if ((fp=fopen(sbuffer, "w")) == NULL) {
345  Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
346  }
347  } else {
348  if ((fp=fopen(sbuffer, "a")) == NULL) {
349  Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
350  }
351  }
352 
353  fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bx);
354  saveagenotype(fp,bx);
355  fflush(fp);
356  fclose(fp);
357  }
358  tfitness[bx]=-9999.0;
359  }
360 
361  //reproducing best
362  bx=0;
363  for(bi=0;bi<this->nreproducing;bi++)
364  for(i =0;i< this->noffspring;i++) {
365  if(this->elitism && bi==0)
366  this->getGenome(bi,bx,0);
367  else
368  this->getGenome(bi,bx,1);// 1 mette mutazione
369 
370  bx++;
371  }
372 
373  //resetting fitness
374  for (i=0;i<this->popSize;i++) tfitness[i]=0.0;
375  this->saveFStat();
376  cgen++;
377 }
378 
380 {
381  //to do
382  //selecting best fathers
383  int i;
384  int bi;
385  double bn, ffit;
386  bn=-999999.0;// it was 0 possible source of bug in case of negsative fitness
387  bi=-1;
388 
389  char sbuffer[64];
390  FILE *fp;
391 
392  sprintf(sbuffer,"B%dS%d.gen",bi+1,this->currentSeed);
393  if (cgen==0) {
394  if ((fp=fopen(sbuffer, "w")) == NULL) {
395  Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
396  }
397  } else {
398  if ((fp=fopen(sbuffer, "a")) == NULL) {
399  Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
400  }
401  }
402 
403  //finding the best simply the best, one individual
404  for(i=0;i<this->popSize;i++) {
405  ffit=this->tfitness[i]/this->ntfitness[i];
406  if(ffit>bn) {
407  bn=ffit;
408  bi=i;
409  }
410  }
411 
412  //now saving
413  fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bi);
414  saveagenotype(fp,bi);
415  fflush(fp);
416  fclose(fp);
417 }
418 
419 //Reproduce individuals with higher ranking
421 {
422  //to do
423  //selecting best fathers
424  int i;
425  int bi,bx;
426  double bn;
427 
428  char sbuffer[64];
429  FILE *fp;
430 
431  //first of all we compute fitness stat
432  this->computeFStat();
433 
434 
435  for(bi=0;bi<this->nreproducing;bi++) {
436  bn=9999.0;
437  bx=-1; //individual to be copied
438  for(i=0;i< this->popSize;i++) {
439  if(tfitness[i]<bn) {
440  bn=tfitness[i];
441  bx=i;
442  }
443  }
444 
445  this->putGenome(bx,bi);
446 
447  //here we save best genome
448  if ((bi+1)<=this->savebest && cgen< this->nogenerations) {
449  sprintf(sbuffer,"B%dS%d.gen",bi+1,this->currentSeed);
450  if (cgen==0) {
451  if ((fp=fopen(sbuffer, "w")) == NULL) {
452  Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
453  }
454  } else {
455  if ((fp=fopen(sbuffer, "a")) == NULL) {
456  Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
457  }
458  }
459 
460  fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bx);
461  saveagenotype(fp,bx);
462  fflush(fp);
463  fclose(fp);
464  }
465  tfitness[bx]=9999.0;
466  }
467 
468  //reproducing best
469  bx=0;
470  for(bi=0;bi<this->nreproducing;bi++)
471  for(i =0;i< this->noffspring;i++) {
472  if(this->elitism && bi==0)
473  this->getGenome(bi,bx,0);
474  else
475  this->getGenome(bi,bx,1);
476 
477  bx++;
478  }
479 
480  //resetting fitness
481  for (i=0;i<this->popSize;i++) tfitness[i]=9999.0;
482  this->saveFStat();
483  cgen++;
484 }
485 
486 
488 {
489  for(int i = 0; i < this->popSize; i++) {
490  QString output = QString("Fit %1 | ").arg(tfitness[i]);
491  for(int l = 0; l < this->glen; l++) {
492  output += QString("%1 ").arg(this->genome[i][l]);
493  }
494  Logger::info(output);
495  }
496 }
497 
499 {
500  for(int i = 0; i < bestgenome.size(); i++) {
501  QString output = QString("Best %d | ").arg(i);
502  for (int s = 0; s < this->glen; s++) {
503  output += QString("%1 ").arg(this->bestgenome[i][s]);
504  }
505  Logger::info(output);
506  }
507 }
508 
510 {
511  int i;
512  double min, max, av;
513 
514  min=max=tfitness[0];
515  av=0.0;
516 
517  for(i=0;i<this->popSize;i++) {
518  if(tfitness[i]<min) min=tfitness[i];
519  if(tfitness[i]>max) max=tfitness[i];
520  av+=tfitness[i];
521  }
522  this->faverage=av/(double)this->popSize;
523  this->fmax=max;
524  this->fmin=min;
525  this->statfit[this->cgen][0]=this->fmax;
526  this->statfit[this->cgen][1]=this->faverage;
527  this->statfit[this->cgen][2]=this->fmin;
528 }
529 
531 {
532  int i;
533  double min, max, av;
534 
535  //min=max=tfitness[0]/ntfitness[0];
536  //try to fix a problem
537  min=9999.00;
538  max=-9999.00;
539  av=0.0;
540 
541  for(i=0;i<this->popSize;i++) {
542  if((tfitness[i]/ntfitness[i])<min) {
543  min=tfitness[i]/ntfitness[i];
544  }
545  if((tfitness[i]/ntfitness[i])>max) max=tfitness[i]/ntfitness[i];
546  av+=(tfitness[i]/ntfitness[i]);
547  }
548  this->faverage=av/(double)this->popSize;
549  this->fmax=max;
550  this->fmin=min;
551  this->statfit[this->cgen][0]=this->fmax;
552  this->statfit[this->cgen][1]=this->faverage;
553  this->statfit[this->cgen][2]=this->fmin;
554 }
555 
556 void Evoga::saveagenotype(FILE *fp, int ind)
557 {
558  int j;
559  fprintf(fp, "DYNAMICAL NN\n");
560  for (j=0; j < this->glen; j++)
561  fprintf(fp, "%d\n", this->genome[ind][j]);
562  fprintf(fp, "END\n");
563 }
564 
565 //save all current generation
567 {
568  FILE *fp;
569  char filename[64];
570  int i;
571 
572  sprintf(filename,"G%dS%d.gen",cgen,currentSeed);
573  if ((fp=fopen(filename, "w+")) == NULL) {
574  Logger::error(QString("Cannot open file %1").arg(filename));
575  } else {
576  //we save
577  for(i=0;i<this->popSize;i++) {
578  fprintf(fp,"**NET : %d_%d_%d.wts\n",cgen,0,i);
579  this->saveagenotype(fp,i);
580  }
581  fclose( fp );
582  }
583 }
584 
586 {
587  FILE *fp;
588  char sbuffer[128];
589  sprintf(sbuffer,"statS%d.fit",currentSeed);
590  if (cgen == 0)
591  fp=fopen(sbuffer , "w");
592  else
593  fp=fopen(sbuffer , "a");
594 
595  if (fp != NULL) {
596  fprintf(fp,"%.3f %.3f %.3f\n",fmax,faverage,fmin);
597  fclose(fp);
598  } else
599  Logger::error("unable to save statistics on a file");
600 }
601 
602 void Evoga::getLastFStat( double &min, double &max, double &average ) {
603  min = fmin;
604  max = fmax;
605  average = faverage;
606 }
607 
608 void Evoga::loadgenotype(FILE *fp, int ind)
609 {
610  int j;
611  int v;
612 
613  fscanf(fp, "DYNAMICAL NN\n");
614  for (j=0; j <this->glen; j++) {
615  fscanf(fp,"%d\n",&v);//this->genome[ind][j]);
616  this->genome[ind][j]=v;
617  }
618  fscanf(fp, "END\n");
619 }
620 
621 int Evoga::loadallg(int gen, const char *filew)
622 {
623  FILE *fp;
624  char filename[512];//[64];
625  char message[512];//[128];
626  char flag[512];//[64];
627 
628  if (gen >= 0) {
629  sprintf(filename, "G%dS%d.gen", gen, seed);
630  } else {
631  sprintf(filename, "%s", filew);//in case of B%P$S.gen
632  }
633 
634  if ((fp = fopen(filename, "r")) != NULL) {
635  genome.clear();
636  while (true) {
637  flag[0] = '\0'; //sprintf(flag,""); //flag = NULL;
638  fscanf(fp, "%s : %s\n", flag, message);
639  if (strcmp(flag, "**NET") == 0) {
640  loadgenotype(fp, genome.addOne());
641  } else {
642  break;
643  }
644  }
645  Logger::info(QString("Loaded ind: %1").arg(genome.size()));
646  fclose(fp);
647  } else {
648  Logger::error(QString("File %1 could not be opened").arg(filename));
649  }
650 
651  loadedIndividuals = genome.size();
652 
653  return genome.size();
654 }
655 
656 /*
657  * load a .fit file (return the number loaded individuals, 0 if the file does not exists)
658  */
659 int Evoga::loadStatistics(char *filename)
660 {
661  FILE *fp;
662  int loaded=0;
663  int i=0;
664  float max,av,min;
665  max=min=av=-1;
666  if ((fp=fopen(filename, "r")) != NULL) {
667  while(fscanf(fp,"%f %f %f\n",&max,&av,&min)!=EOF) {
668  this->statfit[i][0]=max;
669  this->statfit[i][1]=av;
670  this->statfit[i][2]=min;
671  i++;
672  }
673  loaded=i;
674  fflush(fp);
675  fclose(fp);
676  return(loaded);
677  } else {
678  return(0);
679  }
680 }
681 
683 {
684  for (int i = 0; i < genome.size(); i++) {
685  for(int g = 0; g < glen; g++) {
686  genome[i][g] = mrand(256);
687  }
688  }
689 }
690 
692 {
693  int i,g;
694 
695  //fill genome with .phe parameters
696  for(i=0; i<genome.size(); i++)
697  for(g=0; g<glen; g++)
698  {
699  if(ge[g] == Evonet::DEFAULT_VALUE)
700  genome[i][g] = mrand(256);
701  else
702  genome[i][g] = ge[g];
703  }
704 }
705 
706 void Evoga::setMutations(float* mut)
707 {
708  //fill mutation vector
709  for(int i=0; i<glen; i++)
710  mutations[i] = mut[i];
711 }
712 
713 int* Evoga::getGenes(int ind)
714 {
715 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
716  #warning CONTROLLARE INDICE? ALLE VOLTE CRASHA SE NELLA GUI SI SELEZIONA UN INDICE OLTRE IL MASSIMO
717 #endif
718  return this->genome[ind];
719 }
720 
721 int* Evoga::getBestGenes(int ind)
722 {
723  return this->bestgenome[ind];
724 }
725 
727 {
728  this->cgen=0;
729 }
730 
732 {
733  ResourcesLocker locker(this);
734 
735  Evonet* evonet = getResource<Evonet>( "evonet" );
736  if (evonet->pheFileLoaded()) {
737  //temporary mutations vector
738  Evonet* evonet = getResource<Evonet>( "evonet" );
739  float* muts = new float[evonet->freeParameters()];
740  int* pheParams = new int[evonet->freeParameters()];
741 
742  //setting the mutation vector
743  evonet->getMutations(muts); //taking it from the net
744  setMutations(muts); //pushing it inside GA
745 
746  //setting initial genome
747  evonet->copyPheParameters(pheParams); //copy *phe parameters
748  setInitialPopulation(pheParams); //put *phe parameters inside genome
749 
750  delete[] muts;
751  delete[] pheParams;
752  }
753 }
754 
756 
757  ResourcesLocker locker(this);
758  Evonet* evonet = getResource<Evonet>( "evonet" );
759 
760  float wrange = evonet->getWrange();
761 
762  for (int i = 0; i<glen; i++) {
763  genome[ind][i] = -(evonet->getFreeParameter(i)-wrange)/(2*wrange)*255;
764  }
765  /*
766  printf("%s : %d : ",__PRETTY_FUNCTION__,ind);
767  for (int i = 0; i<glen; i++) {
768  printf("%d ",genome[ind][i]);
769  }
770  printf("\n");
771  */
772 }
773 
774 /*
775  * Main function of the Genetic Algorithm (Steady State Version)
776  */
778 {
779  int rp; //replication
780  int gn; //generation
781  int id; //individuals
782  double fit;
783  double minfit=9999;
784  int minid=-1;
785  double mfit;
786  float final_mrate;
787  int startGeneration=0;
788  char statfile[128];
789  char genFile[128];
790  char filename[64];
791 
792  // Resizing genome
793  genome.resize(popSize * 2);
794 
795  final_mrate = mutation;
796  Logger::info("EVOLUTION: steady state");
797  Logger::info("Number of replications: " + QString::number(nreplications));
798 
799  // Creating evaluator objects in case of a multithread simulation. Also setting the actual number of threads used
800  QVector<EvaluatorThreadForEvoga*> evaluators(popSize, NULL);
801  if (numThreads > 1) {
802  for (int i = 0; i < evaluators.size(); i++) {
803  EvoRobotExperiment* newExp = savedConfigurationParameters.getObjectFromGroup<EvoRobotExperiment>(savedExperimentPrefix, false);
804  newExp->setEvoga(this);
805  evaluators[i] = new EvaluatorThreadForEvoga(this, newExp);
806  }
807  QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
808  }
809 
810  for(rp=0;rp<nreplications;rp++) { // replications
811  mutation=initial_mutation; // initially mutation (default 50%)
812  //setSeed(getSeed());
813  setSeed(getStartingSeed()+rp);
814  Logger::info(QString("Replication %1, seed: %2").arg(rp+1).arg(getStartingSeed()+rp));
816  randomizePop();
817  // --- section runnable only if there is an Evonet object
818  if ( hasResource( "evonet" ) ) {
820  }
821 
822  emit startingReplication( rp );
823  QTime evotimer;
824  evotimer.start();
825  for (int i=0;i<popSize+1;i++) {
826  tfitness[i]=0.0;
827  ntfitness[i]=0.0;
828  }
829  //code to recovery a previous evolution: Experimental
830  sprintf(statfile,"statS%d.fit", getStartingSeed()+rp);
831  //now check if the file exists
832  DataChunk statTest(QString("stattest"),Qt::blue,2000,false);
833  if (statTest.loadRawData(QString(statfile),0)) {
834  startGeneration=statTest.getIndex();
835  sprintf(genFile,"G%dS%d.gen",startGeneration,getStartingSeed()+rp);
836  Logger::info("Recovering from startGeneration: " + QString::number(startGeneration));
837  Logger::info(QString("Loading file: ") + genFile);
838  loadallg(startGeneration,genFile);
839  cgen=startGeneration;
840  mutation=mutation-startGeneration*mutationdecay;
841  if (mutation<final_mrate) mutation=final_mrate;
842  // Resizing genome the loading process changed the genome size = popSize
843  genome.resize(popSize * 2);
844  emit recoveredInterruptedEvolution( QString(statfile) );
845  } //end evolution recovery code
846 
847  for(gn=startGeneration;gn<nogenerations;gn++) { // generations
848  evotimer.restart();
849  Logger::info(" Generation " + QString::number(gn+1));
850  // Here we do this to avoid too many complications: if we have to run no threads, we use the old
851  // code, otherwise we go for the multithread code below
852  if (numThreads <= 1) {
853  exp->initGeneration(gn);
854  if ( commitStep() ) { return; }
855  // Not running with multiple threads, using the old code
856  for(id=0;id<popSize;id++) { //individuals
857  fit=0.0;
858  exp->setNetParameters(getGenes(id)); // get the free parameters from the genotype
859  exp->doAllTrialsForIndividual(id);
860  fit = exp->getFitness();
861  if (averageIndividualFitnessOverGenerations) {
862  tfitness[id] += fit;
863  ntfitness[id]++;
864  } else {
865  tfitness[id] = fit;
866  ntfitness[id] = 1;
867  }
868  if (isStopped()) { // stop evolution
869  return;
870  }
871  copyGenes(id, popSize,1); //generate a variation by duplicating and mutating
872  tfitness[popSize]=0;
873  ntfitness[popSize]=0;
874 
875  exp->setNetParameters(getGenes(popSize)); // get the free parameters from the genotype
876  exp->doAllTrialsForIndividual(popSize + id);
877  fit = exp->getFitness();
878  if (averageIndividualFitnessOverGenerations) {
879  tfitness[popSize] += fit;
880  ntfitness[popSize]++;
881  } else {
882  tfitness[popSize] = fit;
883  ntfitness[popSize] = 1;
884  }
885  if (isStopped()) { // stop evolution
886  return;
887  }
888 
889  // find the worst individual
890  minfit=999;
891  minid=-1;
892  for(int wi=0;wi<popSize;wi++) {
893  if (ntfitness[wi] == 0.0) {
894  continue;
895  }
896  mfit=tfitness[wi]/ntfitness[wi];
897  if(mfit<minfit) {
898  minfit=mfit;
899  minid=wi;
900  }
901  }
902  // eventually swap
903  if ((tfitness[popSize]/ntfitness[popSize])>minfit) {
904  copyGenes(popSize, minid,0);
905  tfitness[minid]=tfitness[popSize];
906  ntfitness[minid]=ntfitness[popSize];
907  }
908  }
909  exp->endGeneration(gn);
910  if ( commitStep() ) { return; }
911  } else {
912  // Multithread code
913 
914  // Calling initGeneration on all evaluator
915  for (int i = 0; i < popSize; i++) {
916  evaluators[i]->getExperiment()->initGeneration(gn);
917  }
918  if (commitStep()) return; // stop the evolution process
919 
920  // We first evaluate all parents, so setting genotypes of parents (we have as many evaluators as individuals)
921  for (int i = 0; i < popSize; i++) {
922  evaluators[i]->setGenotype(i);
923  }
924  if (commitStep()) return; // stop the evolution process
925 
926  // Now starting parallel evaluation of parents and wating for it to finish
927  QFuture<void> evaluationFuture = QtConcurrent::map(evaluators, runEvaluatorThreadForEvoga);
928  evaluationFuture.waitForFinished();
929  if (commitStep()) return; // stop the evolution process
930 
931  // We have finished evaluating parents, updating the fitness vectors
932  for (int i = 0; i < popSize; i++) {
933  if (averageIndividualFitnessOverGenerations) {
934  tfitness[evaluators[i]->getGenotypeId()] += evaluators[i]->getFitness();
935  ntfitness[evaluators[i]->getGenotypeId()]++;
936  } else {
937  tfitness[evaluators[i]->getGenotypeId()] = evaluators[i]->getFitness();
938  ntfitness[evaluators[i]->getGenotypeId()] = 1;
939  }
940  }
941  if (commitStep()) return; // stop the evolution process
942 
943  // Now we can generate all children for all individuals and set them in the evaluators
944  for (int i = 0; i < popSize; i++) {
945  copyGenes(i, popSize + i, 1); //generate a variation by duplicating and mutating
946  tfitness[popSize + i] = 0;
947  ntfitness[popSize + i] = 0;
948  evaluators[i]->setGenotype(popSize + i);
949  }
950  if (commitStep()) return; // stop the evolution process
951 
952  // Now starting parallel evaluation of children and wating for it to finish
953  evaluationFuture = QtConcurrent::map(evaluators, runEvaluatorThreadForEvoga);
954  evaluationFuture.waitForFinished();
955  if (commitStep()) return; // stop the evolution process
956 
957  // We have finished evaluating parents, updating the fitness vectors
958  for (int i = 0; i < popSize; i++) {
959  if (averageIndividualFitnessOverGenerations) {
960  tfitness[evaluators[i]->getGenotypeId()] += evaluators[i]->getFitness();
961  ntfitness[evaluators[i]->getGenotypeId()]++;
962  } else {
963  tfitness[evaluators[i]->getGenotypeId()] = evaluators[i]->getFitness();
964  ntfitness[evaluators[i]->getGenotypeId()] = 1;
965  }
966  }
967  if (commitStep()) return; // stop the evolution process
968 
969  // Calling endGeneration on all evaluator
970  for (int i = 0; i < popSize; i++) {
971  evaluators[i]->getExperiment()->endGeneration(gn);
972  }
973  if (commitStep()) return; // stop the evolution process
974 
975  // Finally, we look for the worst individuals (parents) and substitute them with best children.
976  // What we do is: we order both the parents and the children in descending order, then we take the
977  // popSize best individuals. This is not the same as what is done in the sequential version of
978  // the algorithm, but should be similar. We overwrite the worst parents with the best children
979  QVector<FitnessAndId> parents(popSize);
980  for (int i = 0; i < popSize; i++) {
981  parents[i].fitness = tfitness[i] / ntfitness[i];
982  parents[i].id = i;
983  }
984  QVector<FitnessAndId> children(popSize);
985  for (int i = 0; i < popSize; i++) {
986  children[i].fitness = tfitness[popSize + i] / ntfitness[popSize + i];
987  children[i].id = popSize + i;
988  }
989  // Sorting both parents and children. They are sorted in ascending order but we need the best
990  // individuals (those with the highest fitness) first
991  qSort(parents);
992  qSort(children);
993  int p = popSize - 1;
994  int c = popSize - 1;
995  for (int i = 0; i < popSize; i++) {
996  if (parents[p].fitness > children[c].fitness) {
997  // No need to swap, parents are already in the population vector
998  p--;
999  } else {
1000  // Swapping with one of the worst parents (we know for sure that p + c = popSize)
1001  copyGenes(children[c].id, parents[popSize - 1 - c].id, 0);
1002  tfitness[parents[popSize - 1 - c].id] = tfitness[children[c].id];
1003  ntfitness[parents[popSize - 1 - c].id] = ntfitness[children[c].id];
1004  c--;
1005  }
1006  }
1007  }
1008 
1009  saveBestInd();
1010  computeFStat2();
1011  saveFStat();
1012  emit endGeneration( cgen, fmax, faverage, fmin );
1013  if (commitStep()) {
1014  return; // stop the evolution process
1015  }
1016 
1017  cgen++;
1018  if (mutation > final_mrate) {
1019  mutation -= mutationdecay;
1020  } else {
1021  mutation = final_mrate;
1022  }
1023 
1024  //always save in order to be able to resume the evolution process, but keep only the last gen file unless it has to be saved by the param savePopulationEachNGenerations
1025  saveallg();
1026 
1027  //remove the previous genfile unless it has to be kept because of the savePopulationEachNGenerations param
1028  if ((savePopulationEachNGenerations == 0) || (gn>1 && ((gn-1) % (savePopulationEachNGenerations) != 0))) {
1029  //EX: gn 998 = G999S1.gen --- gn 999 = G1000S1.gen --- gn = 1000 = G1001S1.gen --- gn 1001 = G1002S1.gen
1030  sprintf(filename,"G%dS%d.gen",gn,currentSeed);
1031  if(!QFile::remove(filename)) {
1032  Logger::warning(QString("Error deleting temporary gen file: ") + QString::fromStdString(filename));
1033  }
1034  }
1035 
1036  Logger::info(QString("Generation %1 took %2 minutes").arg(gn+1).arg((double)evotimer.elapsed()/60000.0, 0, 'f', 2));
1037  fflush(stdout);
1038  }
1039  saveallg();
1040  }
1041 
1042  // Deleting all evaluators
1043  for (int i = 0; i < evaluators.size(); i++) {
1044  delete evaluators[i];
1045  }
1046 }
1047 
1048 /*
1049  * Main function of the Genetic Algorithm (generational version with truncation selection)
1050  */
1052 {
1053  int rp; //replication
1054  int gn; //generation
1055  int id; //individuals
1056  double fit;
1057  int startGeneration=0;
1058  char statfile[128];
1059  char genFile[128];
1060 
1061  // Resizing genome
1062  genome.resize(popSize);
1063 
1064  for(rp=0;rp<nreplications;rp++) {// replications
1065  setSeed(getStartingSeed()+rp);
1066  Logger::info(QString("Replication %1 seed: %2").arg(rp+1).arg(getStartingSeed()));
1068  randomizePop();
1069  // --- section runnable only if there is an Evonet object
1070  if ( hasResource( "evonet" ) ) {
1072  }
1073 
1074  emit startingReplication( rp );
1075  QTime evotimer;
1076  evotimer.start();
1077 
1078  //code to recovery a previous evolution: Experimental
1079  sprintf(statfile,"statS%d.fit", getStartingSeed()+rp);
1080  //now check if the file exists
1081  DataChunk statTest(QString("stattest"),Qt::blue,2000,false);
1082  if (statTest.loadRawData(QString(statfile),0)) {
1083  startGeneration=statTest.getIndex();
1084  sprintf(genFile,"G%dS%d.gen",startGeneration,getStartingSeed()+rp);
1085  Logger::info("Recovering from startGeneration: " + QString::number(startGeneration));
1086  Logger::info(QString("Loading file: ") + genFile);
1087  loadallg(startGeneration,genFile);
1088  emit recoveredInterruptedEvolution( QString(statfile) );
1089  } //end evolution recovery code
1090 
1091  for(gn=startGeneration;gn<nogenerations;gn++) { // generations
1092  evotimer.restart();
1093  Logger::info(" Generation " + QString::number(gn+1));
1094  exp->initGeneration( gn );
1095  for(id=0;id<popSize;id++) { //individuals
1096  exp->setNetParameters(getGenes(id)); // get the free parameters from the genotype
1097  exp->doAllTrialsForIndividual(id);
1098  fit = exp->getFitness();
1099  tfitness[id]=fit;
1100  if (commitStep()) { // stop evolution
1101  return;
1102  }
1103  }
1104  reproduce();
1105 
1106  emit endGeneration( gn, fmax, faverage, fmin );
1107  exp->endGeneration( gn );
1108 
1109  if(savePopulationEachNGenerations!=0 && gn%savePopulationEachNGenerations == 0)
1110  saveallg();
1111 
1112  Logger::info(QString("Generation %1 took %2 minutes").arg(gn+1).arg((double)evotimer.elapsed()/60000.0, 0, 'f', 2));
1113  fflush(stdout);
1114  }
1115 
1116  saveallg();
1117  }
1118 }
1119 
1120 
1121 // this function generate a random seed for initialize the random number generator
1122 unsigned int generateRandomSeed() {
1123  // this number is always different amongs processes because this function
1124  // is on the stack of the process
1125  unsigned long int stackMem = (unsigned long int)( generateRandomSeed );
1126  // time on which the process has been started
1127 #ifdef FARSA_WIN
1128  unsigned long int startTime = GetTickCount();
1129 #else
1130  unsigned long int startTime = time(NULL);
1131 #endif
1132  // the seed is generated mixing the values above
1133  unsigned long int randSeed = 0;
1134 
1135  stackMem=stackMem-startTime; stackMem=stackMem-randSeed; stackMem=stackMem^(randSeed >> 13);
1136  startTime=startTime-randSeed; startTime=startTime-stackMem; startTime=startTime^(stackMem << 8);
1137  randSeed=randSeed-stackMem; randSeed=randSeed-startTime; randSeed=randSeed^(startTime >> 13);
1138  stackMem=stackMem-startTime; stackMem=stackMem-randSeed; stackMem=stackMem^(randSeed >> 12);
1139  startTime=startTime-randSeed; startTime=startTime-stackMem; startTime=startTime^(stackMem << 16);
1140  randSeed=randSeed-stackMem; randSeed=randSeed-startTime; randSeed=randSeed^(startTime >> 5);
1141  stackMem=stackMem-startTime; stackMem=stackMem-randSeed; stackMem=stackMem^(randSeed >> 3);
1142  startTime=startTime-randSeed; startTime=startTime-stackMem; startTime=startTime^(stackMem << 10);
1143  randSeed=randSeed-stackMem; randSeed=randSeed-startTime; randSeed=randSeed^(startTime >> 15);
1144 
1145  return randSeed%10000;
1146 }
1147 
1148 void Evoga::configure(ConfigurationParameters& params, QString prefix)
1149 {
1150  genome.clear();
1151  bestgenome.clear();
1152 
1153  evolutionType = ConfigurationHelper::getString(params, prefix + "evolutionType", "steadyState");
1154  if ( evolutionType != "steadyState" && evolutionType != "generational" ) {
1155  Logger::error( "Evoga - evolutionType has been wrongly setted. It can assume only 'steadyState' or 'generational' values" );
1156  evolutionType = "steadyState";
1157  }
1158  nogenerations = ConfigurationHelper::getInt(params, prefix + "ngenerations", 100); //number of generations
1159  nreplications = ConfigurationHelper::getInt(params, prefix + "nreplications", 10); //number of replications
1160  nreproducing = ConfigurationHelper::getInt(params, prefix + "nreproducing", 20); //number of father
1161  noffspring = ConfigurationHelper::getInt(params, prefix + "noffspring", 5); //number of sons
1162  // starting seed - if not specified (or setted as 'auto') it auto generate a seed
1163  QString checkSeed = ConfigurationHelper::getString(params, prefix + "seed", "auto");
1164  if ( checkSeed == "auto" ) {
1165  seed = generateRandomSeed();
1166  } else {
1167  seed = checkSeed.toInt();
1168  }
1169  Logger::info( QString("Evoga - Random seed setted to ")+QString::number(seed) );
1170  //seed = ConfigurationHelper::getInt(params, prefix + "seed", 1234); //starting seed
1171  savebest = ConfigurationHelper::getInt(params, prefix + "savenbest", 1); //saving best n genotype
1172  elitism = ConfigurationHelper::getBool(params, prefix + "elitism", false); //activate elitism
1173  numThreads = ConfigurationHelper::getInt(params, prefix + "numThreads", 1); //number of concurrent threads to use
1174  savePopulationEachNGenerations = ConfigurationHelper::getInt(params, prefix + "savePopulationEachNGenerations", 0);
1175  averageIndividualFitnessOverGenerations = ConfigurationHelper::getBool(params, prefix + "averageIndividualFitnessOverGenerations", true);
1176 
1177  //mutation rate can be written both as int or as double
1178  mutation = ConfigurationHelper::getDouble(params, prefix + "mutation_rate", mutation); //mutation rate
1179  if(mutation >= 1) {
1180  mutation /= 100;
1181  }
1182  //speed of decay (only valid for steady-state GA)
1183  mutationdecay = ConfigurationHelper::getDouble(params, prefix + "mutation_decay", 0.01);
1184  initial_mutation = ConfigurationHelper::getDouble(params, prefix + "initial_mutation", 0.5);
1185 
1186  exp = params.getObjectFromGroup<EvoRobotExperiment>(prefix + "Experiment", false);
1187  exp->setEvoga(this);
1188  Logger::info( "Created EvoRobotExperiment " + params.getValue(prefix+"Experiment/type") + " from group " + prefix + "Experiment" );
1189 
1190  // Copying the ConfigurationParameters object and the prefix: we will need them to create new instances of the experiment for
1191  // multithreading evolution
1192  savedConfigurationParameters = params;
1193  savedExperimentPrefix = prefix + "Experiment";
1194 }
1195 
1197 {
1198  Logger::error("NOT IMPLEMENTED (Evoga::save)");
1199  abort();
1200 }
1201 
1202 void Evoga::describe( QString type ) {
1203  Descriptor d = addTypeDescription( type, "Implements the genetic algorithm developed by Stefano Nolfi" );
1204  d.describeEnum( "evolutionType" ).def("steadyState").values( QStringList() << "steadyState" << "generational" ).props( IsMandatory ).help("Specify the type of evolution process to execute");
1205  d.describeInt( "ngenerations" ).def(100).limits(0,MaxInteger).help("Number of generations");
1206  d.describeInt( "nreplications" ).def(10).limits(1,MaxInteger).help("The number of which the evolution process will be replicated with a different random initial population");
1207  d.describeInt( "nreproducing" ).def(20).limits(1,MaxInteger).help("The number of individual allowed to produce offsprings; The size of populazion will be nreproducing x noffspring");
1208  d.describeInt( "noffspring" ).def(5).limits(1,MaxInteger).help("The number of offsprings generated by an individual; The size of populazion will be nreproducing x noffspring");
1209  d.describeInt( "seed" ).def(1234).limits(0,MaxInteger).help("The number used to initialize the random number generator; when a new replication will start, this value will be incremented by one to guarantee a truly different initial population for the next replica");
1210  d.describeInt("savenbest").def(1).limits(1,MaxInteger).help("The number of best genotypes to save each generation");
1211  d.describeBool("elitism").def(false).help("If use elitism or not");
1212  d.describeInt("numThreads").def(1).limits(1,MaxInteger).help("The number of thread used to parallelize the evaluation of individuals");
1213  d.describeInt("savePopulationEachNGenerations").def(0).limits(0,MaxInteger).help("If is zero only the population of the last generation are saved into a file; otherwise it saves the population each N generations done");
1214  d.describeReal("mutation_rate").def(0.05).limits(0,100).help("The rate at a mutation will occur during a genotype copy; a real value below 1 (i.e. 0.12) is considered as a rate (i.e. 0.12 correspond to 12% of mutation); a value egual or above 1 is considered as a percentage of mutation (i.e. 25 correspond to 25% of mutation, or 0.25 rate of mutation)");
1215  d.describeReal("mutation_decay").def(0.01).limits(0,1).help("At first generation the mutation rate will be always 0.5, and at each generation done the mutation rate will be decreased by this value until it reachs the mutation_rate value");
1216  d.describeReal("initial_mutation").def(0.5).limits(0,1).help("The initial value of the mutation rate in case of the steadyState evolution type");
1217  d.describeSubgroup( "Experiment" ).props(IsMandatory).type("EvoRobotExperiment").help("The object delegated to simulate and to evaluate the fitness of an individual");
1218  d.describeBool("averageIndividualFitnessOverGenerations").def(true).help("Whether to average the current fitness with the previous one or not");
1219 }
1220 
1222 {
1223  // Sharing resources and declaring which ones we will access
1224  shareResourcesWith(exp);
1225  usableResources(QStringList() << "evonet");
1226 
1227  // Allocating memory
1228  tfitness = new double[MAXINDIVIDUALS];
1229  statfit = new double*[nogenerations];
1230  ntfitness = new double[MAXINDIVIDUALS]; //used with super ag implementation
1231  for(int i = 0; i < nogenerations; i++) {
1232  statfit[i] = new double[3];
1233  }
1234 
1235  //allocating memory for the mutation vector
1236  glen = exp->getGenomeLength();
1237  mutations = new float[glen];
1238  for(int mi = 0; mi < glen; mi++) {
1239  mutations[mi] = Evonet::DEFAULT_VALUE;
1240  }
1241 
1242  //now we allocate memory for genome and best genome
1243  cgen = 0;
1244  popSize = noffspring * nreproducing;
1245 
1246  //dynamic allocation of genome
1247  genome.setGenomeLength(glen);
1248  genome.resize(popSize); // An initial set of individuals just to avoid problems...
1249  for (int i = 0; i < genome.size(); i++) {
1250  for (int r = 0; r < glen; r++) {
1251  genome[i][r] = i;//mrand(256);test
1252  }
1253  }
1254 
1255  //dynamic allocation of bestgenome
1256  bestgenome.setGenomeLength(glen);
1257  bestgenome.resize(nreproducing);
1258 
1259  //resetting fitness
1260  for (int i = 0; i < MAXINDIVIDUALS; i++) {
1261  tfitness[i] = 0.0;//
1262  }
1263 
1264  for (int i = 0; i < nogenerations; i++) {
1265  statfit[i][0] = 0.0; //Average fitness of population
1266  statfit[i][1] = 0.0; //max fitness
1267  statfit[i][2] = 0.0; //min fitness
1268  }
1269 
1270  Logger::info("Evoga Configured - Number of genes: " + QString::number(glen));
1271 }
1272 
1274 {
1275  stopEvolution = false;
1276  if ( evolutionType == "steadyState" ) {
1278  } else if ( evolutionType == "generational" ) {
1280  } else {
1281  Logger::error( QString("Evoga - request to execute a unrecognized evolution type: %1").arg(evolutionType) );
1282  }
1283 }
1284 
1285 void Evoga::stop() {
1286  stopEvolution = true;
1287  waitForNextStep.wakeAll();
1288 }
1289 
1291  if ( isStepByStep && !stopEvolution ) {
1292  // will block waiting the command for going ahead
1293  mutexStepByStep.lock();
1294  waitForNextStep.wait( &mutexStepByStep );
1295  mutexStepByStep.unlock();
1296  }
1297  return stopEvolution;
1298 }
1299 
1301  return stopEvolution;
1302 }
1303 
1305  stopEvolution = false;
1306 }
1307 
1308 void Evoga::enableStepByStep( bool enable ) {
1309  isStepByStep = enable;
1310  // if disable the step-by-step it wake any eventually blocked commitStep
1311  if ( !enable ) {
1312  waitForNextStep.wakeAll();
1313  }
1314 }
1315 
1317  return isStepByStep;
1318 }
1319 
1321  waitForNextStep.wakeAll();
1322 }
1323 
1325 {
1326  return exp;
1327 }
1328 
1329 QVector<EvoRobotExperiment*> Evoga::getEvoRobotExperimentPool()
1330 {
1331  QVector<EvoRobotExperiment*> v;
1332  v.append(exp);
1333  return v;
1334 }
1335 
1337 {
1338  return cgen;
1339 }
1340 
1342 {
1343  return seed;
1344 }
1345 
1347 {
1348  return currentSeed;
1349 }
1350 
1352 {
1353  return nreplications;
1354 }
1355 
1357  return nogenerations;
1358 }
1359 
1361  return mutation;
1362 }
1363 
1364 void Evoga::setCurrentMutationRate( double mutation_rate ) {
1365  mutation = mutation_rate;
1366 }
1367 
1368 unsigned int Evoga::loadGenotypes(QString filename)
1369 {
1370  return loadallg(-1, filename.toLatin1().data());
1371 }
1372 
1373 unsigned int Evoga::numLoadedGenotypes() const
1374 {
1375  return loadedIndividuals;
1376 }
1377 
1378 int* Evoga::getGenesForIndividual(unsigned int id)
1379 {
1380  return getGenes(id);
1381 }
1382 
1383 QString Evoga::statisticsFilename(unsigned int seed)
1384 {
1385  return "statS" + QString::number(seed) + QString(".fit");
1386 }
1387 
1388 QString Evoga::bestsFilename(unsigned int seed)
1389 {
1390  return "B0S" + QString::number(seed) + QString(".gen");
1391 }
1392 
1394 {
1395  return "B0S*.gen";
1396 }
1397 
1398 QString Evoga::generationFilename(unsigned int generation, unsigned int seed)
1399 {
1400  return "G" + QString::number(generation) + "S" + QString::number(seed) + QString(".gen");
1401 }
1402 
1404 {
1405  return "G*S*.gen";
1406 }
1407 
1409 {
1410  numThreads = 1;
1411 }
1412 
1413 } // end namespace farsa
1414 
1415 // All the suff below is to restore the warning state on Windows
1416 #if defined(_MSC_VER)
1417  #pragma warning(pop)
1418 #endif