-
Notifications
You must be signed in to change notification settings - Fork 0
/
polynomial_parameters.py
392 lines (314 loc) · 13.8 KB
/
polynomial_parameters.py
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
from random import randint , random, choices
from operator import add
import matplotlib.pyplot as plt
from functools import reduce
import numpy as np
import math
#create a memeber of the population
def individual (length , min , max) :
return [randint(min, max) for x in range(length)]
def population(count, length, min, max):
# Create a number of individuals (i.e. a population).
# count: the number of individuals in the population
# length: the number of values per individual
# min: the min possible value in an individual's list of values
# max: the max possible value in an individual's list of values
return [ individual(length,min,max) for x in range(count)]
def fitness(individual, xcoord,ycoord):
ygen = []
for k in xcoord:
ygen.append(np.polyval(individual,k))
# Determine the fitness of an individual. Lower is better.
#individual: the individual to evaluate
#target: the sum of numbers that individuals are aiming for
ygen_arr = np.array(ygen)
ycoord_arr = np.array(ycoord)
ydiff = np.subtract(ygen_arr,ycoord_arr)
percerr = np.divide(ydiff,ycoord_arr+0.000001)
mse = np.mean(np.square(percerr)) #find mean square error
rmse = math.sqrt(mse)# find root mean squre error
return rmse
def grade(pop, xcoord,ycoord):
#Find average fitness for a population.'
summed = reduce(add, (fitness(x, xcoord,ycoord) for x in pop), 0)
score = summed / (len(pop) * 1.0)
if score < 0.001:
print("solution found", individual, i)
#exit()
return score
# SELECTION FUNCTIONS
def eliteselect(pop, xcoord,ycoord, retain, random_select):
#creates list with fitness of individual and individual for all individuals in population
graded = [ (fitness(x, xcoord,ycoord), x) for x in pop]
#creates sorted list of individuals from smallest difference between sum and
# target (highest fitness) to largest difference (lowest fitness)
graded = [ x[1] for x in sorted(graded)]
#changes length of graded list
retain_length = int(len(graded)*retain)
#keeps highest perfroming indviduals within a certain proprotion of list to use as parents
parents = graded[:retain_length]
#randomly add other individuals to promote genetic diversity
for individual in graded[retain_length:]:
if random_select > random():
parents.append(individual)
#generate y coordinates from fittest polynomial coefficients
yfit = []
for k in xcoord:
yfit.append(np.polyval(graded[0],k))
#plot ycoordinates genrated by algorithm
plt.plot(xcoord,yfit,alpha = 0.1, color = "blue")
return parents
def eliteselect(pop, xcoord,ycoord, retain, random_select):
#creates list with fitness of individual and individual for all individuals in population
graded = [ (fitness(x, xcoord, ycoord), x) for x in pop]
#creates sorted list of individuals from smallest difference between sum and
# target (highest fitness) to largest difference (lowest fitness)
graded = [ x[1] for x in sorted(graded)]
ranklist = [(len(graded ) - graded.index(i) )for i in graded] #create list of ranks
sumrank = len(graded)+ 0.0001 #total number of ranks + little extra so proability isn't 1 for first individual
rankprob = [(r/sumrank) for r in ranklist] #generate weighted selection probabilty for each invidual
retain_length = int(len(pop)*retain) #select amount of individuals to be slected with roulette wheel
parents = choices(graded, weights = rankprob, k = retain_length) # generate set of fit parents
#randomly add other individuals to promote genetic diversity
for individual in graded[retain_length:]:
if random_select > random():
parents.append(individual)
return parents
def rouletteselect(pop, xcoord,ycoord, retain, random_select):
graded = [ (fitness(x, xcoord, ycoord), x) for x in pop]
fitlist = [x[0] for x in sorted (graded)] #produce ranked list of fitnesses
graded = [ x[1] for x in sorted(graded)]
sumfit = reduce(add,fitlist,0) #calculate sum of total fitnesses
fitprob = [1-(f/sumfit) for f in fitlist] #generate weighted selection probabilty for each invidual
retain_length = int(len(graded)*retain) #select amount of individuals to be slected with roulette wheel
parents = choices(graded, weights = fitprob, k = retain_length) # generate set of fit parents
#randomly add other individuals to promote genetic diversity
for individual in graded[retain_length:]:
if random_select > random():
parents.append(individual)
return parents
# CROSSOVER FUNCTIONS
def one_point_crossover(parents,pop,crossover):
# crossover parents to create children
parents_length = len(parents)
desired_length = len(pop) - parents_length
children = []
while desired_length > len(children):
if crossover > random():
#select certain value within parents list and assign male or female
male = randint(0, parents_length-1)
female = randint(0, parents_length-1)
#create child using first half of male and second half of female individuals
if male != female:
male = parents[male]
female = parents[female]
crosspoint = randint(0,len(male)-1)
child1 = male[:crosspoint] + female[crosspoint:]
children.append(child1)
if desired_length > len(children):
child2 = female[crosspoint:] + male[:crosspoint]
children.append(child2)
else:
#select certain indvidual within parents list to be cloned
asexual = randint(0, parents_length-1)
clone = parents[asexual]
children.append(clone)
parents.extend(children) #add children to parents
return parents
def two_point_crossover(parents,pop,crossover):
# crossover parents to create children
parents_length = len(parents)
desired_length = len(pop) - parents_length
children = []
while desired_length > len(children):
if crossover > random():
#select certain value within parents list and assign male or female
male = randint(0, parents_length-1)
female = randint(0, parents_length-1)
#create child using first half of male and second half of female individuals
if male != female:
male = parents[male]
female = parents[female]
crosspoint1 = randint(0,len(male)-3)
crosspoint2 = randint(crosspoint1+1,len(male)-2)
child1 = male[:crosspoint1] + female[crosspoint1:crosspoint2] + male[crosspoint2:]
children.append(child1)
if desired_length > len(children):
child2 = female[:crosspoint1] + male[crosspoint1:crosspoint2] + female[crosspoint2:]
children.append(child2)
else:
#select certain indvidual within parents list to be cloned
asexual = randint(0, parents_length-1)
clone = parents[asexual]
children.append(clone)
parents.extend(children) #add children to parents
return parents
def uniform_crossover(parents,pop,crossover):
# crossover parents to create children
parents_length = len(parents)
desired_length = len(pop) - parents_length
children = []
while desired_length > len(children):
if crossover > random():
#select certain value within parents list and assign male or female
male = randint(0, parents_length-1)
female = randint(0, parents_length-1)
#create child using first half of male and second half of female individuals
if male != female:
male = parents[male]
female = parents[female]
child1 = []
child2 = []
for i in range(len(male)):
if randint(0, 1):
child1.append(male[i])
child2.append(female[i])
else:
child1.append(female[i])
child2.append(male[i])
children.append(child1)
if desired_length > len(children):
children.append(child2)
else:
#select certain indvidual within parents list to be cloned
asexual = randint(0, parents_length-1)
clone = parents[asexual]
children.append(clone)
parents.extend(children) #add children to parents
return parents
# MUTATION FUNCTIONS
def mutation(parents, mutate):
# mutate some individuals
#for each individual if the rnadom number generator gives number
# less than mutate value the indivual is mutated with random number
# between the min and max values of that individuals set
for individual in parents:
if mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = randint(i_min, i_max)
return parents
def addmutation(parents, mutate):
#mutate some individuals
#for each individual if the random number generator gives number
# less than mutate value the a random number is added to a gene within
#the individual
for individual in parents:
if mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = individual[pos_to_mutate] + randint(i_min/4, i_max/4)
return parents
def flipmutation(parents, mutate):
#mutate some individuals
#for each individual if the random number generator gives number
# less than mutate value the sign of a gene within
#the individual is flipped
for individual in parents:
if mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = -individual[pos_to_mutate]
return parents
def elitemutation(parents, mutate):
# mutate some individuals
#for each individual if the rnadom number generator gives number
# less than mutate value the indivual is mutated with random number
# between the min and max values of that individuals set
elite = int(len(parents)*0.2) #prevents fittest 20% genes form being mutated
for individual in parents[elite:]:
if mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = randint(i_min, i_max)
return parents
def combimutation(parents,mutate):
for individual in parents:
if mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
p = random()
if p < 0.7:
#carry out addtional mutation if random number is below certain value
individual[pos_to_mutate] = individual[pos_to_mutate] + randint(i_min/4, i_max/4)
else:
#carry out flip mutation if random number is above certain value
individual[pos_to_mutate] = -individual[pos_to_mutate]
return parents
def proportionalmutation(parents,mutate):
# mutate some individuals
#for each individual if the random number generator gives number
# less than mutate value the indivual is mutated with random number
# between the min and max values of that individuals set
#define proportional mutations
top_mutate = mutate
middle_mutate = mutate + 0.05
bottom_mutate = mutate + 0.2
graded = [ (fitness(x, xcoord,ycoord), x) for x in parents]
graded = [ x[1] for x in sorted(graded)]
top = int(len(parents)*0.1)
bottom = int(len(parents)*0.6)
#if indvidual is in top percentage of population
#mutate with standard mutation value
for individual in graded[:top]:
if top_mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = randint(i_min, i_max)
#if indvidual is inbetween top and bottom percentage of population
#mutate with slightly bigger mutation value
for individual in graded[top:bottom]:
if middle_mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = randint(i_min, i_max)
#if indvidual is in bottom percentage of population
#mutate with substantially bigger mutation value
for individual in graded[bottom:]:
if bottom_mutate > random():
pos_to_mutate = randint(0, len(individual)-1)
individual[pos_to_mutate] = randint(i_min, i_max)
return graded
#check if solution has been found
def findsol(pop, xcoord,ycoord):
found = 0
for b in pop:
a = fitness(b,xcoord,ycoord)
if a == 0:
found = 1
return found
# Algorithm parameters
target = [25,18,31,-14,7,-19]
p_count = 300
i_length = 6
i_min = -100
i_max = 100
generations = 1000
xcoord = []
ycoord = []
gen_count = 0
retain =0.1
random_select=0.05
mutate=0.2
crossover = 0.9
results = []
for n in range(-50,50):
xcoord.append(n)
for h in xcoord:
ycoord.append(np.polyval(target,h))
p = population(p_count, i_length, i_min, i_max)
fitness_history = [grade(p, xcoord,ycoord),]
for i in range(generations):
gen_count = i
print("generation: ",gen_count)
print("p[0]",p[0])
#check if solution has been found and break out of generation loop
f = findsol(p,xcoord,ycoord)
if f == 1:
print("solution found", gen_count+1)
results.append(gen_count+1)
break
parents = eliteselect(p, xcoord,ycoord, retain, random_select)
parents = uniform_crossover(parents,p,crossover)
p = addmutation(parents, mutate)
g = grade(p, xcoord, ycoord)
fitness_history.append(g)
print(gen_count+1)
#plot target curve
plt.plot(xcoord,ycoord,color = 'red',alpha =1)
plt.title("Curve Fit Algorithm Performance" )
plt.show()
print(results)