00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00036
00037
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;
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
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
00252 if(drand()<mut) {
00253 b[ii] =(b[ii]+1)%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) {
00287 genome[togenome][i] = mutate(bestgenome[frombestgenome][i], mutation);
00288 } else {
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) {
00302 genome[to][i] = mutate(genome[from][i], mutation);
00303 } else {
00304 genome[to][i] = mutate(genome[from][i], mutations[i]);
00305 }
00306 }
00307 }
00308 }
00309
00310
00311 void Evoga::reproduce()
00312 {
00313
00314
00315 int i;
00316 int bi,bx;
00317 double bn;
00318
00319 char sbuffer[64];
00320 FILE *fp;
00321
00322
00323 this->computeFStat();
00324
00325
00326 for(bi=0;bi<this->nreproducing;bi++) {
00327 bn=-9999.0;
00328 bx=-1;
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
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
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);
00367
00368 bx++;
00369 }
00370
00371
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
00380
00381 int i;
00382 int bi;
00383 double bn, ffit;
00384 bn=-999999.0;
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
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
00411 fprintf(fp,"**NET : s%d_%d.wts\n",cgen,bi);
00412 saveagenotype(fp,bi);
00413 fflush(fp);
00414 fclose(fp);
00415 }
00416
00417
00418 void Evoga::mreproduce()
00419 {
00420
00421
00422 int i;
00423 int bi,bx;
00424 double bn;
00425
00426 char sbuffer[64];
00427 FILE *fp;
00428
00429
00430 this->computeFStat();
00431
00432
00433 for(bi=0;bi<this->nreproducing;bi++) {
00434 bn=9999.0;
00435 bx=-1;
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
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
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
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
00534
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
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
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);
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];
00623 char message[512];
00624 char flag[512];
00625
00626 if (gen >= 0) {
00627 sprintf(filename, "G%dS%d.gen", gen, seed);
00628 } else {
00629 sprintf(filename, "%s", filew);
00630 }
00631
00632 if ((fp = fopen(filename, "r")) != NULL) {
00633 genome.clear();
00634 while (true) {
00635 flag[0] = '\0';
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
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
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
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
00733 Evonet* evonet = getResource<Evonet>( "evonet" );
00734 float* muts = new float[evonet->freeParameters()];
00735 int* pheParams = new int[evonet->freeParameters()];
00736
00737
00738 evonet->getMutations(muts);
00739 setMutations(muts);
00740
00741
00742 evonet->copyPheParameters(pheParams);
00743 setInitialPopulation(pheParams);
00744
00745 delete[] muts;
00746 delete[] pheParams;
00747 }
00748 }
00749
00750
00751
00752
00753 void Evoga::evolveSteadyState()
00754 {
00755 int rp;
00756 int gn;
00757 int id;
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
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
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++) {
00786 mutation=0.5;
00787
00788 setSeed(getStartingSeed()+rp);
00789 Logger::info(QString("Replication %1, seed: %2").arg(rp+1).arg(getStartingSeed()+rp));
00790 resetGenerationCounter();
00791 randomizePop();
00792
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
00805 sprintf(statfile,"statS%d.fit", getStartingSeed()+rp);
00806
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 }
00819
00820 for(gn=startGeneration;gn<nogenerations;gn++) {
00821 evotimer.restart();
00822 Logger::info(" Generation " + QString::number(gn+1));
00823
00824
00825 if (numThreads <= 1) {
00826 exp->initGeneration(gn);
00827 if ( commitStep() ) { return; }
00828
00829 for(id=0;id<popSize;id++) {
00830 fit=0.0;
00831 exp->setNetParameters(getGenes(id));
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()) {
00842 return;
00843 }
00844 copyGenes(id, popSize,1);
00845 tfitness[popSize]=0;
00846 ntfitness[popSize]=0;
00847
00848 exp->setNetParameters(getGenes(popSize));
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()) {
00859 return;
00860 }
00861
00862
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
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
00886
00887
00888 for (int i = 0; i < popSize; i++) {
00889 evaluators[i]->getExperiment()->initGeneration(gn);
00890 }
00891 if (commitStep()) return;
00892
00893
00894 for (int i = 0; i < popSize; i++) {
00895 evaluators[i]->setGenotype(i);
00896 }
00897 if (commitStep()) return;
00898
00899
00900 QFuture<void> evaluationFuture = QtConcurrent::map(evaluators, runEvaluatorThreadForEvoga);
00901 evaluationFuture.waitForFinished();
00902 if (commitStep()) return;
00903
00904
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;
00915
00916
00917 for (int i = 0; i < popSize; i++) {
00918 copyGenes(i, popSize + i, 1);
00919 tfitness[popSize + i] = 0;
00920 ntfitness[popSize + i] = 0;
00921 evaluators[i]->setGenotype(popSize + i);
00922 }
00923 if (commitStep()) return;
00924
00925
00926 evaluationFuture = QtConcurrent::map(evaluators, runEvaluatorThreadForEvoga);
00927 evaluationFuture.waitForFinished();
00928 if (commitStep()) return;
00929
00930
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;
00941
00942
00943 for (int i = 0; i < popSize; i++) {
00944 evaluators[i]->getExperiment()->endGeneration(gn);
00945 }
00946 if (commitStep()) return;
00947
00948
00949
00950
00951
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
00963
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
00971 p--;
00972 } else {
00973
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;
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
01008 for (int i = 0; i < evaluators.size(); i++) {
01009 delete evaluators[i];
01010 }
01011 }
01012
01013
01014
01015
01016 void Evoga::evolveGenerational()
01017 {
01018 int rp;
01019 int gn;
01020 int id;
01021 double fit;
01022 int startGeneration=0;
01023 char statfile[128];
01024 char genFile[128];
01025
01026
01027 genome.resize(popSize);
01028
01029 for(rp=0;rp<nreplications;rp++) {
01030 setSeed(getStartingSeed()+rp);
01031 Logger::info(QString("Replication %1 seed: %2").arg(rp+1).arg(getStartingSeed()));
01032 resetGenerationCounter();
01033 randomizePop();
01034
01035 if ( hasResource( "evonet" ) ) {
01036 getPheParametersAndMutationsFromEvonet();
01037 }
01038
01039 emit startingReplication( rp );
01040 QTime evotimer;
01041 evotimer.start();
01042
01043
01044 sprintf(statfile,"statS%d.fit", getStartingSeed()+rp);
01045
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 }
01055
01056 for(gn=startGeneration;gn<nogenerations;gn++) {
01057 evotimer.restart();
01058 Logger::info(" Generation " + QString::number(gn+1));
01059 exp->initGeneration( gn );
01060 for(id=0;id<popSize;id++) {
01061 exp->setNetParameters(getGenes(id));
01062 exp->doAllTrialsForIndividual(id);
01063 fit = exp->getFitness();
01064 tfitness[id]=fit;
01065 if (commitStep()) {
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
01087 unsigned int generateRandomSeed() {
01088
01089
01090 unsigned long int stackMem = (unsigned long int)( generateRandomSeed );
01091
01092 #ifdef FARSA_WIN
01093 unsigned long int startTime = GetTickCount();
01094 #else
01095 unsigned long int startTime = time(NULL);
01096 #endif
01097
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);
01124 nreplications = ConfigurationHelper::getInt(params, prefix + "nreplications", 10);
01125 nreproducing = ConfigurationHelper::getInt(params, prefix + "nreproducing", 20);
01126 noffspring = ConfigurationHelper::getInt(params, prefix + "noffspring", 5);
01127
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
01136 savebest = ConfigurationHelper::getInt(params, prefix + "savenbest", 1);
01137 elitism = ConfigurationHelper::getBool(params, prefix + "elitism", false);
01138 numThreads = ConfigurationHelper::getInt(params, prefix + "numThreads", 1);
01139 savePopulationEachNGenerations = ConfigurationHelper::getInt(params, prefix + "savePopulationEachNGenerations", 0);
01140 averageIndividualFitnessOverGenerations = ConfigurationHelper::getBool(params, prefix + "averageIndividualFitnessOverGenerations", true);
01141
01142
01143 mutation = ConfigurationHelper::getDouble(params, prefix + "mutation_rate", mutation);
01144 if(mutation >= 1) {
01145 mutation /= 100;
01146 }
01147 mutationdecay = ConfigurationHelper::getDouble(params, prefix + "mutation_decay", 0.01);
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
01154
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
01186 shareResourcesWith(exp);
01187 usableResources(QStringList() << "evonet");
01188
01189
01190 tfitness = new double[MAXINDIVIDUALS];
01191 statfit = new double*[nogenerations];
01192 ntfitness = new double[MAXINDIVIDUALS];
01193 for(int i = 0; i < nogenerations; i++) {
01194 statfit[i] = new double[3];
01195 }
01196
01197
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
01205 cgen = 0;
01206 popSize = noffspring * nreproducing;
01207
01208
01209 genome.setGenomeLength(glen);
01210 genome.resize(popSize);
01211 for (int i = 0; i < genome.size(); i++) {
01212 for (int r = 0; r < glen; r++) {
01213 genome[i][r] = i;
01214 }
01215 }
01216
01217
01218 bestgenome.setGenomeLength(glen);
01219 bestgenome.resize(nreproducing);
01220
01221
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;
01228 statfit[i][1] = 0.0;
01229 statfit[i][2] = 0.0;
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
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
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 }
01376
01377
01378 #if defined(_MSC_VER)
01379 #pragma warning(pop)
01380 #endif