forked from jibsen/galib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathex15.C
148 lines (123 loc) · 4.95 KB
/
ex15.C
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
/* ----------------------------------------------------------------------------
ex15.C
mbwall 28jul94
Copyright (c) 1995-1996 Massachusetts Institute of Technology
DESCRIPTION:
This example nearly identical to example 2, but it uses convergence as the
stopping criterion for the GA rather than number-of-generations.
---------------------------------------------------------------------------- */
#include <stdio.h>
#include <math.h>
#include <ga/ga.h>
#include <ga/std_stream.h>
#define cout STD_COUT
float objective(GAGenome &);
int
main(int argc, char **argv)
{
cout << "Example 15\n\n";
cout << "This program generates a sequence of random numbers then uses\n";
cout << "a simple GA and binary-to-decimal genome to match the\n";
cout << "sequence. It uses the convergence of the best-of-generation\n";
cout << "as the criterion for when to stop.\n\n";
// See if we've been given a seed to use (for testing purposes). When you
// specify a random seed, the evolution will be exactly the same each time
// you use that seed number.
unsigned int seed = 0;
for(int ii=1; ii<argc; ii++) {
if(strcmp(argv[ii++],"seed") == 0) {
seed = atoi(argv[ii]);
}
}
// Declare variables for the GA parameters and set them to some default values.
// When we use convergence as the completion measure we have to specify both
// a convergence value (larger means more converged) and a number-of-gen
// which specifies how many generations back to look to calculate the
// convergence. The number of generations back defaults to 20, so you do not
// have to set that if you don't want to.
int popsize = 30;
float pmut = 0.01;
float pcross = 0.6;
float pconv = 0.99; // threshhold for when we have converged
int nconv = 50; // how many generations back to look
// Generate a sequence of random numbers using the values in the min and max
// arrays. We also set one of them to integer value to show how you can get
// explicit integer representations by choosing your number of bits
// appropriately.
GARandomSeed(seed);
int i;
int n=7;
float *target = new float[n];
float min[] = {0, 0, 3, -5, 100, 0.001, 0};
float max[] = {1, 100, 3, -2, 100000, 0.010, 7};
for(i=0; i<n; i++)
target[i] = GARandomFloat(min[i], max[i]);
target[6] = GARandomInt((int)min[6], (int)max[6]);
// Print out the sequence to be sure we got the right one.
cout << "input sequence:\n";
for(i=0; i<n; i++){
cout.width(10);
cout << target[i] << " ";
}
cout << "\n"; cout.flush();
// Create a phenotype then fill it with the phenotypes we will need to map to
// the values we read from the file. The arguments to the add() method of a
// Bin2Dec phenotype are (1) number of bits, (2) min value, and (3) max value.
// The phenotype maps a floating-point number onto the number of bits that
// you designate. Here we just make everything use 8 bits and use the max and
// min that were used to generate the target values. You can experiment with
// the number of bits and max/min values in order to make the GA work better
// or worse.
GABin2DecPhenotype map;
for(i=0; i<n; i++)
map.add(8, min[i], max[i]);
// Create the template genome using the phenotype map we just made. The
// GA will use this genome to clone the population that it uses to do the
// evolution.
GABin2DecGenome genome(map, objective, (void *)target);
// Now create the GA using the genome and run it.
GASteadyStateGA ga(genome);
ga.scoreFrequency(1);
ga.flushFrequency(50);
ga.scoreFilename("bog.dat");
ga.populationSize(popsize);
ga.pMutation(pmut);
ga.pCrossover(pcross);
ga.pConvergence(pconv);
ga.nConvergence(nconv);
ga.terminator(GAGeneticAlgorithm::TerminateUponConvergence);
ga.evolve();
// Dump the results of the GA to the screen.
genome.initialize();
cout << "random values in the genome:\n";;
unsigned int jj=0;
for(jj=0; jj<map.nPhenotypes(); jj++){
cout.width(10); cout << genome.phenotype(jj) << " ";
}
cout << "\n";
genome = ga.statistics().bestIndividual();
cout << "the ga generated:\n";
for(jj=0; jj<map.nPhenotypes(); jj++){
cout.width(10); cout << genome.phenotype(jj) << " ";
}
cout << "\n\n"; cout.flush();
// Clean up by freeing the memory we allocated.
delete [] target;
return 0;
}
// For this objective function we try to match the values in the array of float
// that is passed to us as userData. If the values in the genome map to
// values that are close, we return a better score. We are limited to positive
// values for the objective value (because we're using linear scaling), so we
// take the reciprocal of the absolute value of the difference between the
// value from the phenotype and the value in the sequence.
float
objective(GAGenome & c)
{
GABin2DecGenome & genome = (GABin2DecGenome &)c;
float *sequence = (float *)c.userData();
float value=genome.nPhenotypes();
for(int i=0; i<genome.nPhenotypes(); i++)
value += 1.0 / (1.0 + fabs(genome.phenotype(i) - sequence[i]));
return(value);
}