3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
35 /**H*O*C**************************************************************
37 ** No.!Version! Date ! Request ! Modification ! Author **
38 ** ---+-------+------+---------+---------------------------+------- **
39 ** 1 + 3.1 +5/18/95+ - + strategy DE/rand-to-best/1+ Storn **
40 ** + + + + included + **
41 ** 1 + 3.2 +6/06/95+C.Fleiner+ change loops into memcpy + Storn **
42 ** 2 + 3.2 +6/06/95+ - + update comments + Storn **
43 ** 1 + 3.3 +6/15/95+ K.Price + strategy DE/best/2 incl. + Storn **
44 ** 2 + 3.3 +6/16/95+ - + comments and beautifying + Storn **
45 ** 3 + 3.3 +7/13/95+ - + upper and lower bound for + Storn **
46 ** + + + + initialization + **
47 ** 1 + 3.4 +2/12/96+ - + increased printout prec. + Storn **
48 ** 1 + 3.5 +5/28/96+ - + strategies revisited + Storn **
49 ** 2 + 3.5 +5/28/96+ - + strategy DE/rand/2 incl. + Storn **
50 ** 1 + 3.6 +8/06/96+ K.Price + Binomial Crossover added + Storn **
51 ** 2 + 3.6 +9/30/96+ K.Price + cost variance output + Storn **
52 ** 3 + 3.6 +9/30/96+ - + alternative to ASSIGND + Storn **
53 ** 4 + 3.6 +10/1/96+ - + variable checking inserted + Storn **
54 ** 5 + 3.6 +10/1/96+ - + strategy indic. improved + Storn **
56 ***H*O*C*E***********************************************************/
58 /* Adopted for use in GROMACS by David van der Spoel, Oct 2001 */
71 #include "gmx_fatal.h"
78 static const char *strat[] = {
79 "DE/best/1/exp", "DE/rand/1/exp",
80 "DE/rand-to-best/1/exp", "DE/best/2/exp",
81 "DE/rand/2/exp", "DE/best/1/bin",
82 "DE/rand/1/bin", "DE/rand-to-best/1/bin",
83 "DE/best/2/bin", "DE/rand/2/bin"
86 /*------------------------Macros----------------------------------------*/
87 static void assignd(int D,real a[],real b[])
95 static real **make2d(int n,int m)
106 static void copy2range(int D,real c[],t_range r[])
110 for(i=0; (i<D); i++) {
112 while (c[i] < r[i].rmin)
114 while (c[i] > r[i].rmax)
116 /* if (c[i] < r[i].rmin)
118 if (c[i] > r[i].rmax)
125 t_genalg *init_ga(FILE *fplog,const char *infile,int D,t_range range[])
132 /*------Initializations----------------------------*/
134 /*-----Read input data------------------------------------------------*/
135 fpin_ptr = gmx_fio_fopen(infile,"r");
136 if ( fscanf(fpin_ptr,"%d",&ga->NP) != 1 || /*---choice of strategy---*/
137 fscanf(fpin_ptr,"%d",&ga->strategy) != 1 || /*---choice of strategy---*/
138 fscanf(fpin_ptr,"%lf",&ff) != 1 || /*---weight factor------------*/
139 fscanf(fpin_ptr,"%lf",&cr) != 1 || /*---crossing over factor-----*/
140 fscanf(fpin_ptr,"%d",&ga->seed) != 1 || /*---random seed----------*/
141 gmx_fio_fclose(fpin_ptr) != 1)
143 gmx_fatal(FARGS,"Error reading from file %s",infile);
152 /* Allocate memory */
153 ga->pold = make2d(ga->NP,ga->D);
154 ga->pnew = make2d(ga->NP,ga->D);
156 snew(ga->best,ga->D);
157 snew(ga->bestit,ga->D);
158 snew(ga->cost,ga->NP);
159 snew(ga->msf,ga->NP);
160 snew(ga->pres,ga->NP);
161 snew(ga->scale,ga->NP);
162 snew(ga->energy,ga->NP);
164 /*-----Checking input variables for proper range--------------*/
165 if ((ga->CR < 0) || (ga->CR > 1.0))
166 gmx_fatal(FARGS,"CR=%f, should be ex [0,1]",ga->CR);
168 gmx_fatal(FARGS,"seed=%d, should be > 0",ga->seed);
169 if ((ga->strategy < 0) || (ga->strategy > 10))
170 gmx_fatal(FARGS,"strategy=%d, should be ex {1-10}",ga->strategy);
172 /* spread initial population members */
173 for (i=0; (i<ga->NP); i++) {
174 for (j=0; (j<ga->D); j++) {
175 ga->pold[i][j] = value_rand(&(range[j]),&ga->seed);
179 fprintf(fplog,"-----------------------------------------------\n");
180 fprintf(fplog,"Genetic algorithm parameters\n");
181 fprintf(fplog,"-----------------------------------------------\n");
182 fprintf(fplog,"Number of variables: %d\n",ga->D);
183 fprintf(fplog,"Population size: %d\n",ga->NP);
184 fprintf(fplog,"Strategy: %s\n",strat[ga->strategy]);
185 fprintf(fplog,"Weight factor: %g\n",ga->FF);
186 fprintf(fplog,"Crossing over factor: %g\n",ga->CR);
187 fprintf(fplog,"Random seed: %d\n",ga->seed);
188 fprintf(fplog,"-----------------------------------------------\n");
193 void update_ga(FILE *fpout_ptr,t_range range[],t_genalg *ga)
195 static int i_init=0; /* Initialisation related stuff */
196 int i, j, L, n; /* counting variables */
197 int r1,r2,r3,r4,r5; /* placeholders for random indexes */
199 if (i_init < ga->NP) {
200 /* Copy data for first force evaluation to range array */
201 copy2range(ga->D,ga->pold[i_init],range);
207 /* Now starts real genetic stuff, a new trial set is made */
208 if (ga->ipop == ga->NP) {
215 do { /* Pick a random population member */
216 /* Endless loop for ga->NP < 2 !!! */
217 r1 = (int)(rando(&ga->seed)*ga->NP);
220 do { /* Pick a random population member */
221 /* Endless loop for ga->NP < 3 !!! */
222 r2 = (int)(rando(&ga->seed)*ga->NP);
223 } while((r2==i) || (r2==r1));
226 /* Pick a random population member */
227 /* Endless loop for ga->NP < 4 !!! */
228 r3 = (int)(rando(&ga->seed)*ga->NP);
229 } while((r3==i) || (r3==r1) || (r3==r2));
232 /* Pick a random population member */
233 /* Endless loop for ga->NP < 5 !!! */
234 r4 = (int)(rando(&ga->seed)*ga->NP);
235 } while((r4==i) || (r4==r1) || (r4==r2) || (r4==r3));
238 /* Pick a random population member */
239 /* Endless loop for ga->NP < 6 !!! */
240 r5 = (int)(rando(&ga->seed)*ga->NP);
241 } while((r5==i) || (r5==r1) || (r5==r2) || (r5==r3) || (r5==r4));
244 /* Choice of strategy
245 * We have tried to come up with a sensible naming-convention: DE/x/y/z
246 * DE : stands for Differential Evolution
247 * x : a string which denotes the vector to be perturbed
248 * y : number of difference vectors taken for perturbation of x
249 * z : crossover method (exp = exponential, bin = binomial)
251 * There are some simple rules which are worth following:
252 * 1) ga->FF is usually between 0.5 and 1 (in rare cases > 1)
253 * 2) ga->CR is between 0 and 1 with 0., 0.3, 0.7 and 1. being worth to
255 * 3) To start off ga->NP = 10*ga->D is a reasonable choice. Increase ga->NP if
256 * misconvergence happens.
257 * 4) If you increase ga->NP, ga->FF usually has to be decreased
258 * 5) When the DE/ga->best... schemes fail DE/rand... usually works and
260 * EXPONENTIAL ga->CROSSOVER
261 *-------DE/ga->best/1/exp-------
262 *-------Our oldest strategy but still not bad. However, we have found several
263 *-------optimization problems where misconvergence occurs.
265 assignd(ga->D,ga->tmp,ga->pold[i]);
266 n = (int)(rando(&ga->seed)*ga->D);
269 switch (ga->strategy) {
271 /* strategy DE0 (not in our paper) */
273 ga->tmp[n] = ga->bestit[n] + ga->FF*(ga->pold[r2][n]-ga->pold[r3][n]);
276 } while((rando(&ga->seed) < ga->CR) && (L < ga->D));
280 * This is one of my favourite strategies. It works especially
281 * well when the ga->bestit[]"-schemes experience misconvergence.
282 * Try e.g. ga->FF=0.7 and ga->CR=0.5 * as a first guess.
285 /* strategy DE1 in the techreport */
287 ga->tmp[n] = ga->pold[r1][n] + ga->FF*(ga->pold[r2][n]-ga->pold[r3][n]);
290 } while((rando(&ga->seed) < ga->CR) && (L < ga->D));
293 /* DE/rand-to-ga->best/1/exp
294 * This strategy seems to be one of the ga->best strategies.
295 * Try ga->FF=0.85 and ga->CR=1.
296 * If you get misconvergence try to increase ga->NP.
297 * If this doesn't help you should play around with all three
301 /* similar to DE2 but generally better */
303 ga->tmp[n] = ga->tmp[n] + ga->FF*(ga->bestit[n] - ga->tmp[n]) +
304 ga->FF*(ga->pold[r1][n]-ga->pold[r2][n]);
307 } while((rando(&ga->seed) < ga->CR) && (L < ga->D));
310 /* DE/ga->best/2/exp is another powerful strategy worth trying */
313 ga->tmp[n] = ga->bestit[n] +
314 (ga->pold[r1][n]+ga->pold[r2][n]-ga->pold[r3][n]-ga->pold[r4][n])*ga->FF;
317 } while((rando(&ga->seed) < ga->CR) && (L < ga->D));
320 /*----DE/rand/2/exp seems to be a robust optimizer for many functions-----*/
323 ga->tmp[n] = ga->pold[r5][n] +
324 (ga->pold[r1][n]+ga->pold[r2][n]-ga->pold[r3][n]-ga->pold[r4][n])*ga->FF;
327 } while((rando(&ga->seed) < ga->CR) && (L < ga->D));
330 /*===Essentially same strategies but BINOMIAL ga->CROSSOVER===*/
332 /*-------DE/ga->best/1/bin------*/
334 for (L=0; L<ga->D; L++) {
335 /* perform D binomial trials */
336 if ((rando(&ga->seed) < ga->CR) || (L == (ga->D-1))) {
337 /* change at least one parameter */
338 ga->tmp[n] = ga->bestit[n] + ga->FF*(ga->pold[r2][n]-ga->pold[r3][n]);
344 /*-------DE/rand/1/bin------*/
346 for (L=0; L<ga->D; L++) {
347 /* perform D binomial trials */
348 if ((rando(&ga->seed) < ga->CR) || (L == (ga->D-1))) {
349 /* change at least one parameter */
350 ga->tmp[n] = ga->pold[r1][n] + ga->FF*(ga->pold[r2][n]-ga->pold[r3][n]);
356 /*-------DE/rand-to-ga->best/1/bin------*/
358 for (L=0; L<ga->D; L++) {
359 /* perform ga->D binomial trials */
360 if ((rando(&ga->seed) < ga->CR) || (L == (ga->D-1))) {
361 /* change at least one parameter */
362 ga->tmp[n] = ga->tmp[n] + ga->FF*(ga->bestit[n] - ga->tmp[n]) +
363 ga->FF*(ga->pold[r1][n]-ga->pold[r2][n]);
369 /*-------DE/ga->best/2/bin------*/
371 for (L=0; L<ga->D; L++) {
372 /* perform ga->D binomial trials */
373 if ((rando(&ga->seed) < ga->CR) || (L == (ga->D-1))) {
374 /* change at least one parameter */
375 ga->tmp[n] = ga->bestit[n] +
376 (ga->pold[r1][n]+ga->pold[r2][n]-ga->pold[r3][n]-ga->pold[r4][n])*ga->FF;
382 /*-------DE/rand/2/bin-------*/
384 for (L=0; L<ga->D; L++) {
385 /* perform ga->D binomial trials */
386 if ((rando(&ga->seed) < ga->CR) || (L == (ga->D-1))) {
387 /* change at least one parameter */
388 ga->tmp[n] = ga->pold[r5][n] +
389 (ga->pold[r1][n]+ga->pold[r2][n]-ga->pold[r3][n]-ga->pold[r4][n])*ga->FF;
396 /*===Trial mutation now in ga->tmp[]. Test how good this choice really was.==*/
397 copy2range(ga->D,ga->tmp,range);
401 gmx_bool print_ga(FILE *fp,t_genalg *ga,real msf,tensor pres,rvec scale,
402 real energy,t_range range[],real tol)
404 static int nfeval=0; /* number of function evaluations */
405 static gmx_bool bImproved;
407 real cvar; /* computes the cost variance */
408 real cmean; /* mean cost */
412 trial_cost = cost(pres,msf,energy);
413 if (nfeval < ga->NP) {
414 ga->cost[nfeval] = trial_cost;
415 ga->msf[nfeval] = msf;
416 ga->energy[nfeval] = energy;
417 copy_mat(pres,ga->pres[nfeval]);
418 copy_rvec(scale,ga->scale[nfeval]);
420 pr_rvec(debug,0,"scale",scale,DIM,TRUE);
421 pr_rvec(debug,0,"pold ",ga->pold[nfeval]+4,DIM,TRUE);
426 /* When we get here we have done an initial evaluation for all
427 * animals in the population
432 /* First iteration after first round of trials */
433 if (nfeval == ga->NP) {
434 /* Evaluate who is ga->best */
436 for (j=1; (j<ga->NP); j++) {
437 if (ga->cost[j] < ga->cost[ga->imin])
440 assignd(ga->D,ga->best,ga->pold[ga->imin]);
441 /* save best member ever */
442 assignd(ga->D,ga->bestit,ga->pold[ga->imin]);
443 /* save best member of generation */
446 if (trial_cost < ga->cost[ga->ipop]) {
447 if (trial_cost < ga->cost[ga->imin]) {
448 /* Was this a new minimum? */
449 /* if so, reset cmin to new low...*/
451 assignd(ga->D,ga->best,ga->tmp);
454 /* improved objective function value ? */
455 ga->cost[ga->ipop] = trial_cost;
457 ga->msf[ga->ipop] = msf;
458 ga->energy[ga->ipop] = energy;
459 copy_mat(pres,ga->pres[ga->ipop]);
460 copy_rvec(scale,ga->scale[ga->ipop]);
462 assignd(ga->D,ga->pnew[ga->ipop],ga->tmp);
466 /* replace target with old value */
467 assignd(ga->D,ga->pnew[ga->ipop],ga->pold[ga->ipop]);
469 /* #define SCALE_DEBUG*/
473 rvec_sub(ga->scale[ga->imin],&(ga->best[ga->D-3]),dscale);
474 if (norm(dscale) > 0) {
475 pr_rvec(fp,0,"scale",scale,DIM,TRUE);
476 pr_rvec(fp,0,"best ",&(ga->best[ga->D-3]),DIM,TRUE);
477 fprintf(fp,"imin = %d, ipop = %d, nfeval = %d\n",ga->imin,
479 gmx_fatal(FARGS,"Scale inconsistency");
484 /* Increase population member count */
487 /* End mutation loop through population? */
488 if (ga->ipop == ga->NP) {
489 /* Save ga->best population member of current iteration */
490 assignd(ga->D,ga->bestit,ga->best);
492 /* swap population arrays. New generation becomes old one */
497 /*----Compute the energy variance (just for monitoring purposes)-----------*/
498 /* compute the mean value first */
500 for (j=0; (j<ga->NP); j++)
501 cmean += ga->cost[j];
502 cmean = cmean/ga->NP;
504 /* now the variance */
506 for (j=0; (j<ga->NP); j++)
507 cvar += sqr(ga->cost[j] - cmean);
508 cvar = cvar/(ga->NP-1);
510 /*----Output part----------------------------------------------------------*/
511 if (1 || bImproved || (nfeval == ga->NP)) {
512 fprintf(fp,"\nGen: %5d\n Cost: %12.3e <Cost>: %12.3e\n"
513 " Ener: %8.4f RMSF: %8.3f Pres: %8.1f %8.1f %8.1f (%8.1f)\n"
514 " Box-Scale: %15.10f %15.10f %15.10f\n",
515 ga->gen,ga->cost[ga->imin],cmean,ga->energy[ga->imin],
516 sqrt(ga->msf[ga->imin]),ga->pres[ga->imin][XX][XX],
517 ga->pres[ga->imin][YY][YY],ga->pres[ga->imin][ZZ][ZZ],
518 trace(ga->pres[ga->imin])/3.0,
519 ga->scale[ga->imin][XX],ga->scale[ga->imin][YY],
520 ga->scale[ga->imin][ZZ]);
522 for (j=0; (j<ga->D); j++)
523 fprintf(fp,"\tbest[%d]=%-15.10f\n",j,ga->best[j]);
524 if (ga->cost[ga->imin] < tol) {
525 for (i=0; (i<ga->NP); i++) {
526 fprintf(fp,"Animal: %3d Cost:%8.3f Ener: %8.3f RMSF: %8.3f%s\n",
527 i,ga->cost[i],ga->energy[i],sqrt(ga->msf[i]),
528 (i == ga->imin) ? " ***" : "");
529 for (j=0; (j<ga->D); j++)
530 fprintf(fp,"\tParam[%d][%d]=%15.10g\n",i,j,ga->pold[i][j]);