<
>

Python遗传算法的测试实现(numpy和matplotlib)

2020-07-20 21:41:49 来源:易采站长站 作者:

import numpy as np
import matplotlib.pyplot as plt

class GA(object):
def __init__(self, para_array=None, obj_func=None, max_iter=50, mp=0.05, cp=0.9, delta=0.001, population_size=100):
"""
:param para_array: 参数数组
:param max_iter: 最大迭代次数
:param mp: 变异概率
:param cp: 交叉概率
:param delta: 放大倍数
:param population_size:
"""
self.para_array = para_array
self.obj_func = obj_func
self.max_iter = max_iter
self.mp = mp
self.cp = cp
self.delta = delta
self.population_size = population_size

# 根据解的精度确定染色体(chromosome)的长度——确定二进制编码的长度
# 需要根据决策变量的上下边界来确定
# 需要根据决策变量的上下边界来确定
def get_encoded_length(self):
"""
:return: 每一个超参的二进制表示的长度
"""
# 每个变量的编码长度
lengths = [] # 根据给定的定义域(自变量的范围)来获取其二进制的长度
for i in self.para_array:
lower = i[0] upper = i[1] while ((np.log2((upper - lower) / self.delta)) + 1) = random_a
# print(logical)
# 当r<cum_[1],则选择个体1,
# 否则,选择个体k,使得:q[k-1] 0:
# 从后向前依次选取,直至没有可以进行交叉的个体
a = index.pop() # a 表示index中最后一个元素值
b = index.pop() # b 表示index中倒数第二个元素值
# 在一个染色体的基因序列中随机选取一个交叉点
crossover_point = np.random.choice(range(1, n), 1, replace=False)[0] # 在染色体中确认交叉点的位置,也就是索引为a、b的染色体在选择的交叉点进行变换

update_population[a, 0:crossover_point] = population[a, 0:crossover_point] update_population[a, crossover_point:] = population[b, crossover_point:] update_population[b, 0:crossover_point] = population[b, 0:crossover_point] update_population[b, crossover_point:] = population[a, crossover_point:] # 返回交叉后的种群(二进制)
return update_population

def mutation(self, population):
"""
种群染色体变异
Pm: 变异概率默认是0.01
:param population: 经交叉后得到的种群
:return: 经变异操作后的新种群
"""
update_population = np.copy(population)
# 种群的染色体数(个体数)m,每个染色体的基因数量n
m, n = population.shape
# 计算需要变异的基因个数
gene_num = np.uint8(m * n * self.mp)
# 将所有的基因按照序号进行10进制编码,则共有m*n个基因
# 随机抽取gene_num个基因进行基本位变异
mutation_gene_index = np.random.choice(range(0, m * n), gene_num, replace=False)
# 确定每个将要变异的基因在整个染色体中的基因座(即基因的具体位置)
for gene in mutation_gene_index:
# 确定变异基因位于第几个染色体
chromosome_index = gene // n
# 确定变异基因位于当前染色体的第几个基因位
gene_index = gene % n
# 变异,1变成0,0变成1
if update_population[chromosome_index, gene_index] == 0:
update_population[chromosome_index, gene_index] = 1
else:
update_population[chromosome_index, gene_index] = 0
# 变异后的种群
return update_population

def fitnessFunction(self, obj_func, para_list):
"""
定义适应度函数
返回:
return: 适应度函数的值
"""
# return lambda x: 21.5 + x[0] * np.sin(4 * np.pi * x[0]) + x[1] * np.sin(20 * np.pi * x[1])
# if name == 'gaussian':
# return lambda p, theta: np.exp(-theta * np.abs(x[0] - x[1]) ** p / (2 * x[3] ** 2))
# return lambda x: x[0] ** 2
# return np.sum(para_list ** 2)
return obj_func(para_list)

