experiments/evorobot/src/evoga.cpp

00001 /********************************************************************************
00002  *  FARSA Experiments Library                                                   *
00003  *  Copyright (C) 2007-2012                                                     *
00004  *  Stefano Nolfi <stefano.nolfi@istc.cnr.it>                                   *
00005  *  Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it>                           *
00006  *  Gianluca Massera <emmegian@yahoo.it>                                        *
00007  *  Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it>                         *
00008  *                                                                              *
00009  *  This program is free software; you can redistribute it and/or modify        *
00010  *  it under the terms of the GNU General Public License as published by        *
00011  *  the Free Software Foundation; either version 2 of the License, or           *
00012  *  (at your option) any later version.                                         *
00013  *                                                                              *
00014  *  This program is distributed in the hope that it will be useful,             *
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00017  *  GNU General Public License for more details.                                *
00018  *                                                                              *
00019  *  You should have received a copy of the GNU General Public License           *
00020  *  along with this program; if not, write to the Free Software                 *
00021  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00022  ********************************************************************************/
00023 
00024 #include "evoga.h"
00025 #include "evodataviewer.h"
00026 #include "logger.h"
00027 #include "randomgenerator.h"
00028 #include <configurationhelper.h>
00029 #include <QVector>
00030 #include <QThreadPool>
00031 #include <QtConcurrentMap>
00032 #include <QtAlgorithms>
00033 #include <QTime>
00034 
00035 // All the suff below is to avoid warnings on Windows about the use of unsafe
00036 // functions. This should be only a temporary workaround, the solution is stop
00037 // using C string and file functions...
00038 #if defined(_MSC_VER)
00039     #pragma warning(push)
00040     #pragma warning(disable:4996)
00041 #endif
00042 
00043 namespace farsa {
00044 
00046 class EvaluatorThreadForEvoga
00047 {
00048 public:
00056     EvaluatorThreadForEvoga(Evoga *ga, EvoRobotExperiment *exp) :
00057         m_ga(ga),
00058         m_exp(exp)
00059     {
00060     }
00061 
00065     ~EvaluatorThreadForEvoga()
00066     {
00067         delete m_exp;
00068     }
00069 
00075     void setGenotype(int id)
00076     {
00077         m_id = id;
00078         m_exp->setNetParameters(m_ga->getGenes(id));
00079     }
00080 
00086     int getGenotypeId() const
00087     {
00088         return m_id;
00089     }
00090 
00094     void run()
00095     {
00096         m_exp->doAllTrialsForIndividual(m_id);
00097         m_fitness = m_exp->getFitness();
00098     }
00099 
00105     double getFitness() const
00106     {
00107         return m_fitness;
00108     }
00109 
00115     EvoRobotExperiment* getExperiment()
00116     {
00117         return m_exp;
00118     }
00119 
00120 private:
00124     Evoga *const m_ga;
00125 
00129     EvoRobotExperiment *const m_exp;
00130 
00134     int m_id;
00135 
00139     double m_fitness;
00140 };
00141 
00146 void runEvaluatorThreadForEvoga(EvaluatorThreadForEvoga* e)
00147 {
00148     e->run();
00149 }
00150 
00155 struct FitnessAndId
00156 {
00160     float fitness;
00161 
00165     int id;
00166 };
00167 
00171 bool operator<(FitnessAndId first, FitnessAndId second)
00172 {
00173     return (first.fitness < second.fitness);
00174 }
00175 
00176 int Evoga::mrand(int i)
00177 {
00178     int r;
00179 
00180     r = rand();
00181     r = r % (int) i;
00182     return r;
00183 
00184 }
00185 
00186 Evoga::Evoga()
00187 {
00188     exp = NULL;
00189     mutations = NULL;
00190     tfitness = NULL;
00191     statfit = NULL;
00192     ntfitness = NULL; //used with super ag implementation
00193     loadedIndividuals = 1;
00194     numThreads = 1;
00195     savePopulationEachNGenerations = 0;
00196     stopEvolution = false;
00197     averageIndividualFitnessOverGenerations = true;
00198     isStepByStep = false;
00199 }
00200 
00201 Evoga::~Evoga()
00202 {
00203     delete exp;
00204     delete[] tfitness;
00205     if (statfit != NULL) {
00206         for(int i = 0; i < nogenerations; i++) {
00207             delete[] statfit[i];
00208         }
00209     }
00210     delete[] statfit;
00211     delete[] ntfitness;
00212     delete[] mutations;
00213 }
00214 
00215 void Evoga::setSeed(int s)
00216 {
00217     srand(s);
00218     globalRNG->setSeed( s );
00219     currentSeed = s;
00220 }
00221 
00222 //return a random value between 0-1
00223 double Evoga::drand()
00224 {
00225     return (double)rand()/(double)RAND_MAX;
00226 }
00227 
00228 double Evoga::getNoise(double minn, double maxn)
00229 {
00230     double nrange;
00231     if(maxn>minn)
00232         nrange=maxn-minn;
00233     else
00234         nrange=minn-maxn;
00235 
00236     return drand()*nrange+minn;
00237 }
00238 
00239 int Evoga::mutate(int w, double mut)
00240 {
00241     int b[8];
00242     int val;
00243     int ii;
00244 
00245     val = w;
00246     for(ii=0;ii < 8;ii++) {
00247         b[ii] = val % 2;
00248         val  = val / 2;
00249     }
00250     for(ii=0;ii < 8;ii++) {
00251         //if (mrand(100) < percmut)
00252         if(drand()<mut) {
00253             b[ii] =(b[ii]+1)%2; // con questa modifica il bit switcha //mrand(2);
00254         }
00255     }
00256     w = 0;
00257     w += b[0] * 1;
00258     w += b[1] * 2;
00259     w += b[2] * 4;
00260     w += b[3] * 8;
00261     w += b[4] * 16;
00262     w += b[5] * 32;
00263     w += b[6] * 64;
00264     w += b[7] * 128;
00265  
00266     return(w);
00267 }
00268 
00269 void Evoga::putGenome(int fromgenome, int tobestgenome)
00270 {
00271     if (tobestgenome < this->nreproducing) {
00272         for (int i = 0; i < this->glen; i++) {
00273             bestgenome[tobestgenome][i] = genome[fromgenome][i];
00274         }
00275     } else {
00276         Logger::error("putGenomeError!");
00277     }
00278 }
00279 
00280 void Evoga::getGenome(int frombestgenome, int togenome, int mut)
00281 {
00282     for(int i = 0; i < this->glen; i++) {
00283         if (mut == 0) {
00284             genome[togenome][i] = bestgenome[frombestgenome][i];
00285         } else {
00286             if (mutations[i] == Evonet::DEFAULT_VALUE) {    //standard mutation
00287                 genome[togenome][i] = mutate(bestgenome[frombestgenome][i], mutation);
00288             } else {                //specific mutation
00289                 genome[togenome][i] = mutate(bestgenome[frombestgenome][i], mutations[i]);
00290             }
00291         }
00292     }
00293 }
00294 
00295 void Evoga::copyGenes(int from, int to, int mut)
00296 {
00297     for(int i = 0; i < this->glen; i++) {
00298         if (mut == 0) {
00299             genome[to][i] = genome[from][i];
00300         } else {
00301             if (mutations[i] == Evonet::DEFAULT_VALUE) {    //standard mutation
00302                 genome[to][i] = mutate(genome[from][i], mutation);
00303             } else {                //specific mutation
00304                 genome[to][i] = mutate(genome[from][i], mutations[i]);
00305             }
00306         }
00307     }
00308 }
00309 
00310 //Reproduce individuals with higher ranking
00311 void Evoga::reproduce()
00312 {
00313     //to do
00314     //selecting best fathers
00315     int i;
00316     int bi,bx;
00317     double bn;
00318 
00319     char sbuffer[64];
00320     FILE *fp;
00321 
00322     //first of all we compute fitness stat
00323     this->computeFStat();
00324 
00325 
00326     for(bi=0;bi<this->nreproducing;bi++) {
00327         bn=-9999.0;
00328         bx=-1; //individual to be copied
00329         for(i=0;i< this->popSize;i++) {
00330             if(tfitness[i]>bn) {
00331                 bn=tfitness[i];
00332                 bx=i;
00333             }
00334         }
00335 
00336         this->putGenome(bx,bi);
00337 
00338         //here we save best genome
00339         if ((bi+1)<=this->savebest && cgen< this->nogenerations) {
00340             sprintf(sbuffer,"B%dS%d.gen",bi+1,this->currentSeed);
00341             if (cgen==0) {
00342                 if ((fp=fopen(sbuffer, "w")) == NULL) {
00343                     Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
00344                 }
00345             } else {
00346                 if ((fp=fopen(sbuffer, "a")) == NULL) {
00347                     Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
00348                 }
00349             }
00350 
00351             fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bx);
00352             saveagenotype(fp,bx);
00353             fflush(fp);
00354             fclose(fp);
00355         }
00356         tfitness[bx]=-9999.0;
00357     }
00358 
00359     //reproducing best
00360     bx=0;
00361     for(bi=0;bi<this->nreproducing;bi++)
00362         for(i =0;i< this->noffspring;i++) {
00363             if(this->elitism && bi==0)
00364                 this->getGenome(bi,bx,0);
00365             else
00366                 this->getGenome(bi,bx,1);// 1 mette mutazione
00367 
00368             bx++;
00369         }
00370 
00371     //resetting fitness
00372     for (i=0;i<this->popSize;i++) tfitness[i]=0.0;
00373     this->saveFStat();
00374     cgen++;
00375 }
00376 
00377 void Evoga::saveBestInd()
00378 {
00379     //to do
00380     //selecting best fathers
00381     int i;
00382     int bi;
00383     double bn, ffit;
00384     bn=-999999.0;// it was 0 possible source of bug in case of negsative fitness
00385     bi=-1;
00386 
00387     char sbuffer[64];
00388     FILE *fp;
00389 
00390     sprintf(sbuffer,"B%dS%d.gen",bi+1,this->currentSeed);
00391     if (cgen==0) {
00392         if ((fp=fopen(sbuffer, "w")) == NULL) {
00393             Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
00394         }
00395     } else {
00396         if ((fp=fopen(sbuffer, "a")) == NULL) {
00397             Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
00398         }
00399     }
00400 
00401     //finding the best simply the best, one individual
00402     for(i=0;i<this->popSize;i++) {
00403         ffit=this->tfitness[i]/this->ntfitness[i];
00404         if(ffit>bn) {
00405             bn=ffit;
00406             bi=i;
00407         }
00408     }
00409 
00410     //now saving
00411     fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bi);
00412     saveagenotype(fp,bi);
00413     fflush(fp);
00414     fclose(fp);
00415 }
00416 
00417 //Reproduce individuals with higher ranking
00418 void Evoga::mreproduce()
00419 {
00420     //to do
00421     //selecting best fathers
00422     int i;
00423     int bi,bx;
00424     double bn;
00425 
00426     char sbuffer[64];
00427     FILE *fp;
00428 
00429     //first of all we compute fitness stat
00430     this->computeFStat();
00431 
00432 
00433     for(bi=0;bi<this->nreproducing;bi++) {
00434         bn=9999.0;
00435         bx=-1; //individual to be copied
00436         for(i=0;i< this->popSize;i++) {
00437             if(tfitness[i]<bn) {
00438                 bn=tfitness[i];
00439                 bx=i;
00440             }
00441         }
00442     
00443         this->putGenome(bx,bi);
00444     
00445         //here we save best genome
00446         if ((bi+1)<=this->savebest && cgen< this->nogenerations) {
00447             sprintf(sbuffer,"B%dS%d.gen",bi+1,this->currentSeed);
00448             if (cgen==0) {
00449                 if ((fp=fopen(sbuffer, "w")) == NULL) {
00450                     Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
00451                 }
00452             } else {
00453                 if ((fp=fopen(sbuffer, "a")) == NULL) {
00454                     Logger::error(QString("I cannot open file B%1S%2.gen").arg(bi+1).arg(this->currentSeed));
00455                 }
00456             }
00457 
00458             fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bx);
00459             saveagenotype(fp,bx);
00460             fflush(fp);
00461             fclose(fp);
00462         }
00463         tfitness[bx]=9999.0;
00464     }
00465 
00466     //reproducing best
00467     bx=0;
00468     for(bi=0;bi<this->nreproducing;bi++)
00469         for(i =0;i< this->noffspring;i++) {
00470             if(this->elitism && bi==0)
00471                 this->getGenome(bi,bx,0);
00472             else
00473                 this->getGenome(bi,bx,1);
00474 
00475             bx++;
00476         }
00477 
00478     //resetting fitness
00479     for (i=0;i<this->popSize;i++) tfitness[i]=9999.0;
00480     this->saveFStat();
00481     cgen++;
00482 }
00483 
00484 
00485 void Evoga::printPop()
00486 {
00487     for(int i = 0; i < this->popSize; i++) {
00488         QString output = QString("Fit %1 | ").arg(tfitness[i]);
00489         for(int l = 0; l < this->glen; l++) {
00490             output += QString("%1 ").arg(this->genome[i][l]);
00491         }
00492         Logger::info(output);
00493     }
00494 }
00495 
00496 void Evoga::printBest()
00497 {
00498     for(int i = 0; i < bestgenome.size(); i++) {
00499         QString output = QString("Best %d | ").arg(i);
00500         for (int s = 0; s < this->glen; s++) {
00501             output += QString("%1 ").arg(this->bestgenome[i][s]);
00502         }
00503         Logger::info(output);
00504     }
00505 }
00506 
00507 void Evoga::computeFStat()
00508 {
00509     int i;
00510     double min, max, av;
00511 
00512     min=max=tfitness[0];
00513     av=0.0;
00514 
00515     for(i=0;i<this->popSize;i++) {
00516         if(tfitness[i]<min) min=tfitness[i];
00517         if(tfitness[i]>max) max=tfitness[i];
00518         av+=tfitness[i];
00519     }
00520     this->faverage=av/(double)this->popSize;
00521     this->fmax=max;
00522     this->fmin=min;
00523     this->statfit[this->cgen][0]=this->fmax;
00524     this->statfit[this->cgen][1]=this->faverage;
00525     this->statfit[this->cgen][2]=this->fmin;
00526 }
00527 
00528 void Evoga::computeFStat2()
00529 {
00530     int i;
00531     double min, max, av;
00532 
00533     //min=max=tfitness[0]/ntfitness[0];
00534     //try to fix a problem
00535     min=9999.00;
00536     max=-9999.00;
00537     av=0.0;
00538 
00539     for(i=0;i<this->popSize;i++) {
00540         if((tfitness[i]/ntfitness[i])<min) {
00541             min=tfitness[i]/ntfitness[i];
00542         }
00543         if((tfitness[i]/ntfitness[i])>max) max=tfitness[i]/ntfitness[i];
00544         av+=(tfitness[i]/ntfitness[i]);
00545     }
00546     this->faverage=av/(double)this->popSize;
00547     this->fmax=max;
00548     this->fmin=min;
00549     this->statfit[this->cgen][0]=this->fmax;
00550     this->statfit[this->cgen][1]=this->faverage;
00551     this->statfit[this->cgen][2]=this->fmin;
00552 }
00553 
00554 void Evoga::saveagenotype(FILE *fp, int ind)
00555 {
00556     int j;
00557     fprintf(fp, "DYNAMICAL NN\n");
00558     for (j=0; j < this->glen; j++)
00559         fprintf(fp, "%d\n", this->genome[ind][j]);
00560     fprintf(fp, "END\n");
00561 }
00562 
00563 //save all current generation
00564 void Evoga::saveallg()
00565 {
00566     FILE *fp;
00567     char filename[64];
00568     int i;
00569 
00570     sprintf(filename,"G%dS%d.gen",cgen,currentSeed);
00571     if ((fp=fopen(filename, "w+")) == NULL) {
00572         Logger::error(QString("Cannot open file %1").arg(filename));
00573     } else {
00574         //we save
00575         for(i=0;i<this->popSize;i++) {
00576             fprintf(fp,"**NET : %d_%d_%d.wts\n",cgen,0,i);
00577             this->saveagenotype(fp,i);
00578         }
00579         fclose( fp );
00580     }
00581 }
00582 
00583 void Evoga::saveFStat()
00584 {
00585     FILE *fp;
00586     char sbuffer[128];
00587     sprintf(sbuffer,"statS%d.fit",currentSeed);
00588         if (cgen == 0)
00589         fp=fopen(sbuffer , "w");
00590     else
00591         fp=fopen(sbuffer , "a");
00592 
00593     if (fp != NULL) {
00594         fprintf(fp,"%.3f %.3f %.3f\n",fmax,faverage,fmin);
00595         fclose(fp);
00596     } else
00597         Logger::error("unable to save statistics on a file");
00598 }
00599 
00600 void Evoga::getLastFStat( double &min, double &max, double &average ) {
00601     min = fmin;
00602     max = fmax;
00603     average = faverage;
00604 }
00605 
00606 void Evoga::loadgenotype(FILE *fp, int ind)
00607 {
00608     int j;
00609     int v;
00610 
00611     fscanf(fp, "DYNAMICAL NN\n");
00612     for (j=0; j <this->glen; j++) {
00613         fscanf(fp,"%d\n",&v);//this->genome[ind][j]);
00614         this->genome[ind][j]=v;
00615     }
00616     fscanf(fp, "END\n");
00617 }
00618 
00619 int Evoga::loadallg(int gen, const char *filew)
00620 {
00621     FILE *fp;
00622     char filename[512];//[64];
00623     char message[512];//[128];
00624     char flag[512];//[64];
00625 
00626     if (gen >= 0) {
00627         sprintf(filename, "G%dS%d.gen", gen, seed);
00628     } else {
00629         sprintf(filename, "%s", filew);//in case of B%P$S.gen
00630     }
00631 
00632     if ((fp = fopen(filename, "r")) != NULL) {
00633         genome.clear();
00634         while (true) {
00635             flag[0] = '\0'; //sprintf(flag,""); //flag = NULL;
00636             fscanf(fp, "%s : %s\n", flag, message);
00637             if (strcmp(flag, "**NET") == 0) {
00638                 loadgenotype(fp, genome.addOne());
00639             } else {
00640                 break;
00641             }
00642         }
00643         Logger::info(QString("Loaded ind: %1").arg(genome.size()));
00644         fclose(fp);
00645     } else {
00646         Logger::error(QString("File %1 could not be opened").arg(filename));
00647     }
00648 
00649     loadedIndividuals = genome.size();
00650 
00651     return genome.size();
00652 }
00653 
00654 /*
00655  * load a .fit file (return the number loaded individuals, 0 if the file does not exists)
00656  */
00657 int Evoga::loadStatistics(char *filename)
00658 {
00659     FILE *fp;
00660     int loaded=0;
00661     int i=0;
00662     float max,av,min;
00663     max=min=av=-1;
00664     if ((fp=fopen(filename, "r")) != NULL) {
00665         while(fscanf(fp,"%f %f %f\n",&max,&av,&min)!=EOF) {
00666             this->statfit[i][0]=max;
00667             this->statfit[i][1]=av;
00668             this->statfit[i][2]=min;
00669             i++;
00670         }
00671         loaded=i; 
00672         fflush(fp);
00673         fclose(fp);
00674         return(loaded);
00675     } else {
00676         return(0);
00677     }
00678 }
00679 
00680 void Evoga::randomizePop()
00681 {
00682     for (int i = 0; i < genome.size(); i++) {
00683         for(int g = 0; g < glen; g++) {
00684             genome[i][g] = mrand(256);
00685         }
00686     }
00687 }
00688 
00689 void Evoga::setInitialPopulation(int* ge)
00690 {
00691     int i,g;
00692 
00693     //fill genome with .phe parameters
00694     for(i=0; i<genome.size(); i++)
00695         for(g=0; g<glen; g++)
00696         {
00697             if(ge[g] == Evonet::DEFAULT_VALUE)
00698                 genome[i][g] = mrand(256);
00699             else
00700                 genome[i][g] = ge[g];
00701         }
00702 }
00703 
00704 void Evoga::setMutations(float* mut)
00705 {
00706     //fill mutation vector
00707     for(int i=0; i<glen; i++)
00708         mutations[i] = mut[i];
00709 }
00710 
00711 int* Evoga::getGenes(int ind)
00712 {
00713     return this->genome[ind];
00714 }
00715 
00716 int* Evoga::getBestGenes(int ind)
00717 {
00718     return this->bestgenome[ind];
00719 }
00720 
00721 void Evoga::resetGenerationCounter()
00722 {
00723     this->cgen=0;
00724 }
00725 
00726 void Evoga::getPheParametersAndMutationsFromEvonet()
00727 {
00728     ResourcesLocker locker(this);
00729 
00730     Evonet* evonet = getResource<Evonet>( "evonet" );
00731     if (evonet->pheFileLoaded()) {
00732         //temporary mutations vector
00733         Evonet* evonet = getResource<Evonet>( "evonet" );
00734         float* muts = new float[evonet->freeParameters()];
00735         int* pheParams = new int[evonet->freeParameters()];
00736 
00737         //setting the mutation vector
00738         evonet->getMutations(muts); //taking it from the net
00739         setMutations(muts);     //pushing it inside GA
00740 
00741         //setting initial genome
00742         evonet->copyPheParameters(pheParams);   //copy *phe parameters
00743         setInitialPopulation(pheParams);            //put *phe parameters inside genome
00744 
00745         delete[] muts;
00746         delete[] pheParams;
00747     }
00748 }
00749 
00750 /*
00751  * Main function of the Genetic Algorithm (Steady State Version)
00752  */
00753 void Evoga::evolveSteadyState()
00754 {
00755     int rp; //replication
00756     int gn; //generation
00757     int id; //individuals
00758     double fit;
00759     double minfit=9999;
00760     int    minid=-1;
00761     double mfit;
00762     float  final_mrate;
00763     int startGeneration=0;
00764     char statfile[128];
00765     char genFile[128];
00766 
00767     // Resizing genome
00768     genome.resize(popSize * 2);
00769 
00770     final_mrate = mutation;
00771     Logger::info("EVOLUTION: steady state");
00772     Logger::info("Number of replications: " + QString::number(nreplications));
00773 
00774     // Creating evaluator objects in case of a multithread simulation. Also setting the actual number of threads used
00775     QVector<EvaluatorThreadForEvoga*> evaluators(popSize, NULL);
00776     if (numThreads > 1) {
00777         for (int i = 0; i < evaluators.size(); i++) {
00778             EvoRobotExperiment* newExp = savedConfigurationParameters.getObjectFromGroup<EvoRobotExperiment>(savedExperimentPrefix, false);
00779             newExp->setEvoga(this);
00780             evaluators[i] = new EvaluatorThreadForEvoga(this, newExp);
00781         }
00782         QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
00783     }
00784 
00785     for(rp=0;rp<nreplications;rp++) {   // replications
00786         mutation=0.5; // initially mutation rate is set to 50%
00787         //setSeed(getSeed());
00788         setSeed(getStartingSeed()+rp);
00789         Logger::info(QString("Replication %1, seed: %2").arg(rp+1).arg(getStartingSeed()+rp));
00790         resetGenerationCounter();
00791         randomizePop();
00792         // --- section runnable only if there is an Evonet object
00793         if ( hasResource( "evonet" ) ) {
00794             getPheParametersAndMutationsFromEvonet();
00795         }
00796 
00797         emit startingReplication( rp );
00798         QTime evotimer;
00799         evotimer.start();
00800         for (int i=0;i<popSize+1;i++) {
00801             tfitness[i]=0.0;
00802             ntfitness[i]=0.0;
00803         }
00804         //code to recovery a previous evolution: Experimental
00805         sprintf(statfile,"statS%d.fit", getStartingSeed()+rp);
00806         //now check if the file exists
00807         DataChunk statTest(QString("stattest"),Qt::blue,2000,false);
00808         if (statTest.loadRawData(QString(statfile),0)) {
00809             startGeneration=statTest.getIndex();
00810             sprintf(genFile,"G%dS%d.gen",startGeneration,getStartingSeed()+rp);
00811             Logger::info("Recovering from startGeneration: " + QString::number(startGeneration));
00812             Logger::info(QString("Loading file: ") + genFile);
00813             loadallg(startGeneration,genFile);
00814             cgen=startGeneration;
00815             mutation=mutation-startGeneration*mutationdecay;
00816             if (mutation<final_mrate) mutation=final_mrate;
00817             emit recoveredInterruptedEvolution( QString(statfile) );
00818         } //end evolution recovery code
00819 
00820         for(gn=startGeneration;gn<nogenerations;gn++) { // generations
00821             evotimer.restart();
00822             Logger::info(" Generation " + QString::number(gn+1));
00823             // Here we do this to avoid too many complications: if we have to run no threads, we use the old
00824             // code, otherwise we go for the multithread code below
00825             if (numThreads <= 1) {
00826                 exp->initGeneration(gn);
00827                 if ( commitStep() ) { return; }
00828                 // Not running with multiple threads, using the old code
00829                 for(id=0;id<popSize;id++) { //individuals
00830                     fit=0.0;
00831                     exp->setNetParameters(getGenes(id)); // get the free parameters from the genotype
00832                     exp->doAllTrialsForIndividual(id);
00833                     fit = exp->getFitness();
00834                     if (averageIndividualFitnessOverGenerations) {
00835                         tfitness[id] += fit;
00836                         ntfitness[id]++;
00837                     } else {
00838                         tfitness[id] = fit;
00839                         ntfitness[id] = 1;
00840                     }
00841                     if (isStopped()) { // stop evolution
00842                         return;
00843                     }
00844                     copyGenes(id, popSize,1); //generate a variation by duplicating and mutating
00845                     tfitness[popSize]=0;
00846                     ntfitness[popSize]=0;
00847 
00848                     exp->setNetParameters(getGenes(popSize)); // get the free parameters from the genotype
00849                     exp->doAllTrialsForIndividual(popSize + id);
00850                     fit = exp->getFitness();
00851                     if (averageIndividualFitnessOverGenerations) {
00852                         tfitness[popSize] += fit;
00853                         ntfitness[popSize]++;
00854                     } else {
00855                         tfitness[popSize] = fit;
00856                         ntfitness[popSize] = 1;
00857                     }
00858                     if (isStopped()) { // stop evolution
00859                         return;
00860                     }
00861 
00862                     // find the worst individual
00863                     minfit=999;
00864                     minid=-1;
00865                     for(int wi=0;wi<popSize;wi++) {
00866                         if (ntfitness[wi] == 0.0) {
00867                             continue;
00868                         }
00869                         mfit=tfitness[wi]/ntfitness[wi];
00870                         if(mfit<minfit) {
00871                             minfit=mfit;
00872                             minid=wi;
00873                         }
00874                     }
00875                     // eventually swap
00876                     if ((tfitness[popSize]/ntfitness[popSize])>minfit) {
00877                         copyGenes(popSize, minid,0);
00878                         tfitness[minid]=tfitness[popSize];
00879                         ntfitness[minid]=ntfitness[popSize];
00880                     }
00881                 }
00882                 exp->endGeneration(gn);
00883                 if ( commitStep() ) { return; }
00884             } else {
00885                 // Multithread code
00886 
00887                 // Calling initGeneration on all evaluator
00888                 for (int i = 0; i < popSize; i++) {
00889                     evaluators[i]->getExperiment()->initGeneration(gn);
00890                 }
00891                 if (commitStep()) return; // stop the evolution process
00892 
00893                 // We first evaluate all parents, so setting genotypes of parents (we have as many evaluators as individuals)
00894                 for (int i = 0; i < popSize; i++) {
00895                     evaluators[i]->setGenotype(i);
00896                 }
00897                 if (commitStep()) return; // stop the evolution process
00898 
00899                 // Now starting parallel evaluation of parents and wating for it to finish
00900                 QFuture<void> evaluationFuture = QtConcurrent::map(evaluators, runEvaluatorThreadForEvoga);
00901                 evaluationFuture.waitForFinished();
00902                 if (commitStep()) return; // stop the evolution process
00903 
00904                 // We have finished evaluating parents, updating the fitness vectors
00905                 for (int i = 0; i < popSize; i++) {
00906                     if (averageIndividualFitnessOverGenerations) {
00907                         tfitness[evaluators[i]->getGenotypeId()] += evaluators[i]->getFitness();
00908                         ntfitness[evaluators[i]->getGenotypeId()]++;
00909                     } else {
00910                         tfitness[evaluators[i]->getGenotypeId()] = evaluators[i]->getFitness();
00911                         ntfitness[evaluators[i]->getGenotypeId()] = 1;
00912                     }
00913                 }
00914                 if (commitStep()) return; // stop the evolution process
00915 
00916                 // Now we can generate all children for all individuals and set them in the evaluators
00917                 for (int i = 0; i < popSize; i++) {
00918                     copyGenes(i, popSize + i, 1); //generate a variation by duplicating and mutating
00919                     tfitness[popSize + i] = 0;
00920                     ntfitness[popSize + i] = 0;
00921                     evaluators[i]->setGenotype(popSize + i);
00922                 }
00923                 if (commitStep()) return; // stop the evolution process
00924 
00925                 // Now starting parallel evaluation of children and wating for it to finish
00926                 evaluationFuture = QtConcurrent::map(evaluators, runEvaluatorThreadForEvoga);
00927                 evaluationFuture.waitForFinished();
00928                 if (commitStep()) return; // stop the evolution process
00929 
00930                 // We have finished evaluating parents, updating the fitness vectors
00931                 for (int i = 0; i < popSize; i++) {
00932                     if (averageIndividualFitnessOverGenerations) {
00933                         tfitness[evaluators[i]->getGenotypeId()] += evaluators[i]->getFitness();
00934                         ntfitness[evaluators[i]->getGenotypeId()]++;
00935                     } else {
00936                         tfitness[evaluators[i]->getGenotypeId()] = evaluators[i]->getFitness();
00937                         ntfitness[evaluators[i]->getGenotypeId()] = 1;
00938                     }
00939                 }
00940                 if (commitStep()) return; // stop the evolution process
00941 
00942                 // Calling endGeneration on all evaluator
00943                 for (int i = 0; i < popSize; i++) {
00944                     evaluators[i]->getExperiment()->endGeneration(gn);
00945                 }
00946                 if (commitStep()) return; // stop the evolution process
00947 
00948                 // Finally, we look for the worst individuals (parents) and substitute them with best children.
00949                 // What we do is: we order both the parents and the children in descending order, then we take the
00950                 // popSize best individuals. This is not the same as what is done in the sequential version of
00951                 // the algorithm, but should be similar. We overwrite the worst parents with the best children
00952                 QVector<FitnessAndId> parents(popSize);
00953                 for (int i = 0; i < popSize; i++) {
00954                     parents[i].fitness = tfitness[i] / ntfitness[i];
00955                     parents[i].id = i;
00956                 }
00957                 QVector<FitnessAndId> children(popSize);
00958                 for (int i = 0; i < popSize; i++) {
00959                     children[i].fitness = tfitness[popSize + i] / ntfitness[popSize + i];
00960                     children[i].id = popSize + i;
00961                 }
00962                 // Sorting both parents and children. They are sorted in ascending order but we need the best
00963                 // individuals (those with the highest fitness) first
00964                 qSort(parents);
00965                 qSort(children);
00966                 int p = popSize - 1;
00967                 int c = popSize - 1;
00968                 for (int i = 0; i < popSize; i++) {
00969                     if (parents[p].fitness > children[c].fitness) {
00970                         // No need to swap, parents are already in the population vector
00971                         p--;
00972                     } else {
00973                         // Swapping with one of the worst parents (we know for sure that p + c = popSize)
00974                         copyGenes(children[c].id, parents[popSize - 1 - c].id, 0);
00975                         tfitness[parents[popSize - 1 - c].id] = tfitness[children[c].id];
00976                         ntfitness[parents[popSize - 1 - c].id] = ntfitness[children[c].id];
00977                         c--;
00978                     }
00979                 }
00980             }
00981 
00982             saveBestInd();
00983             computeFStat2();
00984             saveFStat();
00985             emit endGeneration( cgen, fmax, faverage, fmin );
00986             if (commitStep()) {
00987                 return; // stop the evolution process
00988             }
00989 
00990             cgen++;
00991             if (mutation > final_mrate) {
00992                 mutation -= mutationdecay;
00993             } else {
00994                 mutation = final_mrate;
00995             }
00996 
00997             if ((savePopulationEachNGenerations != 0) && (gn % savePopulationEachNGenerations == 0)) {
00998                 saveallg();
00999             }
01000 
01001             Logger::info(QString("Generation %1 took %2 minutes").arg(gn+1).arg((double)evotimer.elapsed()/60000.0, 0, 'f', 2));
01002             fflush(stdout);
01003         }
01004         saveallg();
01005     }
01006 
01007     // Deleting all evaluators
01008     for (int i = 0; i < evaluators.size(); i++) {
01009         delete evaluators[i];
01010     }
01011 }
01012 
01013 /*
01014  * Main function of the Genetic Algorithm (generational version with truncation selection)
01015  */
01016 void Evoga::evolveGenerational()
01017 {
01018     int rp; //replication
01019     int gn; //generation
01020     int id; //individuals
01021     double fit;
01022     int startGeneration=0;
01023     char statfile[128];
01024     char genFile[128];
01025 
01026     // Resizing genome
01027     genome.resize(popSize);
01028 
01029     for(rp=0;rp<nreplications;rp++) {// replications
01030         setSeed(getStartingSeed()+rp);
01031         Logger::info(QString("Replication %1 seed: %2").arg(rp+1).arg(getStartingSeed()));
01032         resetGenerationCounter();
01033         randomizePop();
01034         // --- section runnable only if there is an Evonet object
01035         if ( hasResource( "evonet" ) ) {
01036             getPheParametersAndMutationsFromEvonet();
01037         }
01038 
01039         emit startingReplication( rp );
01040         QTime evotimer;
01041         evotimer.start();
01042 
01043         //code to recovery a previous evolution: Experimental
01044         sprintf(statfile,"statS%d.fit", getStartingSeed()+rp);
01045         //now check if the file exists
01046         DataChunk statTest(QString("stattest"),Qt::blue,2000,false);
01047         if (statTest.loadRawData(QString(statfile),0)) {
01048             startGeneration=statTest.getIndex();
01049             sprintf(genFile,"G%dS%d.gen",startGeneration,getStartingSeed()+rp);
01050             Logger::info("Recovering from startGeneration: " + QString::number(startGeneration));
01051             Logger::info(QString("Loading file: ") + genFile);
01052             loadallg(startGeneration,genFile);
01053             emit recoveredInterruptedEvolution( QString(statfile) );
01054         } //end evolution recovery code
01055 
01056         for(gn=startGeneration;gn<nogenerations;gn++) { // generations
01057             evotimer.restart();
01058             Logger::info(" Generation " + QString::number(gn+1));
01059             exp->initGeneration( gn );
01060             for(id=0;id<popSize;id++) { //individuals
01061                 exp->setNetParameters(getGenes(id)); // get the free parameters from the genotype
01062                 exp->doAllTrialsForIndividual(id);
01063                 fit = exp->getFitness();
01064                 tfitness[id]=fit;
01065                 if (commitStep()) { // stop evolution
01066                     return;
01067                 }
01068             }
01069             reproduce();
01070 
01071             emit endGeneration( gn, fmax, faverage, fmin );
01072             exp->endGeneration( gn );
01073 
01074             if(savePopulationEachNGenerations!=0 && gn%savePopulationEachNGenerations == 0)
01075                 saveallg();
01076 
01077             Logger::info(QString("Generation %1 took %2 minutes").arg(gn+1).arg((double)evotimer.elapsed()/60000.0, 0, 'f', 2));
01078             fflush(stdout);
01079         }
01080 
01081         saveallg();
01082     }
01083 }
01084 
01085 
01086 // this function generate a random seed for initialize the random number generator
01087 unsigned int generateRandomSeed() {
01088     // this number is always different amongs processes because this function
01089     // is on the stack of the process
01090     unsigned long int stackMem = (unsigned long int)( generateRandomSeed );
01091     // time on which the process has been started
01092 #ifdef FARSA_WIN
01093     unsigned long int startTime = GetTickCount();
01094 #else
01095     unsigned long int startTime = time(NULL);
01096 #endif
01097     // the seed is generated mixing the values above
01098     unsigned long int randSeed = 0;
01099     
01100     stackMem=stackMem-startTime;  stackMem=stackMem-randSeed;  stackMem=stackMem^(randSeed >> 13);
01101     startTime=startTime-randSeed;  startTime=startTime-stackMem;  startTime=startTime^(stackMem << 8); 
01102     randSeed=randSeed-stackMem;  randSeed=randSeed-startTime;  randSeed=randSeed^(startTime >> 13);
01103     stackMem=stackMem-startTime;  stackMem=stackMem-randSeed;  stackMem=stackMem^(randSeed >> 12);
01104     startTime=startTime-randSeed;  startTime=startTime-stackMem;  startTime=startTime^(stackMem << 16);
01105     randSeed=randSeed-stackMem;  randSeed=randSeed-startTime;  randSeed=randSeed^(startTime >> 5);
01106     stackMem=stackMem-startTime;  stackMem=stackMem-randSeed;  stackMem=stackMem^(randSeed >> 3);
01107     startTime=startTime-randSeed;  startTime=startTime-stackMem;  startTime=startTime^(stackMem << 10);
01108     randSeed=randSeed-stackMem;  randSeed=randSeed-startTime;  randSeed=randSeed^(startTime >> 15);
01109     
01110     return randSeed%10000;
01111 }
01112 
01113 void Evoga::configure(ConfigurationParameters& params, QString prefix)
01114 {
01115     genome.clear();
01116     bestgenome.clear();
01117 
01118     evolutionType = ConfigurationHelper::getString(params, prefix + "evolutionType", "steadyState");
01119     if ( evolutionType != "steadyState" && evolutionType != "generational" ) {
01120         Logger::error( "Evoga - evolutionType has been wrongly setted. It can assume only 'steadyState' or 'generational' values" );
01121         evolutionType = "steadyState";
01122     }
01123     nogenerations = ConfigurationHelper::getInt(params, prefix + "ngenerations", 100); //number of generations
01124     nreplications = ConfigurationHelper::getInt(params, prefix + "nreplications", 10); //number of replications
01125     nreproducing = ConfigurationHelper::getInt(params, prefix + "nreproducing", 20); //number of father
01126     noffspring = ConfigurationHelper::getInt(params, prefix + "noffspring", 5); //number of sons
01127     // starting seed - if not specified (or setted as 'auto') it auto generate a seed
01128     QString checkSeed = ConfigurationHelper::getString(params, prefix + "seed", "auto");
01129     if ( checkSeed == "auto" ) {
01130         seed = generateRandomSeed();
01131     } else {
01132         seed = checkSeed.toInt();
01133     }
01134     Logger::info( QString("Evoga - Random seed setted to ")+QString::number(seed) );
01135     //seed = ConfigurationHelper::getInt(params, prefix + "seed", 1234); //starting seed
01136     savebest = ConfigurationHelper::getInt(params, prefix + "savenbest", 1); //saving best n genotype
01137     elitism = ConfigurationHelper::getBool(params, prefix + "elitism", false); //activate elitism
01138     numThreads = ConfigurationHelper::getInt(params, prefix + "numThreads", 1); //number of concurrent threads to use
01139     savePopulationEachNGenerations = ConfigurationHelper::getInt(params, prefix + "savePopulationEachNGenerations", 0);
01140     averageIndividualFitnessOverGenerations = ConfigurationHelper::getBool(params, prefix + "averageIndividualFitnessOverGenerations", true);
01141 
01142     //mutation rate can be written both as int or as double
01143     mutation = ConfigurationHelper::getDouble(params, prefix + "mutation_rate", mutation); //mutation rate
01144     if(mutation >= 1) {
01145         mutation /= 100;
01146     }
01147     mutationdecay = ConfigurationHelper::getDouble(params, prefix + "mutation_decay", 0.01);    //speed of decay (only valid for steady-state GA)
01148 
01149     exp = params.getObjectFromGroup<EvoRobotExperiment>(prefix + "Experiment", false);
01150     exp->setEvoga(this);
01151     Logger::info( "Created EvoRobotExperiment " + params.getValue(prefix+"Experiment/type") + " from group " + prefix + "Experiment" );
01152 
01153     // Copying the ConfigurationParameters object and the prefix: we will need them to create new instances of the experiment for
01154     // multithreading evolution
01155     savedConfigurationParameters = params;
01156     savedExperimentPrefix = prefix + "Experiment";
01157 }
01158 
01159 void Evoga::save(ConfigurationParameters&, QString)
01160 {
01161     Logger::error("NOT IMPLEMENTED (Evoga::save)");
01162     abort();
01163 }
01164 
01165 void Evoga::describe( QString type ) {
01166     Descriptor d = addTypeDescription( type, "Implements the genetic algorithm developed by Stefano Nolfi" );
01167     d.describeEnum( "evolutionType" ).def("steadyState").values( QStringList() << "steadyState" << "generational" ).props( IsMandatory ).help("Specify the type of evolution process to execute");
01168     d.describeInt( "ngenerations" ).def(100).limits(0,MaxInteger).help("Number of generations");
01169     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");
01170     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");
01171     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");
01172     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");
01173     d.describeInt("savenbest").def(1).limits(1,MaxInteger).help("The number of best genotypes to save each generation");
01174     d.describeBool("elitism").def(false).help("If use elitism or not");
01175     d.describeInt("numThreads").def(1).limits(1,MaxInteger).help("The number of thread used to parallelize the evaluation of individuals");
01176     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");
01177     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)");
01178     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");
01179     d.describeSubgroup( "Experiment" ).props(IsMandatory).type("EvoRobotExperiment").help("The object delegated to simulate and to evaluate the fitness of an individual");
01180     d.describeBool("averageIndividualFitnessOverGenerations").def(true).help("Whether to average the current fitness with the previous one or not");
01181 }
01182 
01183 void Evoga::postConfigureInitialization()
01184 {
01185     // Sharing resources and declaring which ones we will access
01186     shareResourcesWith(exp);
01187     usableResources(QStringList() << "evonet");
01188 
01189     // Allocating memory
01190     tfitness = new double[MAXINDIVIDUALS];
01191     statfit = new double*[nogenerations];
01192     ntfitness = new double[MAXINDIVIDUALS]; //used with super ag implementation
01193     for(int i = 0; i < nogenerations; i++) {
01194         statfit[i] = new double[3];
01195     }
01196 
01197     //allocating memory for the mutation vector
01198     glen = exp->getGenomeLength();
01199     mutations = new float[glen];
01200     for(int mi = 0; mi < glen; mi++) {
01201         mutations[mi] = Evonet::DEFAULT_VALUE;
01202     }
01203 
01204     //now we allocate memory for genome and best genome
01205     cgen = 0;
01206     popSize = noffspring * nreproducing;
01207 
01208     //dynamic allocation of genome
01209     genome.setGenomeLength(glen);
01210     genome.resize(popSize); // An initial set of individuals just to avoid problems...
01211     for (int i = 0; i < genome.size(); i++) {
01212         for (int r = 0; r < glen; r++) {
01213             genome[i][r] = i;//mrand(256);test
01214         }
01215     }
01216 
01217     //dynamic allocation of bestgenome
01218     bestgenome.setGenomeLength(glen);
01219     bestgenome.resize(nreproducing);
01220 
01221     //resetting fitness
01222     for (int i = 0; i < MAXINDIVIDUALS; i++) {
01223         tfitness[i] = 0.0;//
01224     }
01225 
01226     for (int i = 0; i < nogenerations; i++) {
01227         statfit[i][0] = 0.0; //Average fitness of population
01228         statfit[i][1] = 0.0; //max fitness
01229         statfit[i][2] = 0.0; //min fitness
01230     }
01231 
01232     Logger::info("Evoga Configured - Number of genes: " + QString::number(glen));
01233 }
01234 
01235 void Evoga::evolveAllReplicas()
01236 {
01237     stopEvolution = false;
01238     if ( evolutionType == "steadyState" ) {
01239         evolveSteadyState();
01240     } else if ( evolutionType == "generational" ) {
01241         evolveGenerational();
01242     } else {
01243         Logger::error( QString("Evoga - request to execute a unrecognized evolution type: %1").arg(evolutionType) );
01244     }
01245 }
01246 
01247 void Evoga::stop() {
01248     stopEvolution = true;
01249     waitForNextStep.wakeAll();
01250 }
01251 
01252 bool Evoga::commitStep() {
01253     if ( isStepByStep && !stopEvolution ) {
01254         // will block waiting the command for going ahead
01255         mutexStepByStep.lock();
01256         waitForNextStep.wait( &mutexStepByStep );
01257         mutexStepByStep.unlock();
01258     }
01259     return stopEvolution;
01260 }
01261 
01262 bool Evoga::isStopped() {
01263     return stopEvolution;
01264 }
01265 
01266 void Evoga::resetStop() {
01267     stopEvolution = false;
01268 }
01269 
01270 void Evoga::enableStepByStep( bool enable ) {
01271     isStepByStep = enable;
01272     // if disable the step-by-step it wake any eventually blocked commitStep
01273     if ( !enable ) {
01274         waitForNextStep.wakeAll();
01275     }
01276 }
01277 
01278 bool Evoga::isEnabledStepByStep() {
01279     return isStepByStep;
01280 }
01281 
01282 void Evoga::doNextStep() {
01283     waitForNextStep.wakeAll();
01284 }
01285 
01286 EvoRobotExperiment* Evoga::getEvoRobotExperiment()
01287 {
01288     return exp;
01289 }
01290 
01291 QVector<EvoRobotExperiment*> Evoga::getEvoRobotExperimentPool()
01292 {
01293     QVector<EvoRobotExperiment*> v;
01294     v.append(exp);
01295     return v;
01296 }
01297 
01298 unsigned int Evoga::currentGeneration()
01299 {
01300     return cgen;
01301 }
01302 
01303 unsigned int Evoga::getStartingSeed()
01304 {
01305     return seed;
01306 }
01307 
01308 unsigned int Evoga::getCurrentSeed()
01309 {
01310     return currentSeed;
01311 }
01312 
01313 unsigned int Evoga::getNumReplications()
01314 {
01315     return nreplications;
01316 }
01317 
01318 unsigned int Evoga::getNumOfGenerations() {
01319     return nogenerations;
01320 }
01321 
01322 double Evoga::getCurrentMutationRate() {
01323     return mutation;
01324 }
01325 
01326 void Evoga::setCurrentMutationRate( double mutation_rate ) {
01327     mutation = mutation_rate;
01328 }
01329 
01330 unsigned int Evoga::loadGenotypes(QString filename)
01331 {
01332     return loadallg(-1, filename.toAscii().data());
01333 }
01334 
01335 unsigned int Evoga::numLoadedGenotypes() const
01336 {
01337     return loadedIndividuals;
01338 }
01339 
01340 int* Evoga::getGenesForIndividual(unsigned int id)
01341 {
01342     return getGenes(id);
01343 }
01344 
01345 QString Evoga::statisticsFilename(unsigned int seed)
01346 {
01347     return "statS" + QString::number(seed) + QString(".fit");
01348 }
01349 
01350 QString Evoga::bestsFilename(unsigned int seed)
01351 {
01352     return "B0S" + QString::number(seed) + QString(".gen");
01353 }
01354 
01355 QString Evoga::bestsFilename()
01356 {
01357     return "B0S*.gen";
01358 }
01359 
01360 QString Evoga::generationFilename(unsigned int generation, unsigned int seed)
01361 {
01362     return "G" + QString::number(generation) + "S" + QString::number(seed) + QString(".gen");
01363 }
01364 
01365 QString Evoga::generationFilename()
01366 {
01367     return "G*S*.gen";
01368 }
01369 
01370 void Evoga::doNotUseMultipleThreads()
01371 {
01372     numThreads = 1;
01373 }
01374 
01375 } // end namespace farsa
01376 
01377 // All the suff below is to restore the warning state on Windows
01378 #if defined(_MSC_VER)
01379     #pragma warning(pop)
01380 #endif