#include "gadget.h" //All the required standard header files are in here #include "optinfo.h" #include "mathfunc.h" #include "doublevector.h" #include "intvector.h" #include "errorhandler.h" #include "ecosystem.h" #include "global.h" #include "pso.h" #ifdef _OPENMP #include "omp.h" #endif extern Ecosystem* EcoSystem; #ifdef _OPENMP extern Ecosystem** EcoSystems; #endif //============================================================== //// calulate swarm size based on dimensionality int OptInfoPso::pso_calc_swarm_size(int dim) { int size = 10. + 2. * sqrt(dim); return (size > PSO_MAX_SIZE ? PSO_MAX_SIZE : size); } void OptInfoPso::OptimiseLikelihood() { handle.logMessage(LOGINFO, "\nStarting PSO optimisation algorithm\n"); double oldf, newf, steplength, tmp; int i, offset,rchange,rcheck,rnumber; int nvars = EcoSystem->numOptVariables(); DoubleVector x(nvars); DoubleVector trialx(nvars); DoubleVector bestx(nvars); struct Best {double bestf; int index;}; struct Best best; double bestf; DoubleVector lowerb(nvars); DoubleVector upperb(nvars); DoubleVector init(nvars); //DoubleVector initialstep(nvars, rho); IntVector param(nvars, 0); IntVector lbound(nvars, 0); IntVector rbounds(nvars, 0); IntVector trapped(nvars, 0); /** * Internal variables for PSO */ DoubleMatrix pos(size,nvars,0.0); // position matrix DoubleMatrix vel(size,nvars,0.0); // velocity matrix DoubleMatrix pos_b(size,nvars,0.0); // best position matrix DoubleVector fit(size); // particle fitness vector DoubleVector fit_b(size); // best fitness vector DoubleMatrix pos_nb(size,nvars,0.0); // what is the best informed position for each particle IntMatrix comm(size,size,0); // communications:who informs who rows : those who inform cols : those who are informed int improved; // whether solution->error was improved during the last iteration int d, step; double a, b; double rho1, rho2; //random numbers (coefficients) double w; //current omega Inform_fun inform_fun; Calc_inertia_fun calc_inertia_fun; // inertia weight update function int psosteps=0; if (this->seed!=0) srand(this->seed); handle.logMessage(LOGINFO,"Starting PSO with particles ",size,"\n"); switch (nhood_strategy) { case PSO_NHOOD_GLOBAL : // comm matrix not used handle.logMessage(LOGINFO,"PSO will use global communication\n"); inform_fun = &OptInfoPso::inform_global; break; case PSO_NHOOD_RING : handle.logMessage(LOGINFO,"PSO will use ring communication\n"); init_comm_ring(comm); inform_fun = &OptInfoPso::inform_ring; break; case PSO_NHOOD_RANDOM : handle.logMessage(LOGINFO,"PSO will use random communication\n"); init_comm_random(comm); inform_fun = &OptInfoPso::inform_random; break; } // SELECT APPROPRIATE INERTIA WEIGHT UPDATE FUNCTION switch (w_strategy) { case PSO_W_CONST : handle.logMessage(LOGINFO,"PSO will use constant inertia\n"); calc_inertia_fun = &OptInfoPso::calc_inertia_const; break; case PSO_W_LIN_DEC : handle.logMessage(LOGINFO,"PSO will use linear decreasing inertia\n"); calc_inertia_fun = &OptInfoPso::calc_inertia_lin_dec; break; } // //initialize omega using standard value // w = PSO_INERTIA; handle.logMessage(LOGINFO,"PSO initial inertia ",w,"\n"); handle.logMessage(LOGINFO,"PSO c1",c1,"\n"); handle.logMessage(LOGINFO,"PSO c2",c2,"\n"); handle.logMessage(LOGINFO,"PSO goal",goal,"\n"); EcoSystem->scaleVariables(); #ifdef _OPENMP int numThr = omp_get_max_threads ( ); #pragma omp parallel for for (i=0;iscaleVariables(); #endif EcoSystem->getOptScaledValues(x); EcoSystem->getOptLowerBounds(lowerb); EcoSystem->getOptUpperBounds(upperb); EcoSystem->getOptInitialValues(init); for (i = 0; i < nvars; i++) { // Scaling the bounds, because the parameters are scaled lowerb[i] = lowerb[i] / init[i]; upperb[i] = upperb[i] / init[i]; if (lowerb[i] > upperb[i]) { tmp = lowerb[i]; lowerb[i] = upperb[i]; upperb[i] = tmp; } bestx[i] = x[i]; trialx[i] = x[i]; param[i] = i; } bestf = EcoSystem->SimulateAndUpdate(trialx); if (bestf != bestf) { //check for NaN handle.logMessage(LOGINFO, "Error starting PSO optimisation with f(x) = infinity"); converge = -1; iters = 1; return; } offset = EcoSystem->getFuncEval(); //number of function evaluations done before loop iters = 0; // // Initialize the particles // i=0; handle.logMessage(LOGINFO,"Initialising PSO ",size,"particles\n"); // // Initialize the fist particle with the best known position // for (d=0; dSimulateAndUpdate(pos[i]); fit_b[i] = fit[i]; // this is also the personal best if (fit[i] < bestf) { bestf = fit[i]; best.bestf=bestf; bestx=pos[i]; best.index=i; } // // Now other particles with a random position in the solution space // best.bestf=bestf; best.index=0; handle.logMessage(LOGINFO,"before Best.bestf=",best.bestf); #pragma omp declare reduction(bestomp: struct Best : omp_out = omp_in.bestf < omp_out.bestf ? omp_in : omp_out) #pragma omp parallel for default(shared) private(i,d,a,b) reduction(bestomp:best) firstprivate(bestf) for (i=1; iSimulateAndUpdate(pos[i]); best.bestf = fit[i]; #else fit[i] = EcoSystem->SimulateAndUpdate(pos[i]); #endif fit_b[i] = fit[i]; // this is also the personal best // update gbest?? //#pragma omp critical (best1) if (fit[i] < bestf) { // update best fitness handle.logMessage(LOGINFO,"iInside Best.bestf=",best.bestf); // copy particle pos to gbest vector //memmove((void *)&bestx, (void *)&pos[i], // sizeof(double) * nvars); best.index=i; bestf=best.bestf; //bestx=pos[i]; } spos<<" ]"; svel<<" ]"; handle.logMessage(LOGDEBUG, spos.str().c_str()); handle.logMessage(LOGDEBUG, svel.str().c_str()); } // // Compare the reduction with the best value // if (best.bestf < bestf){ bestx=pos[best.index]; bestf=best.bestf; } // // RUN ALGORITHM // psosteps=0; while (1) { handle.logMessage(LOGINFO, "PSO optimisation after", psosteps*size,"\n"); if (isZero(bestf)) { iters = EcoSystem->getFuncEval() - offset; handle.logMessage(LOGINFO, "Error in PSO optimisation after", iters, "function evaluations, f(x) = 0"); converge = -1; return; } /* if too many function evaluations occur, terminate the algorithm */ iters = EcoSystem->getFuncEval() - offset; if (psosteps > psoiter) { handle.logMessage(LOGINFO, "\nStopping PSO optimisation algorithm\n"); handle.logMessage(LOGINFO, "The optimisation stopped after", iters, "function evaluations"); handle.logMessage(LOGINFO, "The optimisation stopped because the maximum number of PSO steps was reached"); handle.logMessage(LOGINFO, "was reached and NOT because an optimum was found for this run"); bestf = EcoSystem->SimulateAndUpdate(bestx); for (i = 0; i < nvars; i++) bestx[i] = bestx[i] * init[i]; handle.logMessage(LOGINFO, "\nPSO finished with a likelihood score of", bestf); EcoSystem->storeVariables(bestf, bestx); return; } if (w_strategy) w = (this->*calc_inertia_fun)(psosteps); // check optimization goal if (bestf <= goal) { handle.logMessage(LOGINFO, "\nStopping PSO optimisation algorithm\n"); handle.logMessage(LOGINFO, "Goal achieved!!! @ step ", psosteps); bestf = EcoSystem->SimulateAndUpdate(bestx); handle.logMessage(LOGINFO, "\nPSO finished with a likelihood score of", bestf); break; } // update pos_nb matrix (find best of neighborhood for all particles) (this->*inform_fun)(comm, pos_nb, pos_b, fit_b, bestx, improved); // the value of improved was just used; reset it improved = 0; // update all particles best.bestf=bestf; #pragma omp parallel for default(shared) private(i,d,rho1,rho2) reduction(bestomp:best) firstprivate(bestf) for (i=0; i upperb[d]) { pos[i][d] = upperb[d]; vel[i][d] = 0; } } else { // enforce periodic boundary conditions if (pos[i][d] < lowerb[d]) { pos[i][d] = upperb[d] - fmod(lowerb[d] - pos[i][d], upperb[d] - lowerb[d]); vel[i][d] = 0; } else if (pos[i][d] > upperb[d]) { pos[i][d] = lowerb[d] + fmod(pos[i][d] - upperb[d], upperb[d] - lowerb[d]); vel[i][d] = 0; } } } //end for d spos<< "]" << endl; svel<< "]" << endl; handle.logMessage(LOGDEBUG,spos.str().c_str()); handle.logMessage(LOGDEBUG,svel.str().c_str()); // update particle fitness fit[i] = EcoSystems[omp_get_thread_num()]->SimulateAndUpdate(pos[i]); // update personal best position? best.bestf = fit[i]; if (fit[i] < fit_b[i]) { fit_b[i] = fit[i]; // copy contents of pos[i] to pos_b[i] //memmove((void *)&pos_b[i], (void *)&pos[i], // sizeof(double) * nvars); pos_b[i]=pos[i]; } // update gbest?? handle.logMessage(LOGDEBUG, "Particle ",i); handle.logMessage(LOGDEBUG, "The likelihood score is", bestf, "at the point"); handle.logMessage(LOGDEBUG, "Its likelihood score is", fit[i], "at the point"); //#pragma omp critical (best2) if (fit[i] < bestf) { improved = 1; // update best fitness best.index=i; bestf=fit[i]; // copy particle pos to gbest vector //memmove((void *)&bestx, (void *)&pos[i], // sizeof(double) * nvars); // for (d = 0; d < nvars; d++) // bestx[d] = pos[i][d] * init[d]; // iters = EcoSystem->getFuncEval() - offset; // handle.logMessage(LOGINFO, "\nNew optimum found after", iters, "function evaluations"); // handle.logMessage(LOGINFO, "The likelihood score is", best.bestf, "at the point"); // EcoSystem->storeVariables(best.bestf, bestx); // EcoSystem->writeBestValues(); // bestx=pos[i]; } } // end i if (best.bestf < bestf){ bestf=best.bestf; bestx=pos[best.index]; for (d = 0; d < nvars; d++) bestx[d] = bestx[d] * init[d]; iters = EcoSystem->getFuncEval() - offset; //To change. It is incorrect when is parallel. handle.logMessage(LOGINFO, "\nNew optimum found after", iters, "function evaluations"); handle.logMessage(LOGINFO, "The likelihood score is", bestf, "at the point"); EcoSystem->storeVariables(bestf, bestx); EcoSystem->writeBestValues(); bestx=pos[best.index]; } psosteps++; } // while (newf < bestf) iters = EcoSystem->getFuncEval() - offset; handle.logMessage(LOGINFO, "Existing PSO after ", iters, "function evaluations ..."); for (d = 0; d < nvars; d++) bestx[d] = bestx[d] * init[d]; EcoSystem->storeVariables(bestf, bestx); EcoSystem->writeBestValues(); } void OptInfoPso::OptimiseLikelihoodREP() { OptimiseLikelihood(); } void OptInfoPso::OptimiseLikelihoodOMP() { OptimiseLikelihood(); } /** * \brief calculate constant inertia weight equal to w_max */ double OptInfoPso::calc_inertia_const(int step) { return w_max; } /** * \brief calculate linearly decreasing inertia weight */ double OptInfoPso::calc_inertia_lin_dec(int step) { int dec_stage = 3 * psoiter / 4; if (step <= dec_stage) return w_min + (w_max - w_min) * \ (dec_stage - step) / dec_stage; else return w_min; } /** * \brief NEIGHBORHOOD (COMM) MATRIX STRATEGIES. global neighborhood */ void OptInfoPso::inform_global(IntMatrix& comm, DoubleMatrix& pos_nb, DoubleMatrix& pos_b, DoubleVector& fit_b, DoubleVector& gbest,int improved) { int i; // all particles have the same attractor (gbest) // copy the contents of gbest to pos_nb for (i=0; irng, settings->size); j=rand()*size/RAND_MAX; // particle i informs particle j comm[i] [j] = 1; } } } void OptInfoPso::inform_random(IntMatrix& comm, DoubleMatrix& pos_nb, DoubleMatrix& pos_b, DoubleVector& fit_b, DoubleVector& gbest, int improved) { // regenerate connectivity?? if (!improved) init_comm_random(comm); inform(comm, pos_nb, pos_b, fit_b, improved); }