Output of file : MCLAUGHL.LST contained in archive : DDJ0989.ZIP
_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;
int code;
} cards;
float ratios;
int tableau,best_tableau;
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 = {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;
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],&ratios[i]);
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]) {
t_ratio = ratios[next];
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 index = uni(size);
temp = array[--size];
array[size] = array[index];
array[index] = temp;
}
}
void reconfigure(direction)
/* If direction is FORWARD, make a new move; if it is BACK, restore
the tableau to its previous configuration. */
int direction;
{
static long partition = {0,0,715827799,1296031795,1766307855,
2147483400};
static int hindex = {0,1,2,3,4,5,6,7,8,9,10,11};
static int cindex = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,
14,15,16,17,18,19,20,21,22,23,24};
static int overlap = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,5,10,15,
20,1,6,11,16,21,-1,2,7,12,17,22,-1,-1,3,
8,13,18,23,-1,-1,-1,4,9,14,19,24,-1,-1,-1,
-1,0,6,12,18,24,0,6,12,18,24,4,8,12,16,20,
20,16,12,8,4,12};
static int mode,nchoices,common,last; /* remember changes */
int temp,hi,lo,i,j,k;
if (direction == FORWARD) {
if (rand1() < exg_cutoff) { /* giant step */
mode = 1; nchoices = 2;
selectwr(hindex,mode,nchoices);
hi = hindex; lo = hindex; /* order hand indices */
if (hi < lo) {
hi = lo;
lo = hindex;
}
common = overlap[hi*(hi-1)/2+lo]; /* triangular matrix */
}
else { /* baby step */
mode = 0; nchoices = 2;
rand1(); /* How many cards to rotate? */
while (seed > partition[nchoices])
nchoices++;
selectwr(cindex,mode,nchoices);
temp = tableau[cindex]; /* rotate forward */
for (i=1,j=24;i tableau[cindex[j]] = tableau[cindex[j-1]];
tableau[cindex[j]] = temp;
last = j;
}
}
if (mode == 1) { /* swapping hands is symmetrical */
register first,second,c;
first = hindex; second = hindex;
k = (common<0) ? 5 : 4;
for (c=0,i=0,j=0;c if (hand[first][i] == common)
i++;
if (hand[second][j] == common)
j++;
temp = tableau[hand[first][i]];
tableau[hand[first][i]] = tableau[hand[second][j]];
tableau[hand[second][j]] = temp;
}
}
else if (direction == BACK) { /* rotation is not */
temp = tableau[cindex[last]];
for (i=1,j=last;i tableau[cindex[j]] = tableau[cindex[j+1]];
tableau[cindex] = temp;
}
}
long get_score(crds)
/* Return score of one hand. */
int *crds;
{
static long scores = {0,1,1,20,1,9,20,1760,1,9,9,
293,20,293,1760,108,215,27456};
int flush,i,index = 0;
flush = crds&crds&crds&crds&crds&0xff00;
for (i=0;i<5;i++)
crds[i] = crds[i]&0xff; /* ignore suits */
{
register b,k,t; /* sort cards from high to low */
for (b=4;b>0;b--)
for (k=0;k if (crds[k] < crds[k+1]) {
t = crds[k];
crds[k] = crds[k+1];
crds[k+1] = t;
}
}
if (!flush) { /* multiple cards ? */
if (crds == crds) index += 8;
if (crds == crds) index += 4;
if (crds == crds) index += 2;
if (crds == crds) index += 1;
}
if (!index) { /* straight ? */
if (((crds-crds) == 4)||((crds == 14)&&(crds == 5)))
index = 15;
if (flush)
index = (index == 15) ? 17 : 16;
}
return(scores[index]);
}
long evaluate1()
{
int temp,h,c;
long scr = 0;
for (h=0;h<12;h++) { /* h<13 for corners */
for (c=0;c<5;c++)
temp[c] = tableau[hand[h][c]];
scr += get_score(temp);
}
return(scr);
}
void decide()
/* Either accept new configuration or restore old configuration */
{
float pdt1,pdt2,sscor;
long s;
BOOLEAN acceptable = FALSE;
scor = evaluate1();
if (scor >= 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,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 printf("%s",cards[temp[j]].card);
}
printf("\n");
}
printf("\n");
}
}
void try_new_temperature()
{
init();
while (!equilibrium) {
reconfigure(FORWARD);
decide();
check_equilibrium();
}
update();
if (!quench) { /* ratchet */
while ((float) score < score_limit) { /* maximization */
reconfigure(FORWARD);
decide();
}
}
}
main()
{
initialize();
while (!frozen) {
try_new_temperature();
update();
if ((step == report_time)||(frozen))
report();
step++;
if (temperature > 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
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



### 3 Responses to “Category : Files from MagazinesArchive   : DDJ0989.ZIPFilename : MCLAUGHL.LST”

1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/