|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T l
Length: 16297 (0x3fa9)
Types: TextFile
Names: »learn.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Rog-O-Matic/learn.c«
/*
* learn.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:30:10 1985 - mlm
* Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
*
* Genetic learning component.
*/
# include <stdio.h>
# include "types.h"
# define TRIALS(g) ((g)->score.count)
# define NONE (-1)
# define MAXM 100
# define ALLELE 100
# define ZEROSTAT {0, 0, 0, 0, 0}
typedef struct
{ int id, creation, father, mother, dna[MAXKNOB];
statistic score, level;
} genotype;
extern int knob[];
extern double mean(), stdev(), sqrt();
extern FILE *wopen();
static int inittime=0, trialno=0, lastid=0;
static int crosses=0, shifts=0, mutations=0;
static statistic g_score = ZEROSTAT;
static statistic g_level = ZEROSTAT;
static genotype *genes[MAXM];
static int length = 0;
static int mindiff = 10, pmutate = 4, pshift = 2, mintrials = 1;
static double step = 0.33; /* standard deviations from the mean */
static FILE *glog=NULL;
static int compgene();
/*
* Start a new gene pool
*/
initpool (k, m)
{ inittime = time (0);
if (glog) fprintf (glog, "Gene pool initalized, k %d, m %d, %s",
k, m, ctime (&inittime));
randompool (m);
}
/*
* Summarize the current gene pool
*/
analyzepool (full)
int full;
{ register int g;
qsort (genes, length, sizeof (*genes), compgene);
printf ("Gene pool size %d, started %s", length, ctime (&inittime));
printf ("Trials %d, births %d (crosses %d, mutations %d, shifts %d)\n",
trialno, lastid, crosses, mutations, shifts);
printf ("Mean score %1.0lf+%1.0lf, Mean level %3.1lf+%3.1lf\n\n",
mean (&g_score), stdev (&g_score),
mean (&g_level), stdev (&g_level));
for (g=0; g<length; g++)
{ printf ("Living: "); summgene (stdout, genes[g]);
if (full)
{ if (genes[g]->mother)
printf (" Parents: %3d,%-3d", genes[g]->father, genes[g]->mother);
else
printf (" Parent: %3d, ", genes[g]->father);
printf (" best %4.0lf/%-2.0lf",
genes[g]->score.high, genes[g]->level.high);
printf (" DNA "); printdna (stdout, genes[g]); printf ("\n\n");
}
}
}
/*
* setknobs: Read gene pool, pick genotype, and set knobs accordingly.
*/
setknobs (newid, knob, best, avg)
int *newid, *knob, *best, *avg;
{ register int i, g;
++trialno;
g = pickgenotype (); /* Pick one genotype */
*newid = genes[g]->id;
for (i=0; i<MAXKNOB; i++) /* Set the knobs for that genotype */
knob[i] = genes[g]->dna[i];
*best = genes[g]->score.high;
*avg = (int) mean (&(genes[g]->score));
}
/*
* evalknobs: Add a data point to the gene pool
*/
evalknobs (gid, score, level)
int gid, score, level;
{ register int g;
/* Find out which gene has the correct id */
for (g=0; g<length; g++)
if (gid == genes[g]->id) break;
/* If he got deleted by someone else, blow it off */
if (g >= length) return;
/* Add information about performance */
addstat (&(genes[g]->score), score);
addstat (&g_score, score);
addstat (&(genes[g]->level), level);
addstat (&g_level, level);
if (glog)
{ fprintf (glog, "Trial %4d, Id %3d -> %4d/%-2d ",
trialno, genes[g]->id, score, level);
fprintf (glog, "age %2d, %4.0lf+%-4.0lf %4.1lf+%3.1lf\n",
TRIALS(genes[g]),
mean (&(genes[g]->score)), stdev (&(genes[g]->score)),
mean (&(genes[g]->level)), stdev (&(genes[g]->level)));
}
}
/*
* openlog: Open the gene log file
*/
FILE *openlog (genelog)
register char *genelog;
{ glog = wopen (genelog, "a");
return (glog);
}
/*
* closelog: Close the log file
*/
closelog ()
{ if (glog) fclose (glog);
}
/*
* pickgenotype: Run one trial, record performance, and do some learning
*/
pickgenotype ()
{ register int youth, father, mother, new;
/* Find genotype with fewer trials than needed to measure its performance */
youth = untested ();
if (youth >= 0) return (youth);
/*
* Have a good measure of all genotypes, pick a father, a mother, and
* a loser and create a new genotype using genetic operators.
*/
father = selectgene (NONE, NONE);
mother = selectgene (father, NONE);
new = badgene (father, mother);
/* If no losers yet, return the youngest */
if (new < 0) return (youngest ());
/* Shift a single genotype with probability pshift */
if (randint (100) < pshift)
{ if (glog)
{ fprintf (glog, "Select: "); summgene (glog, genes[father]);
fprintf (glog, "Death: "); summgene (glog, genes[new]);
}
shift (father, new);
}
/* Mutate a single genotype with probability pmutate */
else if (randint (100-pshift) < pmutate)
{ if (glog)
{ fprintf (glog, "Select: "); summgene (glog, genes[father]);
fprintf (glog, "Death: "); summgene (glog, genes[new]);
}
mutate (father, new);
}
/* Cross two genotypes with probability 1-pshift-pmutate */
else
{ if (glog)
{ fprintf (glog, "Select: "); summgene (glog, genes[father]);
fprintf (glog, "Select: "); summgene (glog, genes[mother]);
fprintf (glog, "Death: "); summgene (glog, genes[new]);
}
cross (father, mother, new);
}
/* Log the birth */
if (glog) birth (glog, genes[new]);
return (new); /* Evaluate the new genotype */
}
/*
* readgenes: Open the genepool for reading, and fill the current gene pool.
* Returns true if the file was was, and 0 if there was no fail. Exits
* if the file exists and cannot be read.
*/
readgenes (genepool)
register char *genepool;
{ char buf[BUFSIZ];
register char *b;
register int g=0;
FILE *gfil;
if ((gfil = fopen (genepool, "r")) == NULL)
{ if (fexists (genepool))
quit (1, "Cannot open file '%s'\n", genepool);
else
return (0);
}
/* Read the header line */
b = buf;
fgets (b, BUFSIZ, gfil);
sscanf (b, "%d %d %d %d %d %d",
&inittime, &trialno, &lastid, &crosses, &shifts, &mutations);
SKIPTO ('|', b);
parsestat (b, &g_score);
SKIPTO ('|', b);
parsestat (b, &g_level);
/* Now read in each genotype */
while (fgets (buf, BUFSIZ, gfil) && length < MAXM-1)
{ if (g >= length)
{ genes[g] = (genotype *) malloc (sizeof (**genes));
length++;
}
initgene (genes[g]);
parsegene (buf, genes[g++]);
}
fclose (gfil);
return (1);
}
/*
* parsegene: Given a string representing a genotype and a genotype
* structure, fill the structure according to the string.
*/
static parsegene (buf, gene)
register char *buf;
register genotype *gene;
{ register int i;
/* Get genotype specific info */
sscanf (buf, "%d %d %d %d", &gene->id, &gene->creation,
&gene->father, &gene->mother);
/* Read each DNA gene */
SKIPTO ('|', buf);
SKIPCHAR (' ', buf);
for (i=0; ISDIGIT (*buf); i++)
{ if (i < MAXKNOB) gene->dna[i] = atoi (buf);
SKIPDIG (buf);
SKIPCHAR (' ', buf);
}
/* Read the score and level performance stats */
SKIPTO ('|', buf);
parsestat (buf, &(gene->score));
SKIPTO ('|', buf);
parsestat (buf, &(gene->level));
}
/*
* writegenes: Write the gene pool 'genes' out to file 'genepool'
*/
writegenes (genepool)
register char *genepool;
{ register FILE *gfil;
register int g;
/* Open the gene file */
if ((gfil = wopen (genepool, "w")) == NULL)
quit (1, "Cannot open file '%s'\n", genepool);
/* Write the header line */
fprintf (gfil, "%d %d %d %d %d %d",
inittime, trialno, lastid, crosses, shifts, mutations);
fprintf (gfil, "|");
writestat (gfil, &g_score);
fprintf (gfil, "|");
writestat (gfil, &g_level);
fprintf (gfil, "|\n");
/* Loop through each genotype */
for (g=0; g<length; g++)
writegene (gfil, genes[g]);
fclose (gfil);
}
/*
* Write out one line representing the gene.
*/
static writegene (gfil, g)
register FILE *gfil;
register genotype *g;
{ register int i;
/* Print genotype specific info */
fprintf (gfil, "%3d %4d %3d %3d|", g->id, g->creation,
g->father, g->mother);
/* Write out dna */
for (i=0; i<MAXKNOB; i++)
{ fprintf (gfil, "%2d", g->dna[i]);
if (i < MAXKNOB-1) fprintf (gfil, " ");
}
fprintf (gfil, "|");
/* Write out statistics */
writestat (gfil, &(g->score));
fprintf (gfil, "|");
writestat (gfil, &(g->level));
fprintf (gfil, "|\n");
}
/*
* initgene: Allocate a new genotype structure, set everything to 0.
*/
static initgene (gene)
register genotype *gene;
{ register int i;
/* Clear genoptye specific info */
gene->id = gene->creation = gene->father = gene->mother = 0;
/* Clear the dna */
for (i = 0; i < MAXKNOB; i++) gene->dna[i] = 0;
/* Clear the statictics */
clearstat (&(gene->score));
clearstat (&(gene->level));
}
/*
* compgene: Compare two genotypes in terms of score.
*/
static int compgene (a, b)
genotype **a, **b;
{ register int result;
result = (int) mean (&((*b)->score)) -
(int) mean (&((*a)->score));
if (result) return (result);
else return ((*a)->id - (*b)->id);
}
/*
* summgene: Summarize a single genotype
*/
static summgene (f, gene)
register FILE *f;
register genotype *gene;
{ fprintf (f, "%3d age %2d, created %4d, ",
gene->id, TRIALS(gene), gene->creation);
fprintf (f, "score %5.0lf+%-4.0lf level %4.1lf+%-3.1lf\n",
mean (&(gene->score)), stdev (&(gene->score)),
mean (&(gene->level)), stdev (&(gene->level)));
}
/*
* Birth: Summarize Record the birth of a genotype.
*/
static birth (f, gene)
register FILE *f;
register genotype *gene;
{
if (!glog) return;
fprintf (f, "Birth: %d ", gene->id);
if (gene->mother)
fprintf (f, "(%d,%d)", gene->father, gene->mother);
else
fprintf (f, "(%d)", gene->father);
fprintf (f, " created %d, DNA ", gene->creation);
printdna (f, gene);
fprintf (f, "\n");
}
/*
* printdna: Print the genotype of a gene
*/
static printdna (f, gene)
FILE *f;
register genotype *gene;
{ register int i;
fprintf (f, "(");
for (i=0; i < MAXKNOB; i++)
{ fprintf (f, "%02d", gene->dna[i]);
if (i < MAXKNOB-1) fprintf (f, " ");
}
fprintf (f, ")");
}
/*
* cross: Cross two genotypes producing a new genotype
*/
static cross (father, mother, new)
register int father, mother, new;
{ register int cpoint, i;
/* Set the new genotypes info */
genes[new]->id = ++lastid;
genes[new]->creation = trialno;
genes[new]->father = genes[father]->id;
genes[new]->mother = genes[mother]->id;
clearstat (&(genes[new]->score));
clearstat (&(genes[new]->level));
/* Pick a crossover point and dominant parent */
cpoint = randint (MAXKNOB-1) + 1;
/* Fifty/fifty chance we swap father and mother */
if (randint (100) < 50)
{ father ^= mother; mother ^= father; father ^= mother; }
/* Copy the dna over */
for (i=0; i<MAXKNOB; i++)
genes[new]->dna[i] = (i<cpoint) ?
genes[father]->dna[i] : genes[mother]->dna[i];
makeunique (new);
/* Log the crossover */
if (glog)
{ fprintf (glog, "Crossing %d and %d produces %d\n",
genes[father]->id, genes[mother]->id, genes[new]->id);
}
crosses++;
}
/*
* mutate: mutate a genes producing a new gene
*/
static mutate (father, new)
register int father, new;
{ register int i;
/* Set the new genotypes info */
genes[new]->id = ++lastid;
genes[new]->creation = trialno;
genes[new]->father = genes[father]->id;
genes[new]->mother = 0;
clearstat (&(genes[new]->score));
clearstat (&(genes[new]->level));
/* Copy the dna over */
for (i=0; i<MAXKNOB; i++)
genes[new]->dna[i] = genes[father]->dna[i];
/* Randomly change genes until the new genotype is unique */
do
{ i=randint (MAXKNOB);
genes[new]->dna[i] = (genes[new]->dna[i] +
triangle (20) + ALLELE) % ALLELE;
} while (!unique (new));
/* Log the mutation */
if (glog)
{ fprintf (glog, "Mutating %d produces %d\n",
genes[father]->id, genes[new]->id);
}
mutations++;
}
/*
* shift: shift a gene producing a new gene
*/
static shift (father, new)
register int father, new;
{ register int i, offset;
/* Set the new genotypes info */
genes[new]->id = ++lastid;
genes[new]->creation = trialno;
genes[new]->father = genes[father]->id;
genes[new]->mother = 0;
clearstat (&(genes[new]->score));
clearstat (&(genes[new]->level));
/* Pick an offset, triangularly distributed around 0, until unique */
offset = triangle (20);
for (i=0; i<MAXKNOB; i++)
genes[new]->dna[i] = (genes[father]->dna[i] +
offset + ALLELE) % ALLELE;
makeunique (new);
/* Now log the shift */
if (glog)
{ fprintf (glog, "Shifting %d by %d produces %d\n",
genes[father]->id, offset, genes[new]->id);
}
shifts++;
}
/*
* randompool: Initialize the pool to a random starting point
*/
static randompool (m)
register int m;
{ register int i, g;
for (g=0; g<m; g++)
{ if (g >= length)
{ genes[g] = (genotype *) malloc (sizeof (**genes));
length++;
}
initgene (genes[g]);
genes[g]->id = ++lastid;
for (i=0; i<MAXKNOB; i++) genes[g]->dna[i] = randint (ALLELE);
birth (glog, genes[g]);
}
length = m;
}
/*
* selectgene: Select a random gene, weighted by mean score.
*/
static selectgene (e1, e2)
register int e1, e2;
{ register int total=0;
register int g;
/* Find the total worth */
for (g=0; g<length; g++)
{ if (g==e1 || g==e2) continue;
/* total += (int) mean (&(genes[g]->score)); */
total += genes[g]->score.high;
}
/* Pick a random number and find the corresponding gene */
if (total > 0)
{ for (g=0, total=randint (total); g<length; g++)
{ if (g==e1 || g==e2) continue;
/* total -= (int) mean (&(genes[g]->score)); */
total -= genes[g]->score.high;
if (total < 0) return (g);
}
}
/* Total worth zero, pick any gene at random */
while ((g = randint (length))==e1 || g==e2) ;
return (g);
}
/*
* unique: Return false if gene is an exact copy of another gene.
*/
static unique (new)
register int new;
{ register int g, i, delta, sumsquares;
for (g=0; g<length; g++)
{ if (g != new)
{ sumsquares = 0;
for (i=0; i<MAXKNOB; i++)
{ delta = genes[g]->dna[i] - genes[new]->dna[i];
sumsquares += delta * delta;
}
if (sumsquares < mindiff) return (0);
}
}
return (1);
}
/*
* untested: Return the index of the youngest genotype with too few
* trials to have an accurate measure. The number of trials is
* greater for older genotypes.
*/
static untested ()
{ register int g, y= -1, trials=1e9, newtrials, count=length;
for (g = randint (length); count-- > 0; g = (g+1) % length)
{ if (TRIALS (genes[g]) >= trials) continue;
newtrials = trialno - genes[g]->creation; /* Turns since creation */
if (TRIALS (genes[g]) < newtrials / (4 * length) + mintrials)
{ y = g; trials = TRIALS (genes[g]); }
}
return (y);
}
/*
* youngest: Return the index of the youngest genotype
*/
static youngest ()
{ register int g, y=0, trials=1e9, newtrials, count=length;
for (g = randint (length); count-- > 0; g = (g+1) % length)
{ newtrials = TRIALS (genes[g]);
if (newtrials < trials) { y=g; trials=newtrials; }
}
return (y);
}
/*
* makeunique: Mutate a genotype until it is unique
*/
static makeunique (new)
register int new;
{ register int i;
while (!unique (new))
{ i=randint (MAXKNOB);
genes[new]->dna[i] = (genes[new]->dna[i] +
triangle (20) + ALLELE) % ALLELE;
}
}
/*
* triangle: Return a non-zero triangularly distributed number from -n to n.
*/
static triangle (n)
register int n;
{ register int val;
do
{ val = randint (n) - randint (n);
} while (val==0);
return (val);
}
/*
* badgene: Find the worst performer so far (with the lowest id).
* only consider genotypes dominated by other genotypes.
*/
static badgene (e1, e2)
register int e1, e2;
{ register int g, worst, trials;
double worstval, bestval, avg, dev, value;
worst = -1; worstval = 1.0e9;
bestval = -1.0e9;
for (g=0; g<length; g++)
{ if ((trials = TRIALS (genes[g])) < mintrials) continue;
avg = mean (&(genes[g]->score));
dev = stdev (&(genes[g]->score)) / sqrt ((double) trials);
value = avg - step * dev;
if (value > bestval) { bestval=value; }
if (g==e1 || g==e2) continue;
value = avg + step * dev;
if (value < worstval) { worst=g; worstval=value; }
}
if (worstval < bestval) return (worst);
else return (-1);
}