def genetic_algorithm(self):
# 每次迭代得到的最优解
optimal_solutions = [] optimal_values = [] # 决策变量(自变量)的取值范围,维数多就增加数组元素个数,例如[[4.1, 5.8],[8, 10]] #
# decision_variables = [[100, 100.5], [4.1, 5.8]] # 得到染色体编码长度
length_encode = self.get_encoded_length()
# print(length_encode)
# 得到初始种群编码
chromosomes_encoded = self.get_initial_population(length_encode, self.population_size)
# 种群解码
decoded = self.decoded_chromosome(length_encode, chromosomes_encoded, self.para_array)
# evalvalues, cum_proba = get_fitness_value(fitnessFunction(), decoded)
# 得到个体适应度值和个体的累积概率
fitness_values, cum_individual_proba = self.get_fitness_value(self.fitnessFunction, decoded)
for iteration in range(self.max_iter):
# 选择新的种群
new_populations = self.select_new_population(chromosomes_encoded, cum_individual_proba)
# 进行交叉操作
crossover_population = self.crossover(new_populations)
# mutation进行变异
mutation_population = self.mutation(crossover_population)
# 将变异后的种群解码,得到每轮迭代最终的种群
final_decoded = self.decoded_chromosome(length_encode, mutation_population, self.para_array)
# 变异后的适应度值,累计概率
fitness_values, cum_individual_proba = self.get_fitness_value(self.fitnessFunction, final_decoded)
# 搜索每次迭代的最优解(当前是取最小值,所以是min),以及最优解对应的目标函数(十进制染色体)的取值
# optimal_values.append(np.max(list(fitness_values)))
optimal_values.append(np.min(list(fitness_values)))
index = np.where(fitness_values == min(list(fitness_values)))
optimal_solutions.append(final_decoded[index[0][0], :])
# 从每次迭代的最优解集合中找到总体的最优解
# optimal_value = np.max(optimal_values)
optimal_value = np.min(optimal_values)
# 根据全局最优解得到最优解的索引位置
optimal_index = np.where(optimal_values == optimal_value)
# 得到优化参数的值组成的list
optimal_solution = optimal_solutions[optimal_index[0][0]] return optimal_solution, optimal_value

# 下面是6个函数,其中para_list是搜索空间,也就是自变量
def Sphere(para_list):
return np.sum(para_list ** 2)

def Sum_Squares(para_list):
sum_squares = 0
for i in range(1, len(para_list) + 1):
sum_squares += i * para_list[i - 1] ** 2
return sum_squares

def Step(para_list):
step = 0
for i in range(len(para_list)):
step += np.floor(para_list[i] + 0.5) ** 2
return step

def Quartic(para_list):
quartic = 0
for i in range(1, len(para_list) + 1):
quartic += i * para_list[i - 1] ** 4
return quartic + np.random.rand()

def Easom(para_list):
return -np.cos(para_list[0]) * np.cos(para_list[1]) *
np.exp(-(para_list[0] - np.pi) ** 2 - (para_list[1] - np.pi) ** 2)

def Matyas(para_list):
return 0.26 * (para_list[0] ** 2 + para_list[1] ** 2)
- 0.48 * para_list[0] * para_list[1]

# 对这6个函数使用GA测试的入口,分别可以测试空间dv
def test_func(dv, obj_func, mp, cp, max_iter, pop_size):
"""
:param dv: 测试空间,也就是自变量
:param obj_func: 测试函数
:param mp: 突变概率
:param cp: 交叉概率
:param max_iter: 最大迭代次数
:param pop_size: 种群数量
:return: 最优值
"""
# start = time.perf_counter()
ga = GA(para_array=dv, obj_func=obj_func, mp=mp, cp=cp, max_iter=max_iter, population_size=pop_size)
solution, value = ga.genetic_algorithm()
# print('最优解:', solution)
# print('{0}的最优目标函数值:{1}'.format(obj_func.__name__, value))
# elapsed = (time.perf_counter() - start)
# print("Time used:", elapsed)
return value

# 搜索空间,后边的10 2 表示维度
decision_variables_100 = [[-100, 100]] * 12
decision_variables_10 = [[-10, 10]] * 10
decision_variables_128 = [[-1.28, 1.28]] * 10
decision_variables_easom = [[-100, 100]] * 2
decision_variables_matyas = [[-10, 10]] * 2

