-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGA.py
More file actions
379 lines (329 loc) · 13.4 KB
/
GA.py
File metadata and controls
379 lines (329 loc) · 13.4 KB
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
"""
Module: GA
Author: ShaoHaozhou
motto: Self-discipline, self-improvement, self-love
Date: 2021/4/20
Introduce: This is the Genetic Algorithm which contains discrete and continuous two types [DGA and CGA]
介绍: 这是一种包含离散和连续两种类型的遗传算法。 GA = {DGA, CGA}
"""
import numpy as np
import matplotlib.pyplot as plt
class GABase(object):
"""
Introduce:
This is the base class of genetic algorithms
介绍:
这是遗传算法的基类(GABase)
arg:
f: the objective function
sv: coefficient of Selection
cv: coefficient of variation
参数:
f: 目标函数
sv: 选择系数
cv: 变异系数
"""
def __init__(self, f, sv, cv):
self.f = f
self.sv = sv
self.cv = cv
self.pop = None # 种群
self.best = [None, np.inf] # 最优个体及其适应度(目标函数值)
self.fit_ = None # 每轮最优适应度的记录(作图用)
self.for_ = None # 轮数
def initialize(self):
"""
This is the initialization function.
初始化函数
"""
pass
def fitness(self):
"""
# 用户可通过此函数来自定义目标函数...
func(a_singe_pop) => return the fitness
"""
return np.apply_along_axis(self.f, 1, self.pop)
def select(self, fitness):
"""
This is the selection function.Through the roulette algorithm to eliminate
the number of times for the current population is 1/10.
选择函数,通过轮盘赌算法进行淘汰,淘汰次数为当前种群的1/10。
"""
min_pos = np.argmin(fitness)
if fitness[min_pos] < self.best[1]:
self.best = [self.pop[min_pos], fitness[min_pos]]
min_fitness = fitness[min_pos]
fitness = fitness - min_fitness
u = np.sum(fitness)
fitness = fitness / u
s = 0
for i in range(fitness.shape[0] - 1, -1, -1):
a = fitness[i]
fitness[i] = 1 - s
s += a
rands = np.random.rand(self.pop.shape[0] // 10)
out = set()
for rand in rands:
for i in range(fitness.shape[0]):
if rand < fitness[i]:
out.add(i)
break
self.pop = np.delete(self.pop, list(out), axis=0)
def cross(self):
"""
This is cross function.
交叉函数
"""
pass
def mutate(self):
"""
This is mutation function.
变异函数
"""
pass
def fit(self, for_=1000):
"""
This is opening function to start the train of GA.
启动函数
"""
self.fit_ = np.array([])
self.for_ = for_
self.best = [None, np.inf]
self.initialize()
for _ in range(for_):
self.select(fitness=self.fitness())
self.cross()
self.mutate()
self.fit_ = np.append(self.fit_, self.best[1])
def draw_fit(self):
"""
This is drawing function to draw the fitness line chart.
画图函数 => 画出适应度折线图
"""
if self.fit_ is None:
raise ValueError("you should fit firstly!")
x = np.linspace(0, self.for_, self.for_)
y = self.fit_
plt.plot(x, y)
plt.show()
class DGA(GABase):
"""
Introduce:
This is a discrete type of genetic algorithm
介绍:
这是离散类型的遗传算法(DGA)
arg:
f: the objective function
sv: coefficient of Selection
cv: coefficient of variation
kinds: the type of individual genes
max_pop: the max population
length: the number of genes contained in an individual
can_replace: whether duplicate genes can be present in an individual
参数:
f: 目标函数
sv: 选择系数
cv: 变异系数
kinds: 个体基因的种类
max_pop: 最大种群数量
length: 一个个体所包含的基因
can_replace: 一个个体中是否可以出现重复的基因
"""
def __init__(self, f, cv, sv, kinds, max_pop, length, can_replace=False):
super().__init__(f, cv, sv)
self.kinds = list(kinds)
self.max_pop = max_pop
self.length = length
self.can_replace = can_replace
def initialize(self):
"""
There are two types of initialization: repeatable and non-repeatable. The default
setting for initializing the population is 1/10 of the maximum population.
分成了可重复和不可重复两种初始化方式,初始化种群这里默认设置为最大种群数的1/10。
"""
if self.can_replace is True:
self.pop = np.random.choice(self.kinds, [self.max_pop // 10, self.length]) # 使用整除获得整数
else:
self.pop = np.ones([self.max_pop // 10, self.length]) * np.inf
for i in range(self.max_pop // 10):
for j in range(self.length):
while True:
choice = np.random.choice(self.kinds)
if choice not in self.pop[i]:
self.pop[i][j] = choice
break
def fitness(self):
return super().fitness()
def select(self, fitness):
super().select(fitness)
def cross(self):
"""
In the process of crossover inheritance, individuals before and
after each other are randomly selected at different locations to generate two individuals
交叉遗传过程采取随机选取不同位置对前后的个体进行交叉遗传,生成两个个体。
"""
if self.can_replace:
for i in range(self.pop.shape[0]):
if self.max_pop <= self.pop.shape[0]:
break
if np.random.rand() < self.sv:
selected = np.random.randint(self.length, size=[1, np.random.randint(self.length)])
child = [self.pop[i].copy(), self.pop[(i+1) % self.pop.shape[0]]]
child[0][selected] = self.pop[(i+1) % self.pop.shape[0]][selected]
child[1][selected] = self.pop[i][selected]
self.pop = np.vstack((self.pop, child))
else:
for i in range(self.pop.shape[0]):
if self.max_pop <= self.pop.shape[0]:
break
if np.random.rand() < self.sv: # 使用随机数进行判断
selected = np.random.randint(self.length, size=[1, np.random.randint(self.length)])
child = [self.pop[i].copy(), self.pop[(i+1) % self.pop.shape[0]]]
for j in selected[0]:
if self.pop[(i+1) % self.pop.shape[0]][j] not in child[0]:
child[0][j] = self.pop[(i+1) % self.pop.shape[0]][j]
if self.pop[i][j] not in child[1]:
child[1][j] = self.pop[i][j]
self.pop = np.vstack((self.pop, child)) # 对种群进行拼接
def mutate(self):
"""
The mutation process also uses random numbers to make changes to individual genes.
变异过程也是采用随机数对单个的基因进行更改。
"""
if self.can_replace:
for i in range(self.pop.shape[0]):
if np.random.rand() < self.cv:
pos = np.random.randint(self.length)
self.pop[i][pos] = np.random.choice(self.kinds)
else:
for i in range(self.pop.shape[0]):
if np.random.rand() < self.cv:
pos = np.random.randint(self.length)
cross = np.random.choice(self.kinds)
if cross not in self.pop[i]:
self.pop[i][pos] = cross
else:
self.pop[i][np.where(self.pop[i] == cross)[0]] = self.pop[i][pos]
self.pop[i][pos] = cross
def fit(self, for_=1000):
super().fit(for_)
def draw_fit(self):
super().draw_fit()
class CGA(GABase):
"""
Introduce:
This is a continuous type of genetic algorithm
介绍:
这是连续类型的遗传算法(CGA)
arg:
f: the objective function
sv: coefficient of Selection
cv: coefficient of variation
max_pop: the max population
length: the number of genes contained in an individual
extent: limit the scope of a single gene
参数:
f: 目标函数
sv: 选择系数
cv: 变异系数
max_pop: 最大种群数量
length: 一个个体所包含的基因数量
extent: 单个基因的范围限定
"""
def __init__(self, f, sv, cv, max_pop, length, extent):
super().__init__(f, sv, cv)
self.max_pop = max_pop
self.length = length
self.extent = extent
def initialize(self):
"""
Generate a population within a range.
生成在范围之内的种群。
"""
self.pop = self.extent[0] + np.random.rand(self.max_pop // 10, self.length) * (self.extent[1] - self.extent[0])
def fitness(self):
return super().fitness()
def select(self, fitness):
super().select(fitness)
def cross(self):
for i in range(self.pop.shape[0]):
if self.max_pop <= self.pop.shape[0]:
break
if np.random.rand() < self.sv:
selected = np.random.randint(self.length, size=[1, np.random.randint(self.length)])
child = [self.pop[i].copy(), self.pop[(i + 1) % self.pop.shape[0]]]
child[0][selected] = self.pop[(i + 1) % self.pop.shape[0]][selected]
child[1][selected] = self.pop[i][selected]
self.pop = np.vstack((self.pop, child))
def mutate(self):
for i in range(self.pop.shape[0]):
if np.random.rand() < self.cv:
pos = np.random.randint(self.length)
self.pop[i][pos] = self.extent[0] + np.random.rand() * (self.extent[1] - self.extent[0])
def fit(self, for_=1000):
super().fit(for_)
def draw_fit(self):
super().draw_fit()
class GA(object):
mode = ["DGA", "CGA"]
def __init__(self, f, sv, cv, max_pop, length, extent_or_kinds, can_replace=False):
if len(list(extent_or_kinds)) != 2:
self.mode = GA.mode[0]
self.ga = DGA(f, cv, sv, extent_or_kinds, max_pop, length, can_replace)
self.msg = "{mode}(f:{f}, sv:{sv}, cv:{cv}, max_pop:{max_pop}," \
" length:{length}, kinds:{kinds}, can_replace{can_replace}"\
.format(mode=self.mode, f=f, sv=sv, cv=cv, max_pop=max_pop, length=length, kinds=extent_or_kinds,can_replace=can_replace)
else:
self.mode = GA.mode[1]
self.ga = CGA(f, cv, sv, max_pop, length, extent_or_kinds)
self.msg = "{mode}(f:{f}, sv:{sv}, cv:{cv}, max_pop:{max_pop}," \
" length:{length}, extent:{extent})"\
.format(mode=self.mode, f=f, sv=sv, cv=cv, max_pop=max_pop, length=length, extent=extent_or_kinds)
def __repr__(self):
return self.msg
def __str__(self):
return self.__repr__()
def fit(self, for_=1000):
self.ga.fit(for_)
def result(self):
return self.ga.best
def draw_fit(self):
self.ga.draw_fit()
if __name__ == "__main__":
# f = lambda x: sum(x * np.sin(x) + x * np.cos(2 * x))
#
# # 测试 DGA
# dga = DGA(f, cv=0.1, sv=0.01, kinds=np.linspace(0, 10, 100), max_pop=100, length=5)
# dga.fit(1000)
# dga.draw_fit()
# print(dga.best)
#
# # 测试 CGA
# cga = CGA(f, cv=0.1, sv=0.1, max_pop=100, length=5, extent=[0, 10])
# cga.fit(1000)
# cga.draw_fit()
# print(cga.best)
#
# # 测试 GA
# ga = GA(f, cv=0.1, sv=0.1, max_pop=100, length=5, extent_or_kinds=[0, 10])
# ga.fit(1000)
# ga.draw_fit()
# print(ga.result())
#
distance = lambda x, y: np.sqrt((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2)
points = open("./points.txt", 'r', encoding="utf-8", ).read().splitlines()
points = [list(map(int, each.strip().split(" "))) for each in points]
length = len(points)
rect = np.zeros((length, length))
for i in range(length):
for j in range(length):
rect[i][j] = distance(points[i], points[j])
def f(x):
d = 0
for i in range(len(x)-1):
d += rect[int(x[i])][int(x[i+1])]
return d
dga = DGA(f, cv=0.1, sv=0.05, kinds=list(range(0, length)), max_pop=100, length=length, can_replace=False)
dga.fit(10000)
dga.draw_fit()
print(dga.best)