1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
|
/* PGAPack test program.
*
* The objective is to evolve a string of characters to match a string
* supplied by the user. We will stop evolving when either we run out
* of iterations (500), or when the best string has the same evaluation
* value for 100 generations.
*
* One problem with this implementation is that ' ' is not in
* PGA_DATATYPE_CHAR if we limit it using PGA_CINIT_MIXED, PGA_CINIT_LOWER,
* or PGA_CINIT_UPPER. To fix this, we must define our own interval, and
* thus, our own mutation, initialization operators.
*
* A user function is also used to check the "done" condition; we are
* done if we've done more than 1000 iterations, or the evolved string
* is correct.
*
* Created 28 Sep 95, Brian P. Walenz. Thanks to Dan Ashlock for the idea.
*
* Be warned that duplicate checking will sometimes go into an infinite
* loop.
*/
#include "pgapack.h"
void N_InitString (PGAContext *, int, int);
int N_Mutation (PGAContext *, int, int, double);
int N_StopCond (PGAContext *);
void N_Crossover (PGAContext *ctx, int, int, int, int, int, int);
int N_Duplicate (PGAContext *, int, int, int, int);
void N_PrintString(PGAContext *, FILE *, int, int);
void N_EndOfGen (PGAContext *);
double EvalName (PGAContext *, int, int);
void GetStringParameter(char *, char *);
/* Global, because we use it in EvalName. */
char Name[70];
void main(int argc, char **argv) {
PGAContext *ctx;
MPI_Init(&argc, &argv);
/* Rather than deal with standard io and strings, we'll just set
* this explicitly.
*/
strcpy(Name, "David M. Levine, Philip L. Hallstrom, David M. Noelle, "
"Brian P. Walenz");
ctx = PGACreate(&argc, argv, PGA_DATATYPE_CHARACTER, strlen(Name),
PGA_MAXIMIZE);
PGASetRandomSeed(ctx, 42);
PGASetUserFunction(ctx, PGA_USERFUNCTION_INITSTRING, (void *)N_InitString);
PGASetUserFunction(ctx, PGA_USERFUNCTION_MUTATION, (void *)N_Mutation);
PGASetUserFunction(ctx, PGA_USERFUNCTION_CROSSOVER, (void *)N_Crossover);
PGASetUserFunction(ctx, PGA_USERFUNCTION_DUPLICATE, (void *)N_Duplicate);
PGASetUserFunction(ctx, PGA_USERFUNCTION_STOPCOND, (void *)N_StopCond);
PGASetUserFunction(ctx, PGA_USERFUNCTION_PRINTSTRING,(void *)N_PrintString);
PGASetUserFunction(ctx, PGA_USERFUNCTION_ENDOFGEN, (void *)N_EndOfGen);
/* We don't want to report anything. */
PGASetPrintFrequencyValue(ctx, 10000);
PGASetPopSize(ctx, 100);
PGASetNumReplaceValue(ctx, 90);
PGASetPopReplaceType(ctx, PGA_POPREPL_BEST);
PGASetNoDuplicatesFlag(ctx, PGA_TRUE);
PGASetMaxGAIterValue(ctx, 100);
PGASetUp(ctx);
PGARun(ctx, EvalName);
PGADestroy(ctx);
MPI_Finalize();
}
/* Function to randomly initialize a PGA_DATATYPE_CHARACTER string using
* all printable ASCII characters for the range.
*/
void N_InitString(PGAContext *ctx, int p, int pop) {
int i;
for(i=PGAGetStringLength(ctx)-1; i>=0; i--)
PGASetCharacterAllele(ctx, p, pop, i,
PGARandomInterval(ctx, 32, 126));
}
/* Function to crossover two name strings. Quite an interesting
* crossover, too. Works like a normal uniform crossover, except
* that, if one of the strings matches the correct value, we set
* BOTH children to the correct value 50% of the time.
*/
void N_Crossover(PGAContext *ctx, int p1, int p2, int pop1, int c1,
int c2, int pop2) {
int i, length;
char a, b;
length = PGAGetStringLength(ctx);
for (i=0; i<length; i++) {
a = PGAGetCharacterAllele(ctx, p1, pop1, i);
b = PGAGetCharacterAllele(ctx, p2, pop1, i);
if ((a == Name[i]) || (b == Name[i]))
a = b = Name[i];
if (PGARandomFlip(ctx, 0.5) == PGA_TRUE) {
PGASetCharacterAllele(ctx, c1, pop2, i, a);
PGASetCharacterAllele(ctx, c2, pop2, i, b);
} else {
PGASetCharacterAllele(ctx, c1, pop2, i, b);
PGASetCharacterAllele(ctx, c2, pop2, i, a);
}
}
}
/* Function to compare two strings. Strings are "equalivalent"
* if they match Name at the same alleles (and, thus, disagree at the
* same alleles). We don't care what the disagreement is, just that
* it is there.
*
* NOTE that because it is possible to get stuck in an infinite
* loop while doing duplicate checking on this string (assuming that
* the mutation operator is always beneficial), we ALWAYS return PGA_FALSE.
* The code is left as an example (and for testing).
*/
int N_Duplicate(PGAContext *ctx, int p1, int pop1, int p2, int pop2) {
int i, match;
char a, b, c;
match = PGA_TRUE;
for (i=PGAGetStringLength(ctx)-1; match && i>=0; i--) {
a = PGAGetCharacterAllele(ctx, p1, pop1, i);
b = PGAGetCharacterAllele(ctx, p2, pop2, i);
c = Name[i];
if (((a == c) && (b != c)) || ((a != c) && (b == c)))
match = PGA_FALSE;
}
return(match);
}
/* Function to muatate a PGA_DATATYPE_CHARACTER string. This is done
* by simply picking allele locations and replacing whatever was there.
* Again, legal values are all printable ASCII characters.
*/
int N_Mutation(PGAContext *ctx, int p, int pop, double mr) {
int i, count;
count = 0;
for(i=PGAGetStringLength(ctx)-1; i>=0; i--)
if (PGAGetCharacterAllele(ctx, p, pop, i) != Name[i]) {
if (PGARandomFlip(ctx, mr) == PGA_TRUE) {
PGASetCharacterAllele(ctx, p, pop, i,
PGARandomInterval(ctx, 32, 126));
count++;
}
}
return(count);
}
/* Function to print a string. Since fortran does NOT support
* C file handles, we just print normally. If we we're in C,
* we would print to the file "file".
*/
void N_PrintString(PGAContext *ctx, FILE *file, int p, int pop) {
int i;
char string[71];
for (i=PGAGetStringLength(ctx)-1; i>=0; i--)
string[i] = PGAGetCharacterAllele(ctx, p, pop, i);
string[70] = 0;
fprintf(file," :%s:\n", string);
}
/* Function to check "doneness" of the GA. We check the iteration
* count (by calling PGACheckStoppingConditions), then check if we have found
* the string yet.
*/
int N_StopCond(PGAContext *ctx) {
int done, best;
done = PGACheckStoppingConditions(ctx);
best = PGAGetBestIndex(ctx, PGA_OLDPOP);
if ((done == PGA_FALSE) &&
(PGAGetEvaluation(ctx, best, PGA_OLDPOP) ==
PGAGetStringLength(ctx)))
done = PGA_TRUE;
return(done);
}
/* After each generation, this routine is called. What is done here,
* is to print the best string in our own format, then check if the
* best string is close to the correct value. If it is, duplicate
* checking is tunred off. This is critical, as the mutation operator
* will not degrade a string, so when the strings get near the correct
* solution, they all become duplicates, but none can be changed!
*
* Other applications have done such things as send the best string
* to another process to be visualized. For here, we just call our
* print string function to print the best string.
*/
void N_EndOfGen(PGAContext *ctx) {
int best;
best = PGAGetBestIndex(ctx, PGA_NEWPOP);
N_PrintString(ctx, stdout, best, PGA_NEWPOP);
if (PGAGetEvaluation(ctx, best, PGA_NEWPOP) >=
PGAGetStringLength(ctx)-10)
PGASetNoDuplicatesFlag(ctx, PGA_FALSE);
}
/* Evaluate the string. A highly fit string will have many of
* the characters matching Name.
*/
double EvalName(PGAContext *ctx, int p, int pop) {
int i, count;
count = 0;
for (i=PGAGetStringLength(ctx)-1; i>=0; i--) {
if (PGAGetCharacterAllele(ctx, p, pop, i) == Name[i])
count++;
}
return((double)count);
}
|