# 对每一个函数进行具体测试,可以改变的是以下四个参数变量
def test_all_func(mp, cp, max_iter, pop_size):
"""
:param mp: 突变概率
:param cp: 交叉概率
:param max_iter: 最大迭代次数
:param pop_size: 种群数量
:return: 每个目标函数最优值组成的数组
"""
# Sphere
value_sphere = test_func(decision_variables_100, Sphere, mp, cp, max_iter, pop_size)

# Sum_Squares
value_sum_squares = test_func(decision_variables_10, Sum_Squares, mp, cp, max_iter, pop_size)

# Step
value_step = test_func(decision_variables_100, Step, mp, cp, max_iter, pop_size)

# Quartic
value_quartic = test_func(decision_variables_128, Quartic, mp, cp, max_iter, pop_size)

# Matyas
value_matyas = test_func(decision_variables_matyas, Matyas, mp, cp, max_iter, pop_size)

# Easom
value_easom = test_func(decision_variables_easom, Easom, mp, cp, max_iter, pop_size)

value_array = np.array([value_sphere, value_sum_squares, value_step,
value_quartic, value_matyas, value_easom])
# value_array = np.array([value_sum_squares, value_quartic, value_matyas, value_easom])
return value_array

def draw_results(para_array, which_para):
result_array = [] i_array = np.arange(1, len(para_array) + 1)
for i_para, i_process in zip(para_array, i_array):
if which_para == 'Mutation Probability':
result = test_all_func(i_para, 0.8, 250, 60)
elif which_para == 'Crossover Probability':
result = test_all_func(0.1, i_para, 250, 60)
elif which_para == 'Max Iteration':
result = test_all_func(0.1, 0.8, i_para, 60)
elif which_para == 'Population Size':
result = test_all_func(0.1, 0.8, 250, i_para)
else:
return
result_array.append(result)
print("r程序当前已完成:" + str(round(i_process / len(i_array) * 100)) + '%', end="")
plt.figure()
plt.title(which_para, fontdict={'family': 'Times New Roman', 'size': 20})
plt.xlabel('different values of parameters: ' + which_para, fontdict={'family': 'Times New Roman', 'size': 16})
plt.ylabel('optimum', fontdict={'family': 'Times New Roman', 'size': 16})
plt.plot(para_array, np.array(result_array).T[0], color='#0000ff', marker='+', linestyle='-.',
label='Sphere')
plt.plot(para_array, np.array(result_array).T[1], color='#ff0000', marker='+', linestyle=':',
label='Sum_Squares')
plt.plot(para_array, np.array(result_array).T[2], color='#00ff00', marker='+', linestyle='--',
label='Step')
plt.plot(para_array, np.array(result_array).T[3], color='#ff00aa', marker='+', linestyle='-',
label='Quartic')
plt.plot(para_array, np.array(result_array).T[4], color='#ffaa00', marker='+', linestyle='--',
label='Matyas')
plt.plot(para_array, np.array(result_array).T[5], color='#000000', marker='+', linestyle='-',
label='Easom')
# plt.plot(d, result_array, color='#ff00ff', marker='+', linestyle='-',
# label=('' if i == 0 else '_') + 'y-real')
plt.legend()
plt.show()

"""程序入口 四个参数分别进行寻优"""

# 改变参数——突变概率
mp_array = np.arange(0.0001, 0.5, 0.05)
draw_results(mp_array, "Mutation Probability")

# 改变参数——交叉概率
cp_array = np.arange(0.4, 0.99, 0.05)
# draw_results(cp_array, "Crossover Probability")

# # 改变参数——最大迭代次数
max_iter_array = np.arange(10, 501, 50)
# draw_results(max_iter_array, "Max Iteration")

# # 改变参数——种群数量
pop_size_array = np.arange(20, 101, 10)
# draw_results(pop_size_array, "Population Size")



作者:juzhong180236

暂时禁止评论

微信扫一扫

易采站长站微信账号