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 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 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
]);