forked from mr-andreas/neuralnet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CGenAlg.cpp
269 lines (218 loc) · 7.18 KB
/
CGenAlg.cpp
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include "CGenAlg.h"
const double D_MAX_PERTURBATION = 0.3;
const int I_NUM_COPIES_ELITE = 1;
const int I_NUM_ELITE = 4;
//-----------------------------------constructor-------------------------
//
// sets up the population with random floats
//
//-----------------------------------------------------------------------
CGenAlg::CGenAlg(int popsize,
double MutRat,
double CrossRat,
int numweights) : m_iPopSize(popsize),
m_dMutationRate(MutRat),
m_dCrossoverRate(CrossRat),
m_iChromoLength(numweights),
m_dTotalFitness(0),
m_cGeneration(0),
m_iFittestGenome(0),
m_dBestFitness(0),
m_dWorstFitness(99999999),
m_dAverageFitness(0)
{
//initialise population with chromosomes consisting of random
//weights and all fitnesses set to zero
for (int i=0; i<m_iPopSize; ++i)
{
m_vecPop.push_back(SGenome());
for (int j=0; j<m_iChromoLength; ++j)
{
m_vecPop[i].vecWeights.push_back(RandomClamped());
}
}
}
//---------------------------------Mutate--------------------------------
//
// mutates a chromosome by perturbing its weights by an amount not
// greater than CParams::dMaxPerturbation
//-----------------------------------------------------------------------
void CGenAlg::Mutate(vector<double> &chromo)
{
//traverse the chromosome and mutate each weight dependent
//on the mutation rate
for (int i=0; i<chromo.size(); ++i)
{
//do we perturb this weight?
if (RandFloat() < m_dMutationRate)
{
//add or subtract a small value to the weight
chromo[i] += (RandomClamped() * D_MAX_PERTURBATION);
}
}
}
//----------------------------------GetChromoRoulette()------------------
//
// returns a chromo based on roulette wheel sampling
//
//-----------------------------------------------------------------------
SGenome CGenAlg::GetChromoRoulette()
{
//generate a random number between 0 & total fitness count
double Slice = (double)(RandFloat() * m_dTotalFitness);
//this will be set to the chosen chromosome
SGenome TheChosenOne;
//go through the chromosones adding up the fitness so far
double FitnessSoFar = 0;
for (int i=0; i<m_iPopSize; ++i)
{
FitnessSoFar += m_vecPop[i].dFitness;
//if the fitness so far > random number return the chromo at
//this point
if (FitnessSoFar >= Slice)
{
TheChosenOne = m_vecPop[i];
break;
}
}
return TheChosenOne;
}
//-------------------------------------Crossover()-----------------------
//
// given parents and storage for the offspring this method performs
// crossover according to the GAs crossover rate
//-----------------------------------------------------------------------
void CGenAlg::Crossover(const vector<double> &mum,
const vector<double> &dad,
vector<double> &baby1,
vector<double> &baby2)
{
//just return parents as offspring dependent on the rate
//or if parents are the same
if ( (RandFloat() > m_dCrossoverRate) || (mum == dad))
{
baby1 = mum;
baby2 = dad;
return;
}
//determine a crossover point
int cp = RandInt(0, m_iChromoLength - 1);
//create the offspring
for (int i=0; i<cp; ++i)
{
baby1.push_back(mum[i]);
baby2.push_back(dad[i]);
}
for (int i=cp; i<mum.size(); ++i)
{
baby1.push_back(dad[i]);
baby2.push_back(mum[i]);
}
return;
}
//-----------------------------------Epoch()-----------------------------
//
// takes a population of chromosones and runs the algorithm through one
// cycle.
// Returns a new population of chromosones.
//
//-----------------------------------------------------------------------
vector<SGenome> CGenAlg::Epoch(vector<SGenome> &old_pop)
{
//assign the given population to the classes population
m_vecPop = old_pop;
//reset the appropriate variables
Reset();
//sort the population (for scaling and elitism)
sort(m_vecPop.begin(), m_vecPop.end());
//calculate best, worst, average and total fitness
CalculateBestWorstAvTot();
//create a temporary vector to store new chromosones
vector <SGenome> vecNewPop;
//Now to add a little elitism we shall add in some copies of the
//fittest genomes. Make sure we add an EVEN number or the roulette
//wheel sampling will crash
if (!(I_NUM_COPIES_ELITE * I_NUM_ELITE % 2))
{
GrabNBest(I_NUM_ELITE, I_NUM_COPIES_ELITE, vecNewPop);
}
//now we enter the GA loop
//repeat until a new population is generated
while (vecNewPop.size() < m_iPopSize)
{
//grab two chromosones
SGenome mum = GetChromoRoulette();
SGenome dad = GetChromoRoulette();
//create some offspring via crossover
vector<double> baby1, baby2;
Crossover(mum.vecWeights, dad.vecWeights, baby1, baby2);
//now we mutate
Mutate(baby1);
Mutate(baby2);
//now copy into vecNewPop population
vecNewPop.push_back(SGenome(baby1, 0));
vecNewPop.push_back(SGenome(baby2, 0));
}
//finished so assign new pop back into m_vecPop
m_vecPop = vecNewPop;
return m_vecPop;
}
//-------------------------GrabNBest----------------------------------
//
// This works like an advanced form of elitism by inserting NumCopies
// copies of the NBest most fittest genomes into a population vector
//--------------------------------------------------------------------
void CGenAlg::GrabNBest(int NBest,
const int NumCopies,
vector<SGenome> &Pop)
{
//add the required amount of copies of the n most fittest
//to the supplied vector
while(NBest--)
{
for (int i=0; i<NumCopies; ++i)
{
Pop.push_back(m_vecPop[(m_iPopSize - 1) - NBest]);
}
}
}
//-----------------------CalculateBestWorstAvTot-----------------------
//
// calculates the fittest and weakest genome and the average/total
// fitness scores
//---------------------------------------------------------------------
void CGenAlg::CalculateBestWorstAvTot()
{
m_dTotalFitness = 0;
double HighestSoFar = 0;
double LowestSoFar = 9999999;
for (int i=0; i<m_iPopSize; ++i)
{
//update fittest if necessary
if (m_vecPop[i].dFitness > HighestSoFar)
{
HighestSoFar = m_vecPop[i].dFitness;
m_iFittestGenome = i;
m_dBestFitness = HighestSoFar;
}
//update worst if necessary
if (m_vecPop[i].dFitness < LowestSoFar)
{
LowestSoFar = m_vecPop[i].dFitness;
m_dWorstFitness = LowestSoFar;
}
m_dTotalFitness += m_vecPop[i].dFitness;
}//next chromo
m_dAverageFitness = m_dTotalFitness / m_iPopSize;
}
//-------------------------Reset()------------------------------
//
// resets all the relevant variables ready for a new generation
//--------------------------------------------------------------
void CGenAlg::Reset()
{
m_dTotalFitness = 0;
m_dBestFitness = 0;
m_dWorstFitness = 9999999;
m_dAverageFitness = 0;
}