_SIMULATED ANNEALING_ by Michael P. McLaughlin [LISTING ONE] /* ANNEAL.C -- Author: Dr. Michael P. McLaughlin */ #include #include #define ABS(x) ((x<0)?(-(x)):(x)) #define BOOLEAN int #define TRUE 1 #define FALSE 0 #define FORWARD 1 #define BACK 0 struct cardtype { char card[3]; int code; } cards[25]; float ratios[10][2]; int tableau[25],best_tableau[25]; float temperature,best_temperature,t_low,t_min,t_ratio; long seed,score,best_score,tot_successes,tot_failures,scor,exg_cutoff, report_time,report_interval,modulus = 2147483399,step = 1; int next; BOOLEAN equilibrium,frozen = FALSE,quench=FALSE,final=FALSE; /* variables needed to assess equilibrium */ float totscore,totscore2,avg_score,sigma,half_sigma,score_limit; long bscore,wscore,max_change,nsuccesses,nfailures,scale, incount,outcount; int incount_limit,outcount_limit,succ_min,first_limit,ultimate_limit; /* poker hands in tableau */ int hand[12][5] = {0,1,2,3,4, /* rows */ 5,6,7,8,9, 10,11,12,13,14, 15,16,17,18,19, 20,21,22,23,24, 0,5,10,15,20, /* columns */ 1,6,11,16,21, 2,7,12,17,22, 3,8,13,18,23, 4,9,14,19,24, 0,6,12,18,24, /* diagonals */ 4,8,12,16,20}; /* 0,4,12,20,24 = corners */ long rand1() /* Get uniform 31-bit integer -- Ref. CACM, June 1988, pg. 742 */ { register long k; k = seed/52774; seed = 40692*(seed-k*52774)-k*3791; if (seed < 0) seed += modulus; return(seed); } double uni(z) int z; { return((double) z*rand1()/modulus); } void initialize() /* Set up entire simulated annealing run. */ { char label[20]; double exgc; register i; FILE *fp; fp = fopen("a.dat","r"); fscanf(fp,"%f %s\n",&temperature,label); fscanf(fp,"%f %s\n",&t_low,label); fscanf(fp,"%f %s\n",&t_min,label); fscanf(fp,"%f %s\n",&avg_score,label); fscanf(fp,"%ld %s\n",&scale,label); fscanf(fp,"%f %s\n",&t_ratio,label); fscanf(fp,"%f %s\n",&sigma,label); fscanf(fp,"%lf %s\n",&exgc,label); fscanf(fp,"%d %s\n",&succ_min,label); fscanf(fp,"%d %s\n",&incount_limit,label); fscanf(fp,"%d %s\n",&outcount_limit,label); fscanf(fp,"%d %s\n",&first_limit,label); fscanf(fp,"%d %s\n",&ultimate_limit,label); fscanf(fp,"%ld %s\n",&report_interval,label); fscanf(fp,"%ld %s\n",&seed,label); half_sigma = 0.5*sigma; report_time = report_interval; score_limit = 20; exg_cutoff = modulus*exgc; for (i=0;i<10;i++) fscanf(fp,"%f %f\n",&ratios[i][0],&ratios[i][1]); for (i=0;i<25;i++) { fscanf(fp,"%d %s\n",&cards[i].code,cards[i].card); tableau[i] = cards[i].code; } fclose(fp); printf(" TOTAL TOTAL CURRENT AVERAGE\n"); printf("STEP TEMPERATURE SUCCESSES FAILURES SCORE SCORE "); printf(" SIGMA\n\n"); } void init() /* set up for new temperature */ { nsuccesses = 0; nfailures = 0; equilibrium = FALSE; incount = 0; outcount = 0; bscore = 0; wscore = 100000; max_change = 0; totscore = 0; totscore2 = 0; if (temperature < t_min) frozen = TRUE; } void get_new_temperature() { if (temperature < ratios[next][0]) { t_ratio = ratios[next][1]; next++; } temperature = t_ratio*temperature; } void check_equilibrium() /* Determine whether equilibrium has been reached. */ { if ((nsuccesses+nfailures) > ultimate_limit) equilibrium = TRUE; else if (nsuccesses >= succ_min) { if (incount > incount_limit) equilibrium = TRUE; else { if (outcount > outcount_limit) { if (nsuccesses > first_limit) equilibrium = TRUE; else { incount = 0; outcount = 0; } } } } } void update() /* Compute statistics, etc. */ { float ascore,s; if (nsuccesses > 0) { ascore = totscore/nsuccesses; avg_score = ascore+scale; s = totscore2/nsuccesses-ascore*ascore; if (s > 0.0) { sigma = sqrt(s); half_sigma = 0.5*sigma; score_limit = avg_score-half_sigma; } } if ((temperature < t_low)&&((bscore-wscore) == max_change)) frozen = TRUE; } void selectwr(array,mode,nchoices) /* Select from array without replacement. */ int *array,mode,nchoices; { int i,temp,size,index; size = mode==1 ? 12 : 25; for (i=0;i partition[nchoices]) nchoices++; selectwr(cindex,mode,nchoices); temp = tableau[cindex[24]]; /* rotate forward */ for (i=1,j=24;i0;b--) for (k=0;k= score) { if (scor > best_score) { register i; best_score = scor; best_temperature = temperature; for (i=0;i<25;i++) best_tableau[i] = tableau[i]; } acceptable = TRUE; } else if (temperature > 0.0) { /* uphill movement? */ if (uni(1) < exp((scor-score)/temperature)) /* Equation 2 */ acceptable = TRUE; } if (acceptable) { /* statistics, etc. */ s = ABS(score-scor); if (s > max_change) max_change = s; score = scor; sscor = scor-scale; /* to aid precision of sigma */ totscore += sscor; totscore2 += sscor*sscor; nsuccesses++; if (ABS(avg_score-score) < half_sigma) incount++; else outcount++; if (score > bscore) /* maximization */ bscore = score; else if (score < wscore) wscore = score; } else { /* unacceptable */ reconfigure(BACK); nfailures++; } } void report() { tot_successes += nsuccesses; tot_failures += nfailures; printf("%3ld %10.1f %9ld %9ld %7ld %7.0f %5.1f\n",step,temperature, tot_successes,tot_failures,score,avg_score,sigma); report_time += report_interval; if (frozen) { int temp[25],k,kk; register i,j; BOOLEAN ok; if (final) printf("\nFINAL -- "); else if (quench) printf("\nQUENCH -- "); else printf("\nFROZEN -- "); printf("BEST SCORE = %5ld BEST TEMPERATURE = %5.1f\n\n", best_score,best_temperature); for (i=0;i<25;i++) { k = best_tableau[i]; j = 0; ok = FALSE; while (!ok) { if (cards[j].code == k) { temp[i] = j; ok = TRUE; } else j++; } } for (i=0;i<25;i+=5) { for (j=i;j<(i+5);j++) { k = 4-strlen(cards[temp[j]].card); for (kk=0;kk 0.0) get_new_temperature(); } /* Quench frozen configuration. */ temperature = 0; quench = TRUE; try_new_temperature(); update(); report(); step++; /* Quench best configuration (rarely useful). */ { register i; final = TRUE; for (i=0;i<25;i++) tableau[i] = best_tableau[i]; } try_new_temperature(); update(); report(); printf("SEED = %ld\n",seed); /* seed of next run */ } [LISTING TWO] if ((nsuccesses+nfailures) > ULTIMATE_LIMIT) equilibrium = true; else if (nsuccesses >= SUCC_MIN) { if (incount > INCOUNT_LIMIT) equilibrium = true; else { if (outcount > OUTCOUNT_LIMIT) { if (nsuccesses > FIRST_LIMIT) equilibrium = true; else { incount = 0; outcount = 0; } } } } [LISTING THREE] 2150 temperature 1.5 t_low 0.1 t_min 40 avg_score 4400 scale 0.7 t_ratio 150 sigma 0.2 exg_cutoff 200 succ_min 250 incount_limit 400 outcount_limit 2700 first_limit 10000 ultimate_limit 1 report_interval 1234567890 seed 360 0.8 215 0.7 85 0.8 60 0.9 30 0.95 15 0.9 7 0.8 3 0.7 0 0.7 0 0.7 1032 8H 2061 KS 270 AC 526 AD 522 10D 1029 5H 265 9C 1035 JH 1037 KH 525 KD 515 3D 263 7C 2058 10S 2062 AS 518 6D 1036 QH 267 JC 259 3C 2053 5S 269 KC 520 8D 1028 4H 1038 AH 519 7D 1026 2H [EXAMPLE 1] Equation 1: N /su/hi//N /su/lo/ = exp((E lo-E hi)/kT) Equation 2: Prob(accept worse score) = exp((S /su/lo/ -S /su/hi/)/T) Example 1: Equations that describe the Boltzman distribution