//tries to add a set of candidate solutions the repository if it is non-dominated //param - the candidate solutions to be inserted in the repository void Repository::add(Repository &rep){ if(rep.getActualSize()+actualSize > repositorySize){ fprintf(stderr,"\nWARNING repository already contains %d solutions, you are trying to add more %d. The total size is %d, the maximum size is %d\n", actualSize, rep.getActualSize(), actualSize+rep.getActualSize(), repositorySize); } for(int s=0;s<rep.getActualSize();s++){ add(rep.getSolutions()[s]); } }
void myLearn(Swarm &sw){ int N=decisionNumber, hsig; double oldMean[N], initialStds[N], BDz[N]; double muEff, cc, muCov, cCov, trace=0.0, chiN; cSigma=0; dSigma=0; //double sigma, C[N][N], pC[N], pSigma[N], D[N], mean[N], B[N][N]; //****************** treating the input data ********************// Repository repTemp; //gathering the solutions to be used to learn and putting them on repTemp if(decomposition){ mergeNeighboringRepositories(repTemp, sw); }else{ repTemp.initialize(archSubSwarms, sw.getSize()+sw.repository.getActualSize()); if(!strcmp(solSet, "population") || !strcmp(solSet, "both")) for(int i=0;i<sw.getSize();i++) if(!sw.particles[i].solution.dominated) repTemp.add(sw.particles[i].solution); if(!strcmp(solSet, "repository") || repTemp.getActualSize()==0 || !strcmp(solSet, "both")) repTemp.add(sw.repository); } repTemp.organize(); // if(!strcmp(archSubSwarms, "p-ideal") || !strcmp(archSubSwarms, "w-ideal") || !strcmp(archSubSwarms, "r-ideal")){ if(decomposition){ updateWeightedDistances(repTemp.getSolutions(), repTemp.getActualSize(), sw.repository.weight); std::sort(repTemp.getSolutions(), repTemp.getSolutions()+repTemp.getActualSize(), weightedDistanceComparatorSol); }else{ if(!strcmp(cmaRanking, "cd")){ updateCrowdingDistances(repTemp.getSolutions(), repTemp.getActualSize()); std::sort(repTemp.getSolutions(), repTemp.getSolutions()+repTemp.getActualSize(), crowdingComparatorSol); } if(!strcmp(cmaRanking, "hv")){ updateContributingHypervolume(repTemp); //stores in the crowding distance field, since both are the higher the contribution, the better, there is no problem std::sort(repTemp.getSolutions(), repTemp.getSolutions()+repTemp.getActualSize(), crowdingComparatorSol); } if(!strcmp(cmaRanking, "r2")){ if(refSize==-1){ perror("ERROR ON CMA-ES R2 RANKING! Reference file not set."); } updateContributingR2(repTemp); //stores in the crowding distance field, stores in the crowding distance field //if the value of the r2 increase after I take this solution, it is important, so the higher is the contribution, the better std::sort(repTemp.getSolutions(), repTemp.getSolutions()+repTemp.getActualSize(), crowdingComparatorSol); } } //normalizing non dominated solutions double nonDominated[repTemp.getActualSize()][N]; int nonDom=0; // for(int i=0;i<repTemp.getActualSize()/2;i++){ for(int i=0;i<repTemp.getActualSize();i++){ // printVector(repTemp.getSolution(i).decisionVector, decisionNumber); // printVector(repTemp.getSolution(i).objectiveVector, objectiveNumber); // printf("sol:%d: %e\n", i, repTemp.getSolution(i).crowdingDistance); for(int j=0;j<N;j++) nonDominated[nonDom][j]=normalize(repTemp.getSolution(i).decisionVector[j], inferiorPositionLimit[j], superiorPositionLimit[j]); nonDom++; //mu } int mu = nonDom; double weights[mu]; //**************************** end of treatment of input data***************// /***************setting default parameters according to****************/ //https://www.lri.fr/~hansen/hansenedacomparing.pdf // in my strategy lambda = mu = solSize double weightSquare=0, weightSum=0, value=0; double smaller=MAXDOUBLE, larger=-MAXDOUBLE; if(mu > 2){ if(!strcmp(weightDistribution, "metric")){ //uses the value of the ranking metric as weight for(int i=mu-1;i>=0;i--){// find the smaller > 0 if(decomposition){ value=repTemp.getSolution(i).weightedDistance; if(value < MAXDOUBLE){ larger=value; break; } } else{ value=repTemp.getSolution(i).crowdingDistance; if(value > 0){ //a little higher than 0 smaller=value; break; } } } for(int i=0;i<mu;i++){ //find the larger < MAXDOUBLE if(decomposition){ value=repTemp.getSolution(i).weightedDistance; if(value > 0){ //a little higher than 0 smaller=value; break; } } else{ value=repTemp.getSolution(i).crowdingDistance; if(value < MAXDOUBLE){ larger=value; break; } } } if(larger == -MAXDOUBLE || smaller == MAXDOUBLE){ fprintf(stderr, "\nERROR ON ASSIGNING WEIGHTS FOR CMA-ES!!\n"); fprintf(stderr, "\nsm: %f lg: %f mu: %d\n", smaller, larger, mu); exit(1); } } }else{ larger=1; smaller=0; } for(int i=0;i<mu;i++){ if(!strcmp(weightDistribution, "equal")) weights[i]=1.0; //equal weight distribution if(!strcmp(weightDistribution, "log")) weights[i]=log(mu+1)-log(i+1.0); //according to code if(!strcmp(weightDistribution, "linear")) weights[i]=mu-i; //according to code if(!strcmp(weightDistribution, "metric")){ //uses the value of the ranking metric as weight if(decomposition){ value=repTemp.getSolution(i).weightedDistance; weights[i]=1-(normalize(value, (smaller-(smaller/100.0)), larger)); }else{ value=repTemp.getSolution(i).crowdingDistance; weights[i]=(normalize(value, (smaller-(smaller/100.0)), larger)); } // weights[i]=exp(normalize(repTemp.getSolution(i).crowdingDistance, smaller, larger)); // if(repTemp.getSolution(i).crowdingDistance<=0) // weights[i]=exp(0); // if(repTemp.getSolution(i).crowdingDistance>=MAXDOUBLE) // weights[i]=exp(1); // weights[i]=(normalize(value, (smaller-(smaller/100.0)), larger)); if(weights[i]<= 0) weights[i]=normalize(smaller, (smaller-(smaller/100.0)), larger);//weights[i-1]/2.0; if(weights[i]>1) weights[i]=1; // weights[i]=log(1+weights[i]); } weightSum+=weights[i]; //sum of the weights for posterior normalization } for(int i=0;i<mu;i++){ //normalization of the weights weightSquare+=weights[i]*weights[i]; weights[i]/=weightSum; // printf("\n %f - %f",repTemp.getSolution(i).weightedDistance, weights[i]); } // muEff=1.0/weightSquare;//paper muEff=weightSum*weightSum/weightSquare;//code cSigma= (muEff+2.0)/(N+muEff+3.0); //code // cSigma= (muEff+2.0)/(N+muEff+5.0); //paper dSigma= (1.0 + 2.0*std::max(0.0, sqrt((muEff-1.0)/(N+1.0)) - 1.0)) * std::max(0.3, 1.0 -(double)N / (1e-6+maxIterations)) + cSigma;//code // dSigma= 1.0+ 2.0*( std::max(0.0, sqrt( (muEff-1.0)/(N+1.0) )-1.0 )) +cSigma; //paper cc= 4.0/(N+4.0); //code // cc= (4.0+(muEff/N))/ (N+4.0+(2.0*muEff/N)); //paper muCov=muEff; // cCov=((1.0/muCov)*(2.0/( (N+sqrt(2.0))*(N+sqrt(2.0)) )))+((1.0- (1.0/muCov))*std::min(1.0, ((2.0*muEff)-1.0)/( ((N+2.0)*(N+2.0))+muEff ) )); //paper (probably more precise) double t1 = 2.0 / ((N+1.4142)*(N+1.4142)); double t2 = (2.0*muEff-1.) / ((N+2.0)*(N+2.0)+muEff); t2 = (t2 > 1) ? 1 : t2; t2 = (1.0/muCov) * t1 + (1.0-1.0/muCov) * t2; cCov = t2; //code chiN = sqrt((double) N) * (1.0 - 1.0/(4.0*N) + 1./(21.0*N*N)); /***************setting default parameters ****************/ if(sw.init){ for (int i = 0; i < N; ++i){ //avoid memory garbage for (int j = 0; j < N; j++) sw.B[i][j]=0.0; //need to keep sw.B[i][i]=1.0; //need to keep initialStds[i] = 0.3; //does not change //code trace += initialStds[i]*initialStds[i]; //does not change } sw.sigma=sqrt(trace/N); //need to keep for (int i = 0; i < N; ++i){ //avoid memory garbage for (int j = 0; j < N; j++) sw.C[i][j]=0.0; //need to keep sw.pC[i] = sw.pSigma[i] = 0.0; //need to keep // sw.mean[i]=0.5; //need to keep // sw.mean[i]=normalize(sw.centroid[i], inferiorPositionLimit[i], superiorPositionLimit[i]); if(sw.gen>0) sw.mean[i]=(rand()/(double)RAND_MAX);//already initialized within the swarm, when restart does not need to restart, does it? } for (int i = 0; i < N; ++i) { sw.C[i][i] = sw.D[i] = initialStds[i] * sqrt(N / trace); //need to keep sw.C[i][i] *= sw.C[i][i]; //need to keep } sw.gen=0; sw.init=false; if(logCMAES) printf("\n INIT \n"); // cmaes_init(&evo, decisionNumber, NULL, NULL, 0, mu, "cmaes_initials.par"); // printf("\nlambda: %d\n",evo.sp.lambda); }else sw.gen++; //exit(1); //******************************************// //http://arxiv.org/pdf/1110.4181v1.pdf https://hal.inria.fr/hal-01146738/document //injecting external solutions into moead sw.solsKept=0; double clipped[mu][N], in[N], t[N]; for (int i = 0; i < N; i++) oldMean[i]=sw.mean[i]; for(int s=0;s<mu;s++){ //for all solutions bool injected=true; for(int r=0;r<sw.getSize();r++){//check if the current solution is in the population from the previous generation, otherwise it was injected for(int d=0;d<N;d++) t[d]=normalize(sw.particles[r].solution.decisionVector[d], inferiorPositionLimit[d], superiorPositionLimit[d]); if(isEqual(nonDominated[s],t,N)){//if this solution is in the population, it is not injected injected=false; sw.solsKept++; } } for (int i = 0; i < N; i++)// eq(2) turning x_i into y_i in[i]=(nonDominated[s][i]-oldMean[i])/sw.sigma; if(injected){//first step eq(3) : y_i <-- clip(cy,||C^{-1/2}y_i||) double sum, tmp[N], sum2=0; for (int i = 0; i < N; i++) { sum=0; for (int j = 0; j < N; ++j) sum += sw.B[j][i]*in[i];//B^T*y_i tmp[i] = sum / sw.D[i]; //B^T*y_i*D^-1 } for (int i = 0; i < N; i++) { sum=0; for (int j = 0; j < N; ++j) sum += sw.B[i][j] * tmp[j];//B^T*y_i*B*D^-1 sum2+=sum*sum; } sum2=sqrt(sum2); double cy=sqrt(N)+((2*N)/N+2); double clip=cy/sum2; //clip(c,x) = min(1,c/x) clip=std::min(1.0,clip); // double * in = nonDominated[s];//x_i // double sum2=0;//C^{-1/2} * y_i // for (int i = 0; i < N; ++i) { // double sum = 0.0; // for (int j = 0; j < N; ++j) // sum += sw.B[i][j] * sw.D[i] * ((in[i]-oldMean[i])/sw.sigma ); //y_i // sum2+=sum*sum; // } // sum2=sqrt(sum2); // double cy=sqrt(N)+((2*N)/N+2); // double clip=cy/sum2; //clip(c,x) = min(1,c/x) // clip=std::min(1.0,clip); // printf(" -- %f %f %f\n----------------------\n",sum2, cy, clip); for (int i = 0; i < N; ++i) clipped[s][i]=in[i]*clip; }else for (int i = 0; i < N; ++i) clipped[s][i]=in[i]; }//end of first step, clipping y_i //second step: \Delta m //As far as I understood, the differentiation in eq (4) is optional, to be used only if we want a strong impact with an injection, it is not used in the MOEA/D-CMA-ES paper, and is not going to be used here. double deltaM[N]; for (int i = 0; i < N; ++i){ //update of the delta mean using the second part of eq (4) deltaM[i]=0; for(int j=0;j<mu;++j) deltaM[i]+=weights[j]*clipped[j][i]; }//end of delta m update //mean update eq(5) double cm=1; for (int i = 0; i < N; ++i) sw.mean[i]=oldMean[i]+cm*sw.sigma*deltaM[i]; //end of mean update // // //delta mean clip eq(6), but only if strong injection of mean shift, we do not use this // // if(injected){ // // double * in = deltaM;//deltaM // // double sum, tmp[N], sum2=0; // // for (int i = 0; i < N; i++) { // // sum=0; // // for (int j = 0; j < N; ++j) // // sum += sw.B[j][i]*in[i];//B^T*deltaM // // tmp[i] = sum / sw.D[i]; //B^T*deltaM*D^-1 // // } // // for (int i = 0; i < N; i++) { // // sum=0; // // for (int j = 0; j < N; ++j) // // sum += sw.B[i][j] * tmp[j];//B^T*deltaM*B*D^-1 // // sum2+=sum*sum; // // } // // sum2=sqrt(sum2); // // double cym=sqrt(2*N)+((2*N)/N+2); // // double clip=cym/(sqrt(muEff)*sum2); //clip(c,x) = min(1,c/x) // // clip=std::min(1.0,clip); // // for (int i = 0; i < N; ++i) // // deltaM[i]*=clip;//if not injected, deltaM keeps the same // // } // // //end of the delta mean clip //Equations 7 and 9 were updated by changing the BDz calculation, now it is sqrt(muEff)*deltaM //Equation 8 is a little different, but there is no apparent reason for it, so we did not change it yet //Equation 10 is changed in the cov matrix //Equation 11 is changed in the sigma update //------------------------------------------------------------// // for (int i = 0; i < N; ++i) {//update of the mean and BDz //original CMA-ES update // oldMean[i]=sw.mean[i]; // sw.mean[i]=0; // for(int j=0;j<mu;++j) // sw.mean[i]+=weights[j]*nonDominated[j][i]; // in the paper sw.mean = m ;; y_w = (mean-oldMean)/sigma // BDz[i] = sqrt(muEff)*(sw.mean[i] - oldMean[i])/sw.sigma; // BDz * sqrt(muEff) = y_w * sqrt(muEff) // } for (int i = 0; i < N; ++i)//BDz with deltaM, as in the paper of injecting solutions into CMA-ES BDz[i]=sqrt(muEff)*deltaM[i]; // if(decomposition && sw.neighborhood[0].index==swarmNumber/2){//if the first neighbor of it (itself) is zero // double sum=0; // for(int i=0;i<N;i++) // sum+=abs(sw.mean[i]-oldMean[i]); // printf("%d -- %f\n",repTemp.getActualSize(), sw.sigma); // for(int i=0;i<mu;i++){ // // printf("%f -- ", repTemp.getSolution(i).weightedDistance); // for(int d=0;d<N;d++){ // printf("%.4f ", nonDominated[i][d]); // // printf("%.4f ", repTemp.getSolution(i).decisionVector[d]); // } // printf(" (%.4f)\n", getScalarValue(repTemp.getSolution(i).objectiveVector, sw.repository.weight)); // } // printf("-----------------------------------------\ncovMat:\n"); // for(int i=0;i<N;i++){ // for(int j=0;j<N;j++) // printf("%.4f ",sw.C[i][j]); // printf("\n"); // } // printf("---------------------------------------\n"); // printf("mean: "); // for(int d=0;d<N;d++){ // // printf("%.4f ", sw.mean[i]); // printf("%.4f ", sw.mean[d]); // } // printf("\nbest: "); // for(int d=0;d<N;d++){ // printf("%.4f ", normalize(sw.repository.getSolution(0).decisionVector[d], inferiorPositionLimit[d], superiorPositionLimit[d]) ); // } // printf("\n---------------------------------------------------\n"); // } double sum, tmp[N], psxps=0.0; //calculate z := D^(-1) * B^(-1) * BDz into tmp // orignal comment for (int i = 0; i < N; i++) { sum=0; for (int j = 0; j < N; ++j) sum += sw.B[j][i] * BDz[j]; tmp[i] = sum / sw.D[i]; //tmp = z = D^(-1) * B' * BDz } //cumulation for sigma (ps) using B*z //original comment for (int i = 0; i < N; i++) { sum=0; for (int j = 0; j < N; ++j) sum += sw.B[i][j] * tmp[j]; //sum = sqrt(muEff)*C^(1/2)*y_w = sqrt(muEff)*BD^−1B'*y_w sw.pSigma[i] = (1.0 - cSigma) * sw.pSigma[i] + sqrt(cSigma * (2.0 - cSigma)) * sum; /* calculate norm(ps)^2 */ psxps += sw.pSigma[i] * sw.pSigma[i]; } /* cumulation for covariance matrix (pc) using B*D*z~N(0,C) */ hsig = sqrt(psxps) / sqrt(1.0 - pow(1.0-cSigma, 2*(sw.gen+1))) / chiN < 1.4 + 2.0/(N+1); for (int i = 0; i < N; ++i) sw.pC[i] = (1.0 - cc) * sw.pC[i] + hsig * sqrt(cc * (2.0 - cc)) * BDz[i]; //************ Adapt_C2 *********// Update covariance matrix double ccov1 = std::min(cCov * (1.0/muCov) * 1.0, 1.0); //code // double ccov1 = 2.0/(((N+1.3)*(N+1.3))+muEff); //paper double ccovmu = std::min(cCov * (1-1.0/muCov)* 1.0, 1.0-ccov1); //code // double ccovmu = std::min(1.0-ccov1, 2 * ( ( (muEff-2.0)+(1.0/muEff) )/( (N+2.0)*(N+2.0) + (2.0*muEff)/2.0 ) )); //paper double sigmasquare = sw.sigma * sw.sigma; /* update covariance matrix */ for (int i = 0; i < N; ++i) for (int j = 0; j <= i; ++j) { sw.C[i][j] = (1.0 - ccov1 - ccovmu) * sw.C[i][j] + ccov1* (sw.pC[i] * sw.pC[j] + (1.0-hsig)*cc*(2.0-cc) * sw.C[i][j]); for (int k = 0; k < mu; ++k) { /* additional rank mu update */ // sw.C[i][j] += ccovmu * weights[k]* (nonDominated[k][i] - oldMean[i]) * (nonDominated[k][j] - oldMean[j])/ sigmasquare;//original equation sw.C[i][j] += ccovmu * weights[k] * clipped[k][i] * clipped[k][j];//changed on eq (10) of the injecting solutions into cmaes paper } } //**************************************// // dSigma= (1.0 + 2.0*std::max(0.0, sqrt((muEff-1.0)/(N+1.0)) - 1.0)) * std::max(0.3, 1.0 -(double)N / (1e-6+std::min(evo.sp.stopMaxIter, evo.sp.stopMaxFunEvals/evo.sp.lambda))) + cSigma;//code (used to compare our algorithm to the implemented) /* update of sigma */ // sw.sigma *= exp(((sqrt(psxps)/chiN)-1.0)*cSigma/dSigma);//original equation double deltaSigmaMax=1; sw.sigma *= exp(std::min(deltaSigmaMax, ((sqrt(psxps)/chiN)-1.0)*cSigma/dSigma ) );//Changed on eq (11) of the injecting solutions into cmaes paper if(logCMAES){ printf("\n\nmueff %f, cSigma %f, dSigma %f, ccumcov %f, sigma %f", muEff, cSigma, dSigma, cc, sw.sigma); printf("\nhsig %d, psxps %f, chiN %f, gen %d \n", hsig, psxps, chiN, sw.gen); // printf("\n\nweights - mu: %d : ", mu); // printVector(weights, mu); printf("\navg_old : "); printVector(oldMean, N); printf("\navg : "); printVector(sw.mean, N); // printf("\n\nD mat:"); // printVector(sw.D, N); printf("\n\nBDz: "); printVector(BDz, N); printf("\ntmp : "); printVector(tmp, N); printf("\nps : "); printVector(sw.pSigma, N); printf("\npc : "); printVector(sw.pC, N); } // t->rgBDz[i] = sqrt(t->sp.mueff)*(t->rgxmean[i] - t->rgxold[i])/t->sigma; // printf("\n\nrgD (new): "); // printVector(D, N); // printf("\n\nB (new): \n"); // for (int i = 0; i < N; ++i){ // printVector(B[i], N); // printf("\n"); // } // printf("\n\nCov mat: \n"); // for (int i = 0; i < N; ++i){ // printVector(sw.C[i], N); // printf("\n"); // } //****************comparing the implemented CMA-ES with our version**********************// // evo.sp.mu=mu; // evo.sp.lambda=mu; // // for(int i=0;i<mu;i++) // for(int j=0;j<N;j++) // evo.rgrgx[i][j]=nonDominated[i][j]; // cmaes_SamplePopulation(&evo); /* do not change content of pop */ // for(int i=0;i<mu;i++) // for(int j=0;j<N;j++) // evo.rgrgx[i][j]=nonDominated[i][j]; // // for(int i=0;i<N;i++) // evo.rgxmean[i]=oldMean[i]; // // printf("\nccov1 %f", ccov1); // printf("\nccovmu %f", ccovmu); // printf("\nsigmasquare %.20f", sigmasquare); // printf("\nhsig %d", hsig); // printf("\nccumcov %f", cc); // printf("\nccov %.20f", cCov); // printf("\nmucov %.20f", muCov); // printf("\nmueff: %.20f", muEff); // printf("\nBDz: "); // printVector(BDz, N); // printf("\npSigma: "); // printVector(sw.pSigma, N); // printf("\npC: "); // printVector(sw.pC, N); // printf("\nD: "); // for(int i=0;i<N;i++) // printf("%.15f ",sw.D[i]); // printf("\npsxps: %f", psxps); // printf("\nchin: %f", chiN); // printf("\ncSigma: %f", cSigma); // printf("\ndSigma: %f", dSigma); // printf("\nsigma: %f", sw.sigma); // printf("\nmean: "); // printVector(sw.mean, N); // printf("\nold: "); // printVector(oldMean, N); // printf("\nweights: "); // printVector(weights, mu); // // cmaes_UpdateDistribution(&evo, weights); // // if(evo.sp.ccov != cCov){ // printf("\ncCov different\n"); // exit(1); // } // if(evo.sp.mucov != muCov){ // printf("\nmuCov different\n"); // exit(1); // } // if(evo.sp.ccumcov != cc){ // printf("\ncc different\n"); // exit(1); // } // if(evo.sp.mueff != muEff){ // printf("\nmuEff different\n"); // exit(1); // } // if(evo.sp.cs != cSigma){ // printf("\ncSigma different\n"); // exit(1); // } // if(evo.sp.damps != dSigma){ // printf("\ndSigma different\n"); // exit(1); // } // for(int i=0;i<N;i++){ // if(evo.rgBDz[i] != BDz[i]){ // printf("\nBDz on %d different\n", i); // exit(1); // } // if(evo.rgD[i] != sw.D[i]){ // printf("\nD on %d different\n", i); // exit(1); // } // if(evo.rgdTmp[i] != tmp[i]){ // printf("\ntmp on %d different\n", i); // exit(1); // } // if(evo.rgps[i] != sw.pSigma[i]){ // printf("\npSigma on %d different (%.20f)\n", i, abs(evo.rgps[i] - sw.pSigma[i])); // exit(1); // } // if(evo.rgpc[i] != sw.pC[i]){ // printf("\npC on %d different\n", i); // exit(1); // } // } // // printf("\nevo mean: "); // printVector(evo.rgxmean, N); // printf("\nevo old: "); // printVector(evo.rgxold, N); // printf("\nevo weights: "); // printVector(evo.sp.weights, mu); // // printf("\n\norig-cmaes\n"); // for(int i=0; i<cmaes_Get(&evo, "dim");i++){ // for(int j=0;j<cmaes_Get(&evo, "dim");j++) // printf("%f ",evo.C[i][j]); // printf("\n"); // } // // printf("\nmodif-cmaes\n"); // for(int i=0; i<N;i++){ // for(int j=0;j<N;j++) // printf("%f ",sw.C[i][j]); // printf("\n"); // } // // for(int i=0; i<N;i++){ // for(int j=0;j<N;j++){ // if(((int)(evo.C[i][j]*1000000))/1000000.0 != ((int)(sw.C[i][j]*1000000))/1000000.0){ // printf("Different %f -- %f \t (%e) (%d,%d)\n", evo.C[i][j], sw.C[i][j], abs(evo.C[i][j] - sw.C[i][j]), i, j ); // maxDifference=std::max(maxDifference, abs(evo.C[i][j] - sw.C[i][j])); // // exit(1); // } // } // } // printf("maxDifference: %.20f, sigmaDifference: %.20f\n", maxDifference, abs(evo.sigma-sw.sigma)); // if(maxDifference > 1 ){ // printf("%d\n", mu); // exit(1); // } //**************************************************************************************// }