TPCCLIB
Loading...
Searching...
No Matches
mpso.c
Go to the documentation of this file.
1
6/*****************************************************************************/
7#include "tpcclibConfig.h"
8/*****************************************************************************/
9#include <stdio.h>
10#include <stdlib.h>
11#include <math.h>
12#include <time.h>
13#include <string.h>
14/*****************************************************************************/
15#include "tpcextensions.h"
16#include "tpcrand.h"
17#include "tpcstatist.h"
18/*****************************************************************************/
19#include "tpcnlopt.h"
20/*****************************************************************************/
21
22/*****************************************************************************/
24typedef struct MPSO_PARTICLE {
26 double *position;
28 double *velocity;
30 double cost;
32 double *bestPosition;
34 double bestCost;
36 unsigned int since;
37} MPSO_PARTICLE;
38
40typedef struct MPSO_SWARM {
42 MPSO_PARTICLE *particle;
44 double *bestPosition;
46 double bestCost;
48 unsigned int since;
49} MPSO_SWARM;
50
52typedef struct MPSO_MULTISWARM {
54 unsigned int sn;
56 unsigned int pn;
58 unsigned int dim;
60 MPSO_SWARM *swarm;
62 double *bestPosition;
64 double bestCost;
66 unsigned int since;
70 MERTWI mt;
71} MPSO_MULTISWARM;
72/*****************************************************************************/
73
74/*****************************************************************************/
78 MPSO_MULTISWARM *ms,
80 unsigned int si,
82 double *mean,
84 double *sd
85) {
86 if(ms==NULL || ms->dim<1 || ms->sn<1 || ms->pn<1 || si>=ms->sn) return;
87 for(unsigned int i=0; i<ms->dim; i++) {
88 double a[ms->pn];
89 for(unsigned int pi=0; pi<ms->pn; pi++) a[pi]=ms->swarm[si].particle[pi].position[i];
90 double *amean=NULL, *asd=NULL;
91 if(mean!=NULL) amean=mean+i;
92 if(sd!=NULL) asd=sd+i;
93 statMeanSD(a, ms->pn, amean, asd, NULL);
94 }
95}
99 MPSO_MULTISWARM *ms,
101 unsigned int si,
103 double *mean,
105 double *sd
106) {
107 if(ms==NULL || ms->dim<1 || ms->sn<1 || ms->pn<1 || si>=ms->sn) return;
108 for(unsigned int i=0; i<ms->dim; i++) {
109 double a[ms->pn];
110 for(unsigned int pi=0; pi<ms->pn; pi++) a[pi]=fabs(ms->swarm[si].particle[pi].velocity[i]);
111 double *amean=NULL, *asd=NULL;
112 if(mean!=NULL) amean=mean+i;
113 if(sd!=NULL) asd=sd+i;
114 statMeanSD(a, ms->pn, amean, asd, NULL);
115 }
116}
117/*****************************************************************************/
118
119/*****************************************************************************/
135 NLOPT *nlo,
137 unsigned int maxIter,
139 unsigned int nSwarms,
141 unsigned int nParticles,
144 double wInertia,
147 double wParticle,
150 double wSwarm,
153 double wGlobal,
155 double pDeath,
157 double pImmigration,
160 const int doLocal,
162 TPCSTATUS *status
163) {
164 FILE *fp=stdout;
165 int verbose=0; if(status!=NULL) {verbose=status->verbose; fp=status->fp;}
166 if(verbose>0) {
167 fprintf(fp, "\n%s(NLOPT, %d, status)\n", __func__, doLocal);
168 fflush(fp);
169 }
170
171 if(nlo==NULL) {
172 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
173 return TPCERROR_FAIL;
174 }
175 if(nlo->totalNr<1 || nlo->xfull==NULL || nlo->_fun==NULL) {
176 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
177 return TPCERROR_NO_DATA;
178 }
179 if(nlo->maxFunCalls<100) {
180 if(verbose>0) {fprintf(stderr, "Error: too low limit for function calls.\n"); fflush(stderr);}
181 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
183 }
184
185 /* Check if any of the parameters are fixed */
186 unsigned int dim=nlo->totalNr; // Nr of parameters
187 unsigned int fixedParNr=nloptLimitFixedNr(nlo);
188 if(verbose>1 && fixedParNr>0) fprintf(fp, "fixedParNr := %d\n", fixedParNr);
189 unsigned int fittedParNr=nlo->totalNr-fixedParNr;
190 if(verbose>2) fprintf(fp, "fittedParNr := %d\n", fittedParNr);
191 if(fittedParNr<1) {
192 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
193 return TPCERROR_NO_DATA;
194 }
195
196 /* Check the tolerations */
197 for(unsigned int i=0; i<nlo->totalNr; i++) {
198 if(nlo->xlower[i]>=nlo->xupper[i]) {nlo->xtol[i]=0.0; continue;}
199 if(!(nlo->xtol[i]>0.0)) {
200 if(verbose>0) {fprintf(stderr, "Error: invalid xtol[].\n"); fflush(stderr);}
201 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
203 }
204 }
205
206
207
208 if(verbose>2) fprintf(fp, "\nInitializing MPSO\n");
209
210 if(maxIter<10) maxIter=1000; // max nr of loops (150)
211 if(nSwarms<2) nSwarms=2+fittedParNr; // nr of swarms (3)
212 if(nParticles<5) nParticles=5+2*fittedParNr; // nr of particles (25)
213 if(!(wInertia>0.0)) wInertia=0.333; // inertia (0.333)
214 if(!(wParticle>0.0)) wParticle=1.00; // particle / cognitive (1.40)
215 if(!(wSwarm>0.0)) wSwarm=1.60; // swarm / social (1.40)
216 if(!isfinite(wGlobal)) wGlobal=0.40; // multi-swarm / global (0.40)
217 if(!isfinite(pDeath) || pDeath>=0.1) // probability of particle death-rebirth (0.005)
218 pDeath=0.005; else if(pDeath<0.0) pDeath=0.0;
219 if(!isfinite(pImmigration) || pImmigration>=0.1) // probability of particle immigration (0.025)
220 pImmigration=0.025; else if(pImmigration<0.0) pImmigration=0.0;
221 /* Initiate the number of function calls */
222 if(nlo->usePList) { // not supported with this function; would crash if used anyway
223 nlo->usePList=0;
224 if(nlo->funCalls>0) free(nlo->plist);
225 nlo->plist=NULL;
226 }
227 nlo->funCalls=0;
228
229 unsigned int pFrustration=10; // Nr of non-successful movements when particle becomes frustrated
230 unsigned int nFrustration=15; // Nr of non-successful movements when swarm becomes frustrated
231
232 if(verbose>3) {
233 fprintf(fp, "maxIter := %u\n", maxIter);
234 fprintf(fp, "maxFunCalls := %u\n", nlo->maxFunCalls);
235 fprintf(fp, "nSwarms := %u\n", nSwarms);
236 fprintf(fp, "nParticles := %u\n", nParticles);
237 fprintf(fp, "dim := %u\n", dim);
238 fprintf(fp, "wInertia := %g\n", wInertia);
239 fprintf(fp, "wParticle := %g\n", wParticle);
240 fprintf(fp, "swarm/social (wSwarm) := %g\n", wSwarm);
241 fprintf(fp, "multi-swarm/global (wGlobal) := %g\n", wGlobal);
242 fprintf(fp, "probability of death := %g\n", pDeath);
243 fprintf(fp, "probability of immigration := %g\n", pImmigration);
244 fprintf(fp, "pFrustration := %u\n", pFrustration);
245 fprintf(fp, "nFrustration := %u\n", nFrustration);
246 fflush(fp);
247 }
248
249 /* Allocate memory */
250 MPSO_MULTISWARM multi;
251 multi.dim=dim; multi.sn=nSwarms; multi.pn=nParticles;
252 multi.bestPosition=calloc(dim, sizeof(double));
253 multi.swarm=calloc(nSwarms, sizeof(MPSO_SWARM));
254 for(unsigned int si=0; si<nSwarms; si++) {
255 multi.swarm[si].particle=calloc(nParticles, sizeof(MPSO_PARTICLE));
256 multi.swarm[si].bestPosition=calloc(dim, sizeof(double));
257 for(unsigned int pi=0; pi<nParticles; pi++) {
258 multi.swarm[si].particle[pi].position=calloc(dim, sizeof(double));
259 multi.swarm[si].particle[pi].velocity=calloc(dim, sizeof(double));
260 multi.swarm[si].particle[pi].bestPosition=calloc(dim, sizeof(double));
261 }
262 }
263 /* Initialize Mersenne Twister MT19937 */
264 mertwiInit(&multi.mt); mertwiInitWithSeed64(&multi.mt, mertwiSeed64());
265
266
267
268 /* Check if initial guess is valid */
269 int initGuessAvailable=1;
270 double initGuessCost=nan("");
271 for(unsigned int i=0; i<dim; i++) {
272 if(isnan(nlo->xfull[i])) {initGuessAvailable=0; break;}
273 if(nlo->xfull[i]<nlo->xlower[i]) {initGuessAvailable=0; break;}
274 if(nlo->xfull[i]>nlo->xupper[i]) {initGuessAvailable=0; break;}
275 }
276 if(initGuessAvailable) {
277 initGuessCost=(*nlo->_fun)(dim, nlo->xfull, nlo->fundata); nlo->funCalls++;
278 if(!isfinite(initGuessCost)) initGuessAvailable=0;
279 else if(verbose>3) {
280 fprintf(fp, "valid initial guess with cost=%g\n", initGuessCost); fflush(fp);
281 }
282 }
283
284 int carpetFill=0;
285
286 if(carpetFill) {
287 /* Fill the swarms with random parameters and their costs */
288 multi.bestCost=nan("");
289 for(unsigned int si=0; si<nSwarms; si++) {
290 for(unsigned int pi=0; pi<nParticles; pi++) {
291 nloptRandomPoint(multi.swarm[si].particle[pi].position, nlo->xlower, nlo->xupper, dim, &multi.mt);
292 nloptRandomPoint(multi.swarm[si].particle[pi].velocity, nlo->xlower, nlo->xupper, dim, &multi.mt);
293 for(unsigned int i=0; i<dim; i++)
294 multi.swarm[si].particle[pi].velocity[i]-=multi.swarm[si].particle[pi].position[i];
295 multi.swarm[si].particle[pi].cost=
296 (*nlo->_fun)(dim, multi.swarm[si].particle[pi].position, nlo->fundata);
297 nlo->funCalls++;
298 /* Currently, this is the best position of the particle */
299 multi.swarm[si].particle[pi].bestCost=multi.swarm[si].particle[pi].cost;
300 doubleCopy(multi.swarm[si].particle[pi].bestPosition,
301 multi.swarm[si].particle[pi].position, dim);
302 multi.swarm[si].particle[pi].since=0;
303 /* Set the best cost in this swarm */
304 if(pi==0) {
305 if(si==0 && initGuessAvailable) { // if initial guess available, use it here
306 multi.swarm[si].bestCost=initGuessCost;
307 doubleCopy(multi.swarm[si].bestPosition, nlo->xfull, dim);
308 } else {
309 multi.swarm[si].bestCost=multi.swarm[si].particle[pi].cost;
310 doubleCopy(multi.swarm[si].bestPosition, multi.swarm[si].particle[pi].position, dim);
311 }
312 } else {
313 if(!isfinite(multi.swarm[si].bestCost) ||
314 multi.swarm[si].bestCost>multi.swarm[si].particle[pi].cost)
315 {
316 multi.swarm[si].bestCost=multi.swarm[si].particle[pi].cost;
317 doubleCopy(multi.swarm[si].bestPosition, multi.swarm[si].particle[pi].position, dim);
318 }
319 }
320 } // next particle in this swarm
321 /* Set the best cost of all swarms */
322 if(si==0) {
323 multi.bestCost=multi.swarm[si].bestCost;
324 doubleCopy(multi.bestPosition, multi.swarm[si].bestPosition, dim);
325 } else {
326 if(!isfinite(multi.bestCost) || multi.bestCost>multi.swarm[si].bestCost) {
327 multi.bestCost=multi.swarm[si].bestCost;
328 doubleCopy(multi.bestPosition, multi.swarm[si].bestPosition, dim);
329 }
330 }
331 multi.swarm[si].since=0;
332 } // next swarm
333 multi.since=0;
334 } else {
335 /* For each swarm, make one random particle inside the limits */
336 unsigned int si=0;
337 if(initGuessAvailable) // if initial guess is available, use it as particle for first swarm
338 doubleCopy(multi.swarm[si++].particle[0].position, nlo->xfull, dim);
339 for(; si<nSwarms; si++)
340 nloptRandomPoint(multi.swarm[si].particle[0].position, nlo->xlower, nlo->xupper, dim, &multi.mt);
341 /* Then add other particles around it with Gaussian distribution */
342 double sd[dim];
343 for(unsigned int i=0; i<dim; i++) sd[i]=0.13*(nlo->xupper[i]-nlo->xlower[i]);
344 for(unsigned int si=0; si<nSwarms; si++) {
345 for(unsigned int pi=1; pi<nParticles; pi++) {
346 nloptGaussianPoint(multi.swarm[si].particle[pi].position,
347 multi.swarm[si].particle[0].position, sd, nlo->xlower, nlo->xupper, dim,
348 &multi.mt);
349 }
350 }
351 /* Add random velocity and direction for each particle */
352 for(unsigned int i=0; i<dim; i++) sd[i]=0.23*(nlo->xupper[i]-nlo->xlower[i]);
353 double mvel[dim]; for(unsigned int i=0; i<dim; i++) mvel[i]=0.0;
354 for(unsigned int si=0; si<nSwarms; si++) {
355 for(unsigned int pi=0; pi<nParticles; pi++) {
356 nloptGaussianPoint(multi.swarm[si].particle[pi].velocity,
357 mvel, sd, NULL, NULL, dim, &multi.mt);
358 }
359 }
360 /* Calculate the cost of each particle, and find the best positions */
361 multi.bestCost=nan("");
362 for(unsigned int si=0; si<nSwarms; si++) {
363 multi.swarm[si].bestCost=nan("");
364 for(unsigned int pi=0; pi<nParticles; pi++) {
365 multi.swarm[si].particle[pi].cost=
366 (*nlo->_fun)(dim, multi.swarm[si].particle[pi].position, nlo->fundata);
367 nlo->funCalls++;
368 /* Currently, this is the best position of the particle */
369 multi.swarm[si].particle[pi].bestCost=multi.swarm[si].particle[pi].cost;
370 doubleCopy(multi.swarm[si].particle[pi].bestPosition,
371 multi.swarm[si].particle[pi].position, dim);
372 multi.swarm[si].particle[pi].since=0;
373 /* How about best in the swarm? */
374 if(!isfinite(multi.swarm[si].bestCost) ||
375 multi.swarm[si].bestCost>multi.swarm[si].particle[pi].cost)
376 {
377 multi.swarm[si].bestCost=multi.swarm[si].particle[pi].cost;
378 doubleCopy(multi.swarm[si].bestPosition,
379 multi.swarm[si].particle[pi].position, dim);
380 }
381 }
382 /* Does this swarm has the best particle of all? */
383 if(!isfinite(multi.bestCost) || multi.bestCost>multi.swarm[si].bestCost) {
384 multi.bestCost=multi.swarm[si].bestCost;
385 doubleCopy(multi.bestPosition, multi.swarm[si].bestPosition, dim);
386 }
387 multi.swarm[si].since=0;
388 }
389 multi.since=0;
390 }
391
392
393 /* Inside the loop, save the previous best position to check if fit is improving */
394 double lastBestPosition[dim];
395 unsigned int movementCounter=0; // counter for stopped movement
396 unsigned int convergenceCounter=0; // counter for converged swarms
397
398 unsigned int stopCostLimit=20, stopCost=0;
399 double lastBestCost=multi.bestCost;
400
401 unsigned int iterNr=0; // loop index
402 while(iterNr<maxIter && nlo->funCalls<nlo->maxFunCalls) {
403 iterNr++;
404 if(verbose>4) {
405 fprintf(fp, "-----------------------------\nloop %d\n", iterNr);
406 fprintf(fp, "bestCost=%g since %u iterations\n", multi.bestCost, multi.since);
407 if(verbose>5) fprintf(fp, "function_calls_so_far=%d\n", nlo->funCalls);
408 fflush(fp);
409 }
410
411
412#if(0)
413 /* Check if each swarm has concentrated inside tolerance */
414 unsigned int swarmsConcentrated=0;
415 for(unsigned int si=0; si<nSwarms; si++) {
416 double /*pmean[dim],*/ psd[dim], vmean[dim], vsd[dim];
417 nloptMPSOpMean(&multi, si, pmean, psd);
418 nloptMPSOabsvMean(&multi, si, vmean, vsd);
419 if(verbose>5) {
420 fprintf(fp, "swarm %d bestCost=%g since %u\n", 1+si,
421 multi.swarm[si].bestCost, multi.swarm[si].since);
422 if(verbose>6) {
423 fprintf(fp, " bestPosition: %g", multi.swarm[si].bestPosition[0]);
424 for(unsigned int i=1; i<dim; i++) fprintf(fp, ", %g", multi.swarm[si].bestPosition[i]);
425 fprintf(fp, "\n");
426 }
427 if(verbose>9 || iterNr==1) {
428 for(unsigned int i=0; i<dim; i++)
429 fprintf(fp, " parameter %d: meanPosition %g +- %g\n", 1+i, pmean[i], psd[i]);
430 for(unsigned int i=0; i<dim; i++)
431 fprintf(fp, " parameter %d: meanAbsVelocity %g +- %g\n", 1+i, vmean[i], vsd[i]);
432 }
433 fflush(fp);
434 }
435 /* Swarm particle mean and best particle ever inside tolerance? */
436 /* Parameter SD below tolerance? */
437 unsigned int i=0;
438 for(i=0; i<dim; i++) {
439 if(fabs(pmean[i] - multi.swarm[si].bestPosition[i]) > 0.01*nlo->xtol[i]) break;
440 if(psd[i]>0.02*nlo->xtol[i]) break;
441 }
442 if(i==dim) {
443 if(verbose>5) fprintf(fp, " swarm %d particles inside tolerance.\n", 1+si);
444 swarmsConcentrated++;
445 }
446 }
447 if(swarmsConcentrated==nSwarms) {
448 if(verbose>2) fprintf(fp, " all swarm particles shrunk inside swarm tolerance.\n");
449 break;
450 }
451#endif
452
453
454 /* Go through all swarms, and their particles */
455 unsigned int swarmsConcentrated=0;
456 multi.since++;
457 for(unsigned int si=0; si<nSwarms; si++) {
458 multi.swarm[si].since++;
459
460 /* Calculate statistics of the swarm */
461 double pmean[dim], psd[dim], vmean[dim], vsd[dim];
462 nloptMPSOpMean(&multi, si, pmean, psd);
463 nloptMPSOabsvMean(&multi, si, vmean, vsd);
464 if(verbose>5) {
465 fprintf(fp, "swarm %d bestCost=%g since %u\n", 1+si,
466 multi.swarm[si].bestCost, multi.swarm[si].since);
467 if(verbose>6) {
468 fprintf(fp, " bestPosition: %g", multi.swarm[si].bestPosition[0]);
469 for(unsigned int i=1; i<dim; i++) fprintf(fp, ", %g", multi.swarm[si].bestPosition[i]);
470 fprintf(fp, "\n");
471 }
472 if(verbose>7 || iterNr==1) {
473 for(unsigned int i=0; i<dim; i++)
474 fprintf(fp, " parameter %d: meanPosition %g +- %g\n", 1+i, pmean[i], psd[i]);
475 for(unsigned int i=0; i<dim; i++)
476 fprintf(fp, " parameter %d: meanAbsVelocity %g +- %g\n", 1+i, vmean[i], vsd[i]);
477 }
478 fflush(fp);
479 }
480 /* Swarm particle mean and best-ever particle inside tolerance? */
481 /* Parameter SD below tolerance? */
482 {
483 unsigned int i=0;
484 for(i=0; i<dim; i++) {
485 if(fabs(pmean[i] - multi.swarm[si].bestPosition[i]) > 0.01*nlo->xtol[i]) break;
486 if(psd[i]>0.02*nlo->xtol[i]) break;
487 }
488 if(i==dim) {
489 if(verbose>5) fprintf(fp, " swarm %d particles inside tolerance.\n", 1+si);
490 swarmsConcentrated++;
491 }
492 }
493
494
495
496 /* Swarm can get frustrated if no advancement for a long time */
497 int swarmFrustrated=0;
498 if(multi.swarm[si].since>=nFrustration) {
499 swarmFrustrated=1; multi.swarm[si].since=0;
500 if(verbose>5) {fprintf(fp, "swarm is frustrated\n"); fflush(fp);}
501 }
502
503 /* After every 10 loops, try Nelder-Mead, if requested */
504 if(doLocal && !swarmFrustrated && (iterNr%10)==0) {
505 if(verbose>5) {fprintf(fp, "local optimization:\n"); fflush(fp);}
506 /* Best-ever position as starting point */
507 doubleCopy(nlo->xfull, multi.swarm[si].bestPosition, dim);
508 /* Deltas based on swarm particle SD, but making sure that above zero, unless parameter is fixed */
509 for(unsigned int i=0; i<dim; i++) {
510 if(!(nlo->xupper[i]>nlo->xlower[i])) {nlo->xdelta[i]=0.0; continue;}
511 if(psd[i]>nlo->xtol[i]) {nlo->xdelta[i]=psd[i]; continue;}
512 nlo->xdelta[i]=mertwiRandomExponential(&multi.mt, nlo->xtol[i]);
513 }
514 if(verbose>7) {
515 fprintf(fp, "initial guesses and deltas, with cost %g:\n", multi.swarm[si].bestCost);
516 for(unsigned int i=0; i<dim; i++) fprintf(fp, "\t%e\t%e\n", nlo->xfull[i], nlo->xdelta[i]);
517 fflush(fp);
518 }
519 if(nloptSimplex(nlo, 50*dim, NULL)==0) {
520 double cost=nlo->funval;
521 if(cost<multi.swarm[si].bestCost) {
522 multi.swarm[si].bestCost=cost;
523 doubleCopy(multi.swarm[si].bestPosition, nlo->xfull, dim);
524 multi.swarm[si].since=0;
525 if(verbose>7) {
526 fprintf(fp, "results: %e", multi.swarm[si].bestPosition[0]);
527 for(unsigned int i=1; i<dim; i++) fprintf(fp, ", %e", multi.swarm[si].bestPosition[i]);
528 fprintf(fp, ", with cost: %g\n", cost); fflush(fp);
529 }
530 } else {
531 if(verbose>10) fprintf(fp, "local optimization did not provide lower cost (%e)\n", cost);
532 }
533 } else {
534 if(verbose>10) fprintf(fp, "local optimization failed.\n");
535 }
536 }
537
538 /* Go through the particles of this swarm */
539 for(unsigned int pi=0; pi<nParticles; pi++) {
540
541 if(verbose>14) {
542 fprintf(fp, " particle %d bestCost=%g since %u\n", 1+pi,
543 multi.swarm[si].particle[pi].bestCost, multi.swarm[si].particle[pi].since);
544 fflush(fp);
545 }
546
547 /* Cast lots for whether it is time to kill particle and create a new;
548 but if cost is NaN, then most definitely kill it. */
549 int killed=0;
550 if((iterNr>3 && mertwiRandomDouble1(&multi.mt)<pDeath)
551 || isnan(multi.swarm[si].particle[pi].cost))
552 {
553 killed=1; multi.swarm[si].particle[pi].since=0;
554 /* Replace current position and velocity with random position and velocity */
555 if(verbose>12) {fprintf(fp, "death of particle %u\n", 1+pi); fflush(fp);}
556
557 nloptRandomPoint(multi.swarm[si].particle[pi].position, nlo->xlower, nlo->xupper, dim, &multi.mt);
558 nloptRandomPoint(multi.swarm[si].particle[pi].velocity, nlo->xlower, nlo->xupper, dim, &multi.mt);
559 for(unsigned int i=0; i<dim; i++)
560 multi.swarm[si].particle[pi].velocity[i]-=multi.swarm[si].particle[pi].position[i];
561 /* cost */
562 multi.swarm[si].particle[pi].cost=
563 (*nlo->_fun)(dim, multi.swarm[si].particle[pi].position, nlo->fundata);
564 nlo->funCalls++;
565 /* Check if this is the best position ever for this particle */
566 if(multi.swarm[si].particle[pi].bestCost>multi.swarm[si].particle[pi].cost) {
567 if(verbose>10) printf("Miracle: resurrection led to a new best!\n");
568 multi.swarm[si].particle[pi].bestCost=multi.swarm[si].particle[pi].cost;
569 doubleCopy(multi.swarm[si].particle[pi].bestPosition,
570 multi.swarm[si].particle[pi].position, dim);
571 }
572 }
573
574 /* Cast lots for whether it is time to immigrate */
575 int immigrated=0;
576 if(iterNr>5 && !killed && nSwarms>1 && mertwiRandomDouble1(&multi.mt)<pImmigration) {
577 immigrated=1; multi.swarm[si].particle[pi].since=0;
578 /* Swap particle with a random particle in different swarm */
579 if(verbose>12) {fprintf(fp, " immigration\n"); fflush(fp);}
580 unsigned int sj;
581 if(nSwarms<4) {
582 sj=si+1; if(sj>=nSwarms) sj=si-1;
583 } else {
584 do {sj=mertwiRandomInt63(&multi.mt)/(INT64_MAX/(nSwarms-1)+1);} while(si==sj);
585 }
586 if(verbose>12) fprintf(fp, " swapping particle %d between swarms %d and %d\n", 1+pi, 1+si, 1+sj);
587 for(unsigned int i=0; i<dim; i++) {
588 /* position */
589 double d=multi.swarm[si].particle[pi].position[i];
590 multi.swarm[si].particle[pi].position[i]=multi.swarm[sj].particle[pi].position[i];
591 multi.swarm[sj].particle[pi].position[i]=d;
592 /* velocity */
593 d=multi.swarm[si].particle[pi].velocity[i];
594 multi.swarm[si].particle[pi].velocity[i]=multi.swarm[sj].particle[pi].velocity[i];
595 multi.swarm[sj].particle[pi].velocity[i]=d;
596 }
597 /* cost */
598 double d=multi.swarm[si].particle[pi].cost;
599 multi.swarm[si].particle[pi].cost=multi.swarm[sj].particle[pi].cost;
600 multi.swarm[sj].particle[pi].cost=d;
601 /* also the particles memory of its best ever cost and position follows it to another swarm */
602 d=multi.swarm[si].particle[pi].bestCost;
603 multi.swarm[si].particle[pi].bestCost=multi.swarm[sj].particle[pi].bestCost;
604 multi.swarm[sj].particle[pi].bestCost=d;
605 for(unsigned int i=0; i<dim; i++) {
606 double d=multi.swarm[si].particle[pi].bestPosition[i];
607 multi.swarm[si].particle[pi].bestPosition[i]=multi.swarm[sj].particle[pi].bestPosition[i];
608 multi.swarm[sj].particle[pi].bestPosition[i]=d;
609 }
610 /* Is the immigrated particle the best in its new swarm? */
611 if(multi.swarm[si].bestCost>multi.swarm[si].particle[pi].bestCost) {
612 multi.swarm[si].bestCost=multi.swarm[si].particle[pi].bestCost;
613 doubleCopy(multi.swarm[si].bestPosition, multi.swarm[si].particle[pi].bestPosition, dim);
614 }
615 if(multi.swarm[sj].bestCost>multi.swarm[sj].particle[pi].bestCost) {
616 multi.swarm[sj].bestCost=multi.swarm[sj].particle[pi].bestCost;
617 doubleCopy(multi.swarm[sj].bestPosition, multi.swarm[sj].particle[pi].bestPosition, dim);
618 }
619 }
620
621 /* If particle does not advance, it gets frustrated */
622 int frustrated=0;
623 if(multi.swarm[si].particle[pi].since>=nFrustration && !killed && !immigrated) {
624 frustrated=1;
625 }
626 if(!frustrated && !killed && !immigrated && multi.swarm[si].particle[pi].since>2) {
627 /* If particle has the worst position in the swarm, it will get frustrated, too */
628 frustrated=1;
629 for(unsigned int pj=0; pj<nParticles; pj++) if(pi!=pj)
630 if(multi.swarm[si].particle[pj].cost>multi.swarm[si].particle[pi].cost) {
631 frustrated=0; break;}
632 }
633 if(frustrated) {
634 multi.swarm[si].particle[pi].since=0;
635 /* Particle gets frustrated and will turn towards the swarm mean */
636 if(verbose>12) {
637 fprintf(fp, " particle %u became frustrated\n", 1+pi);
638 fprintf(fp, " current position: %g", multi.swarm[si].particle[pi].position[0]);
639 for(unsigned int i=1; i<dim; i++) fprintf(fp, ", %g", multi.swarm[si].particle[pi].position[i]);
640 fprintf(fp, " -> %g\n", multi.swarm[si].particle[pi].cost);
641 fflush(fp);
642 }
643 }
644
645
646 /* Update velocity in every dimension */
647 if(!frustrated) {
648 for(unsigned int i=0; i<dim; i++) if(nlo->xupper[i]>nlo->xlower[i]) {
649 multi.swarm[si].particle[pi].velocity[i] =
650 wInertia*multi.swarm[si].particle[pi].velocity[i];
651 multi.swarm[si].particle[pi].velocity[i] += wParticle*mertwiRandomDouble1(&multi.mt)*
652 (multi.swarm[si].particle[pi].bestPosition[i] - multi.swarm[si].particle[pi].position[i]);
653 multi.swarm[si].particle[pi].velocity[i] += wSwarm*mertwiRandomDouble1(&multi.mt)*
654 (multi.swarm[si].bestPosition[i] - multi.swarm[si].particle[pi].position[i]);
655 if(wGlobal>0.0)
656 multi.swarm[si].particle[pi].velocity[i] += wGlobal*mertwiRandomDouble1(&multi.mt)*
657 (multi.bestPosition[i] - multi.swarm[si].particle[pi].position[i]);
658 }
659 if(swarmFrustrated) {
660 /* Additional random panic movement, if swarm is frustrated */
661 for(unsigned int i=0; i<dim; i++) if(nlo->xupper[i]>nlo->xlower[i]) {
662 double v=mertwiRandomExponential(&multi.mt, nlo->xtol[i]);
663 if(multi.swarm[si].particle[pi].velocity[i]>0.0)
664 multi.swarm[si].particle[pi].velocity[i]+=v;
665 else multi.swarm[si].particle[pi].velocity[i]-=v;
666 }
667 }
668 } else {
669 /* Frustrated particle turns towards the swarm mean */
670 for(unsigned int i=0; i<dim; i++) if(nlo->xupper[i]>nlo->xlower[i]) {
671 multi.swarm[si].particle[pi].velocity[i] =
672 0.11*wInertia*multi.swarm[si].particle[pi].velocity[i] +
673 0.89*(pmean[i] - multi.swarm[si].particle[pi].position[i]);
674 }
675 }
676 if(wGlobal<0.0 && nSwarms>1) { // Swarms reject each other; not recommended
677 for(unsigned int sj=0; sj<nSwarms; sj++) if(si!=sj) {
678 for(unsigned int i=0; i<dim; i++) if(nlo->xupper[i]>nlo->xlower[i]) {
679 multi.swarm[si].particle[pi].velocity[i] += wGlobal*mertwiRandomDouble1(&multi.mt)*
680 (multi.swarm[sj].bestPosition[i] - multi.swarm[si].particle[pi].position[i]);
681 }
682 }
683 }
684 if(verbose>15 || (verbose>12 && frustrated)) {
685 fprintf(fp, " updated velocities: %g", multi.swarm[si].particle[pi].velocity[0]);
686 for(unsigned int i=1; i<dim; i++)
687 fprintf(fp, ", %g", multi.swarm[si].particle[pi].velocity[i]);
688 fprintf(fp, "\n");
689 }
690
691 /* Update position */
692 for(unsigned int i=0; i<dim; i++)
693 multi.swarm[si].particle[pi].position[i]+=multi.swarm[si].particle[pi].velocity[i];
694 /* check that new position is inside limits */
695 for(unsigned int i=0; i<dim; i++)
696 if(multi.swarm[si].particle[pi].position[i]<nlo->xlower[i]) {
697 multi.swarm[si].particle[pi].position[i]=nlo->xlower[i];
698 /* reduce velocity and change direction */
699 multi.swarm[si].particle[pi].velocity[i]*=-0.1;
700 } else if(multi.swarm[si].particle[pi].position[i]>nlo->xupper[i]) {
701 multi.swarm[si].particle[pi].position[i]=nlo->xupper[i];
702 /* reduce velocity and change direction */
703 multi.swarm[si].particle[pi].velocity[i]*=-0.1;
704 }
705 if(verbose>15 || (verbose>12 && frustrated)) {
706 fprintf(fp, " updated positions: %g", multi.swarm[si].particle[pi].position[0]);
707 for(unsigned int i=1; i<dim; i++) fprintf(fp, ", %g", multi.swarm[si].particle[pi].position[i]);
708 fprintf(fp, "\n");
709 }
710
711
712 /* Update cost */
713 multi.swarm[si].particle[pi].cost=
714 (*nlo->_fun)(dim, multi.swarm[si].particle[pi].position, nlo->fundata);
715 nlo->funCalls++;
716 if(verbose>15 || (verbose>12 && frustrated))
717 fprintf(fp, " updated_cost=%g\n", multi.swarm[si].particle[pi].cost);
718
719
720 /* Check if this is the best position ever for this particle */
721 if(multi.swarm[si].particle[pi].bestCost>multi.swarm[si].particle[pi].cost) {
722 multi.swarm[si].particle[pi].bestCost=multi.swarm[si].particle[pi].cost;
723 doubleCopy(multi.swarm[si].particle[pi].bestPosition,
724 multi.swarm[si].particle[pi].position, dim);
725 multi.swarm[si].particle[pi].since=0;
726 } else {
727 multi.swarm[si].particle[pi].since++;
728 }
729
730 /* Check if the best position of this particle is the best ever in this swarm?
731 Note: check this separately, because of possible immigrations. */
732 if(multi.swarm[si].bestCost>multi.swarm[si].particle[pi].bestCost) {
733 multi.swarm[si].bestCost=multi.swarm[si].particle[pi].bestCost;
734 doubleCopy(multi.swarm[si].bestPosition, multi.swarm[si].particle[pi].bestPosition, dim);
735 multi.swarm[si].since=0;
736 }
737
738 } // next particle
739
740 /* Is the best particle of this swarm the best particle in all swarms? */
741 if(multi.bestCost>multi.swarm[si].bestCost) {
742 multi.bestCost=multi.swarm[si].bestCost;
743 doubleCopy(multi.bestPosition, multi.swarm[si].bestPosition, dim);
744 multi.since=0;
745 }
746
747 } // next swarm
748
749 /* Check if each swarm has concentrated inside tolerance */
750 if(swarmsConcentrated==nSwarms) {
751 if(verbose>2) fprintf(fp, " all swarm particles shrunk inside swarm tolerance.\n");
752 break;
753 }
754
755
756 /* Stop if the best particle in each swarm is inside tolerances of parameters;
757 all swarms have then converged to the same position. */
758 if(nSwarms>1 && iterNr>10) {
759 int swarmsConverged=1;
760 for(unsigned int i=0; i<dim; i++) {
761 for(unsigned int si=0; si<nSwarms; si++) {
762 double d=fabs(multi.bestPosition[i]-multi.swarm[si].bestPosition[i]);
763 if(d>nlo->xtol[i]) {swarmsConverged=0; convergenceCounter=0; break;}
764 }
765 if(!swarmsConverged) break;
766 }
767 if(swarmsConverged) {
768 convergenceCounter++;
769 if(convergenceCounter>5) {
770 if(verbose>3) fprintf(fp, "all swarms converged into one minimum.\n");
771// break;
772 }
773 }
774 }
775
776
777 /* Stop if the best overall position stops moving */
778 if(iterNr>=20) {
779 int moved=0;
780 for(unsigned int i=0; i<dim; i++) {
781 double d=fabs(lastBestPosition[i]-multi.bestPosition[i]);
782 if(d>0.1*nlo->xtol[i]) {moved=1; movementCounter=0; break;}
783 }
784 if(moved==0) {
785 movementCounter++;
786 if(movementCounter>10) {
787 if(verbose>3)
788 fprintf(fp, "best position did not improve in %d last loops.\n", movementCounter);
789#if(0)
790 if(verbose>80 && movementCounter>10) {
791 fprintf(fp, "Why does the movement not continue?\n");
792 for(unsigned int si=0; si<nSwarms; si++) {
793 fprintf(fp, "Swarm %d : bestCost=%g\n", 1+si, multi.swarm[si].bestCost);
794 /* Search the currently best particle to get its also its velocity */
795 unsigned int pBest=0;
796 double pBestCost=multi.swarm[si].particle[0].cost;
797 for(unsigned int pi=1; pi<nParticles; pi++)
798 if(multi.swarm[si].particle[pi].cost<pBestCost) {
799 pBestCost=multi.swarm[si].particle[pi].cost; pBest=pi;
800 }
801 fprintf(fp, " currentBestCost=%g\n", pBestCost);
802 fprintf(fp, "\tDim\toPos\tcPos\tcVel\n");
803 for(unsigned int i=0; i<dim; i++) {
804 fprintf(fp, "\t%d\t%g\t%g\t%g\n", 1+i, multi.swarm[si].bestPosition[i],
805 multi.swarm[si].particle[pBest].position[i],
806 multi.swarm[si].particle[pBest].velocity[i]);
807 }
808 }
809 }
810#endif
811 }
812 }
813 if(movementCounter>20+dim) {
814 fprintf(fp, "best position did not move markedly in %d last loops.\n", movementCounter);
815 break;
816 }
817 }
818 doubleCopy(lastBestPosition, multi.bestPosition, dim);
819
820
821 /* Check that cost is improving */
822 if(multi.bestCost<lastBestCost) {
823 lastBestCost=multi.bestCost;
824 stopCost=0;
825 } else {
826 stopCost++;
827 }
828 if(stopCost>=stopCostLimit) {
829 if(verbose>1) fprintf(fp, "Cost did not improve in %d last iterations.\n", stopCost);
830 break;
831 }
832
833
834 } // next loop
835
836 /* Check the reason for loop exit */
837 if(iterNr>=maxIter) {
838 if(verbose>1) fprintf(fp, "exceeded the maximum number for loops.\n");
839 }
840 if(nlo->funCalls>=nlo->maxFunCalls) {
841 if(verbose>1) fprintf(fp, "exceeded the maximum number for function calls.\n");
842 }
843
844 /* Copy optimized parameters over initial values */
845 doubleCopy(nlo->xfull, multi.bestPosition, dim);
846
847 /* Analyze the swarms */
848 if(verbose>2) {
849 fprintf(fp, "\n---- MPSO end analysis ----\n");
850 fprintf(fp, "loops: %d\n", iterNr);
851 fprintf(fp, "function calls: %d\n", nlo->funCalls);
852 for(unsigned int si=0; si<nSwarms; si++) {
853 fprintf(fp, "\nSwarm %d : bestCost=%g\n", 1+si, multi.swarm[si].bestCost);
854 for(unsigned int i=0; i<dim; i++) {
855 fprintf(fp, "parameter %d: bestPosition %g\n", 1+i, multi.swarm[si].bestPosition[i]);
856 }
857 double pmean[dim], psd[dim];
858 nloptMPSOpMean(&multi, si, pmean, psd);
859 for(unsigned int i=0; i<dim; i++) {
860 fprintf(fp, "parameter %d: meanPosition %g +- %g\n", 1+i, pmean[i], psd[i]);
861 }
862 nloptMPSOabsvMean(&multi, si, pmean, psd);
863 for(unsigned int i=0; i<dim; i++) {
864 fprintf(fp, "parameter %d: meanAbsVelocity %g +- %g\n", 1+i, pmean[i], psd[i]);
865 }
866
867 }
868 fprintf(fp, "\nOverall bestCost=%g\n", multi.bestCost);
869 fprintf(fp, "at position: %g", multi.bestPosition[0]);
870 for(unsigned int i=1; i<dim; i++) fprintf(fp, ", %g", multi.bestPosition[i]);
871 fprintf(fp, "\n"); fflush(fp);
872 }
873
874 /* Free allocated memory */
875 for(unsigned int si=0; si<nSwarms; si++) {
876 for(unsigned int pi=0; pi<nParticles; pi++) {
877 free(multi.swarm[si].particle[pi].position);
878 free(multi.swarm[si].particle[pi].velocity);
879 free(multi.swarm[si].particle[pi].bestPosition);
880 }
881 free(multi.swarm[si].particle);
882 free(multi.swarm[si].bestPosition);
883 }
884 free(multi.bestPosition);
885 free(multi.swarm);
886
887
888 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
889 return TPCERROR_OK;
890}
891/*****************************************************************************/
892
893/*****************************************************************************/
void doubleCopy(double *t, double *s, const unsigned int n)
Definition doubleutil.c:117
int statMeanSD(double *data, unsigned int n, double *mean, double *sd, unsigned int *vn)
Definition mean.c:25
void mertwiInitWithSeed64(MERTWI *mt, uint64_t seed)
Initialize the state vector mt[] inside data structure for Mersenne Twister MT19937 pseudo-random num...
Definition mertwi.c:94
double mertwiRandomDouble1(MERTWI *mt)
Generate a 64-bit double precision floating point pseudo-random number in the range of [0,...
Definition mertwi.c:216
double mertwiRandomExponential(MERTWI *mt, double mean)
Generate pseudo-random number with exponential distribution and specified mean.
Definition mertwi.c:322
uint64_t mertwiSeed64(void)
Make uint64_t seed for pseudo-random number generators.
Definition mertwi.c:76
void mertwiInit(MERTWI *mt)
Definition mertwi.c:28
int64_t mertwiRandomInt63(MERTWI *mt)
Generate a random number on [0, 2^63-1]-interval using Mersenne Twister MT19937.
Definition mertwi.c:197
void nloptMPSOabsvMean(MPSO_MULTISWARM *ms, unsigned int si, double *mean, double *sd)
Definition mpso.c:97
void nloptMPSOpMean(MPSO_MULTISWARM *ms, unsigned int si, double *mean, double *sd)
Definition mpso.c:76
int nloptMPSO(NLOPT *nlo, unsigned int maxIter, unsigned int nSwarms, unsigned int nParticles, double wInertia, double wParticle, double wSwarm, double wGlobal, double pDeath, double pImmigration, const int doLocal, TPCSTATUS *status)
Definition mpso.c:129
unsigned int nloptLimitFixedNr(NLOPT *d)
Definition nlopt.c:333
int nloptRandomPoint(double *p, double *low, double *up, unsigned int n, MERTWI *mt)
Definition rndpoint.c:28
int nloptGaussianPoint(double *p, double *mean, double *sd, double *low, double *up, unsigned int n, MERTWI *mt)
Definition rndpoint.c:70
int nloptSimplex(NLOPT *nlo, unsigned int maxIter, TPCSTATUS *status)
Definition simplex.c:32
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
double(* _fun)(int, double *, void *)
Definition tpcnlopt.h:42
double funval
Definition tpcnlopt.h:50
unsigned int maxFunCalls
Definition tpcnlopt.h:46
double * xupper
Definition tpcnlopt.h:33
double * xlower
Definition tpcnlopt.h:31
void * fundata
Definition tpcnlopt.h:44
double * xfull
Definition tpcnlopt.h:29
unsigned int funCalls
Definition tpcnlopt.h:48
double * xdelta
Definition tpcnlopt.h:36
unsigned int usePList
Definition tpcnlopt.h:52
double * xtol
Definition tpcnlopt.h:39
double * plist
Definition tpcnlopt.h:56
unsigned int totalNr
Definition tpcnlopt.h:27
int verbose
Verbose level, used by statusPrint() etc.
FILE * fp
File pointer for writing log information during development and testing.
Header file for library libtpcextensions.
@ TPCERROR_INVALID_VALUE
Invalid value.
@ TPCERROR_FAIL
General error.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
Header file for library libtpcnlopt.
Header file for libtpcrand.
Header file for libtpcstatist.