1 # 调试注意事项,当出现小数值时,可能时int位数设置不当,导致溢出
2 import numpy
3 import matplotlib.pyplot as plt
4
5
6 data = numpy.array([[71, 34, 82, 23, 1, 88, 12, 57, 10, 68, 5, 33, 37, 69, 98, 24, 26, 83, 16, 26],
7 [26, 59, 30, 19, 66, 85, 94, 8, 3, 44, 5, 1, 41, 82, 76, 1, 12, 81, 73, 32]])
8
9 data = data.T
10
11
12 class GA(object):
13 """
14 遗传算法解决0-1背包问题
15 """
16
17 def __init__(self, length, number, iter_number):
18 """
19 参数初始化
20 :param length: 20
21 :param number: 300
22 :param iter_number: 200
23 """
24 self.length = length # 确定染色体编码长度
25 self.number = number # 确定初始化种群数量
26 self.iteration = iter_number # 设置迭代次数
27 self.bag_capacity = 200 # 背包容量
28
29 self.retain_rate = 0.2 # 每一代精英选择出前20%
30 self.random_selection_rate = 0.5 # 对于不是前20%的,有0.5的概率可以进行繁殖
31 self.mutation_rate = 0.01 # 变异概率0.01
32
33 def initial_population(self):
34 """
35 种群初始化,
36
37 :return: 返回种群集合
38 """
39 init_population = numpy.random.randint(low=0, high=2, size=[self.length, self.number], dtype=numpy.int64)
40 return init_population
41
42 def weight_price(self, chromosome):
43 """
44 计算累计重量和累计价格
45 :param chromosome:
46 :return:返回每一个个体的累计重量和价格
47 """
48 w_accumulation = 0
49 p_accumulation = 0
50 for i in range(len(chromosome)):
51
52 w = chromosome[i]*data[i][0]
53 p = chromosome[i]*data[i][1]
54 w_accumulation = w + w_accumulation
55 p_accumulation = p + p_accumulation
56
57 return w_accumulation, p_accumulation
58
59 def fitness_function(self, chromosome):
60 """
61 计算适应度函数,一般来说,背包的价值越高越好,但是
62 当重量超过100时,适应度函数=0
63 :param chromosome:
64 :return:
65 """
66
67 weight, price = self.weight_price(chromosome)
68 if weight > self.bag_capacity:
69 fitness = 0
70 else:
71 fitness = price
72
73 return fitness
74
75 def fitness_average(self, init_population):
76 """
77 求出这个种群的平均适应度,才能知道种群已经进化好了
78 :return:返回的是一个种群的平均适应度
79 """
80 f_accumulation = 0
81 for z in range(init_population.shape[1]):
82 f_tem = self.fitness_function(init_population[:, z])
83 f_accumulation = f_accumulation + f_tem
84 f_accumulation = f_accumulation/init_population.shape[1]
85 return f_accumulation
86
87 def selection(self, init_population):
88 """
89 选择
90 :param init_population:
91 :return: 返回选择后的父代,数量是不定的
92 """
93 # sort_population = numpy.array([[], [], [], [], [], []])
94 sort_population = numpy.empty(shape=[21, 0]) # 生成一个排序后的种群列表,暂时为空
95 for i in range(init_population.shape[1]):
96
97 x1 = init_population[:, i]
98 # print('打印x1', x1)
99 x2 = self.fitness_function(x1)
100 x = numpy.r_[x1, x2]
101 # print('打印x', x)
102 sort_population = numpy.c_[sort_population, x]
103
104 sort_population = sort_population.T[numpy.lexsort(sort_population)].T # 联合排序,从小到大排列
105
106 # print('排序后长度', sort_population.shape[1])
107 # print(sort_population)
108
109 # 选出适应性强的个体,精英选择
110 retain_length = sort_population.shape[1]*self.retain_rate
111
112 # parents = numpy.array([[], [], [], [], [], []]) # 生成一个父代列表,暂时为空
113 parents = numpy.empty(shape=[21, 0]) # 生成一个父代列表,暂时为空
114 for j in range(int(retain_length)):
115 y1 = sort_population[:, -(j+1)]
116 parents = numpy.c_[parents, y1]
117
118 # print(parents.shape[1])
119
120 rest = sort_population.shape[1] - retain_length # 精英选择后剩下的个体数
121 for q in range(int(rest)):
122
123 if numpy.random.random() < self.random_selection_rate:
124 y2 = sort_population[:, q]
125 parents = numpy.c_[parents, y2]
126
127 parents = numpy.delete(parents, -1, axis=0) # 删除最后一行,删除了f值
128 # print('打印选择后的个体数')
129 # print(parents.shape[0])
130
131 parents = numpy.array(parents, dtype=numpy.int64)
132
133 return parents
134
135 def crossover(self, parents):
136 """
137 交叉生成子代,和初始化的种群数量一致
138 :param parents:
139 :return:返回子代
140 """
141 # children = numpy.array([[], [], [], [], []]) # 子列表初始化
142 children = numpy.empty(shape=[20, 0]) # 子列表初始化
143
144 while children.shape[1] < self.number:
145 father = numpy.random.randint(0, parents.shape[1] - 1)
146 mother = numpy.random.randint(0, parents.shape[1] - 1)
147 if father != mother:
148 # 随机选取交叉点
149 cross_point = numpy.random.randint(0, self.length)
150 # 生成掩码,方便位操作
151 mark = 0
152 for i in range(cross_point):
153 mark |= (1 << i)
154
155 father = parents[:, father]
156 # print(father)
157 mother = parents[:, mother]
158
159 # 子代将获得父亲在交叉点前的基因和母亲在交叉点后(包括交叉点)的基因
160 child = ((father & mark) | (mother & ~mark)) & ((1 << self.length) - 1)
161
162 children = numpy.c_[children, child]
163
164 # 经过繁殖后,子代的数量与原始种群数量相等,在这里可以更新种群。
165 # print('子代数量', children.shape[1])
166 # print(children.dtype)
167 children = numpy.array(children, dtype=numpy.int64)
168 return children
169
170 def mutation(self, children):
171 """
172 变异
173
174 :return:
175 """
176 for i in range(children.shape[1]):
177
178 if numpy.random.random() < self.mutation_rate:
179 j = numpy.random.randint(0, self.length - 1) # s随机产生变异位置
180 children[:, i] ^= 1 << j # 产生变异
181 children = numpy.array(children, dtype=numpy.int64)
182 return children
183
184 def plot_figure(self, iter_plot, f_plot, f_set_plot):
185 """
186 画出迭代次数和平均适应度曲线图
187 画出迭代次数和每一步迭代最大值图
188 :return:
189 """
190 plt.figure()
191
192 ax1 = plt.subplot(121)
193 ax2 = plt.subplot(122)
194
195 plt.sca(ax1)
196 plt.plot(iter_plot, f_plot)
197 plt.ylim(0, 400) # 设置y轴范围
198
199 plt.sca(ax2)
200 plt.plot(iter_plot, f_set_plot)
201 plt.ylim(0, 400) # 设置y轴范围
202 plt.show()
203
204 def main(self):
205 """
206 main函数,用来进化
207 对当前种群依次进行选择、交叉并生成新一代种群,然后对新一代种群进行变异
208 :return:
209 """
210 init_population = self.initial_population()
211 # print(init_population)
212
213 iter_plot = []
214 f_plot = []
215 iteration = 0
216
217 f_set_plot = []
218
219 while iteration < self.iteration: # 设置迭代次数300
220
221 parents = self.selection(init_population) # 选择后的父代
222 children = self.crossover(parents)
223 mutation_children = self.mutation(children)
224
225 init_population = mutation_children
226
227 f_set = [] # 求出每一步迭代的最大值
228 for init in range(init_population.shape[1]):
229 f_set_tem = self.fitness_function(init_population[:, init])
230 f_set.append(f_set_tem)
231
232 f_set = max(f_set)
233
234 f_set_plot.append(f_set)
235
236 iter_plot.append(iteration)
237 iteration = iteration+1
238 print("第%s进化得如何******************************************" % iteration)
239 f_average = self.fitness_average(init_population)
240 f_plot.append(f_average)
241 print(f_set)
242 # f_accumulation = f_accumulation + f
243 # f_print = f_accumulation/(iteration + 1)
244 # print(f_print)
245 self.plot_figure(iter_plot, f_plot, f_set_plot)
246
247
248 if __name__ == '__main__':
249 g1 = GA(20, 300, 200)
250 g1.main()