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