遗传算法解决二维和高维优化问题——基于Python
代码
1.二维问题:最优解为最小值
#-*- coding: utf-8 -*-
#遗传算法解决二维问题
#找最优解,这里是找最小值,因此需要对适应度函数做一下处理,即适应度函数为目标函数的倒数
import numpy as np
import matplotlib.pyplot as plt
import Scripts
import math
from pylab import mpl
#中文显示问题,黑体
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
'''
遗传算法基本流程:
初始化种群
适应值评价,保存最优染色体
选择
交配
变异
重新评价适应值,更新最优染色体
满足终止条件则结束,否则继续选择过程
'''
#计算初始串长度
def Compute_Length(x, prec):
length = 0.
value = (x[1] - x[0]) * pow(10, prec) + 1.0
length = np.log2(value)
return length
#根据串长度创建初始种群
def Build_Init_Group(len0, len1, size):
#先生成20位,再生成20位
ref_list = []
for i in range(size):
initial_group = np.random.randint(0, 2, len0 + len1)
# initial_group1 = np.random.randint(0, 2, len1)
ref_list.append(initial_group)
# ref_list1.append(initial_group1)
#第二个子代的二进制表示在前
# new_list = list(zip(ref_list1, ref_list0))
#二维数组
init_popu = np.array(ref_list)
return init_popu
'''
计算解码值
init_popu:初始种群
'''
def Compute_Decode_Value(init_popu, x_range0, x_range1, length0, length1):
# print(type(init_popu[0]))#ndarray
# print(init_popu.size / init_popu[0].size)#ndarray
#init_popu[0][0]表示第二个子代的二进制表示
length_single = len(init_popu[0])
ref_list0 = []
ref_list1 = []
#x和y的精度,用于计算解码值
delta = [(x_range0[1] - x_range0[0]) / (pow(2, length0) - 1), (x_range1[1] - x_range1[0]) / (pow(2, length1) - 1)]
'''
计算每个个体的解码值
先计算位和
然后计算解码值存到数组里
'''
#遍历种群内所有个体 计算x和y的位和值
for i in range(len(init_popu)):
for j in range(0, 2):
sum = 0.
# x 的位和
if j == 0:
for k in reversed(range(length0, length_single)):
sum += init_popu[i][k] * pow(2, length_single - k - 1)
# print(init_popu[i][k], k, length_single, pow(2, length_single - k - 1))
ref_list0.append(sum)
# y 的位和
if j == 1:
for k in reversed(range(0, length1)):
sum += init_popu[i][k] * pow(2, length1 - k - 1)
# print(init_popu[i][k], k, length_single, pow(2, length1 - k - 1))
ref_list1.append(sum)
#计算x的解码值
for x_num in range(len(ref_list0)):
ref_list0[x_num] = x_range0[0] + delta[0] * ref_list0[x_num]
#计算y的解码值
for y_num in range(len(ref_list1)):
ref_list1[y_num] = x_range1[0] + delta[1] * ref_list1[y_num]
#构建二维解码值(x, y)
new_list = list(zip(ref_list0, ref_list1))
#构建二维解码值数组
f = np.array(new_list)
return f
#适应度函数
def Fittness_function(x, y):
#这里取负值,因为要求最小解,所以取目标函数的负值选最大的
# f1
return 1. / (pow(x, 2) + pow(y, 2))
# return (pow(x, 2) + pow(y, 2)) #求最大值
# #f2
# return 1. / (100 * pow((y - pow(x, 2)), 2) + pow((x - 1), 2))
##f3
# return 1. / (((1 + pow((x + y + 1), 2)) + (19 - 14 * x + 3 * pow(x, 2) - 14 * y + 6 * x * y + 3 * pow(y, 2))) * (
# pow((30 + 2 * x - 3 * pow(y, 2)), 2) * (18 - 32 * x + 12 * pow(x, 2) + 48 * y - 32 * x * y + 27 * y)
# ))
# #f4
# return 1. / (pow((pow(x, 2) + y - 11), 2) + pow((x + pow(y, 2) - 7), 2))
# #f5
# return 1. / (4 * pow(x, 2) + 2.1 * pow(x, 4) + (1/3) * pow(x, 6) + x * y - 4 * pow(y, 2) + 4 * pow(y, 4))
# #f6
# return 1.0 / (pow(x, 2) + pow(y, 2) - 0.3 * math.cos(3 * math.pi * x) + 0.3 * math.cos(4 * math.pi * y) + 0.3)
#目标函数
def Desti_function(x, y):
#f1
return pow(x, 2) + pow(y, 2)
# #f2
# return 100 * pow((y - pow(x, 2)), 2) + pow((x - 1), 2)
##f3
# return ((1 + pow((x + y + 1), 2)) + (19 - 14 * x + 3 * pow(x, 2) - 14 * y + 6 * x * y + 3 * pow(y, 2))) * (
# pow(30 + 2 * x - 3 * pow(y, 2), 2) * (18 - 32 * x + 12 * pow(x, 2) + 48 * y - 32 * x * y + 27 * y)
# )
# #f4
# return (pow((pow(x, 2) + y - 11), 2) + pow((x + pow(y, 2) - 7), 2))
# #f5
# return (4 * pow(x, 2) + 2.1 * pow(x, 4) + (1/3) * pow(x, 6) + x * y - 4 * pow(y, 2) + 4 * pow(y, 4))
# #f6
# return (pow(x, 2) + pow(y, 2) - 0.3 * math.cos(3 * math.pi * x) + 0.3 * math.cos(4 * math.pi * y) + 0.3)
#计算适应度
def Compute_Fitness(decode_value):
ref = np.array([])
for i in range(len(decode_value)):
ref = np.append(ref, Fittness_function(decode_value[i][0], decode_value[i][1]))
return ref
#轮盘赌选择
def Roulette_Select(fitness_value, init_pop):
'''
计算总体适应度F
计算选择概率p_select
计算累积概率q_select
生成相应数量的[0, 1]之间的随机数
若q_k-1<r<=q_k, 则选vk
将选择出来的结果作为新的种群返回
:param fitness_value: 适应度值
'''
#总体适应度
F = sum(fitness_value)
#计算选择概率
p_select = fitness_value.copy()
for i in range(len(fitness_value)):
p_select[i] = p_select[i] / F
#计算累积概率
q_select = fitness_value.copy()
for i in range(len(fitness_value)):
q_select[i] = 0.
for j in range(len(fitness_value)):
for k in range(0, j+1):
q_select[j] += p_select[k]
#生成[0,1]之间的随机数
rand_num = fitness_value.copy()
for i in range(len(fitness_value)):
rand_num[i] = 0.
np.random.seed()#产生不固定的随机数
rand_num = np.random.uniform(0, 1, len(rand_num))
#比较判别,若q_k-1<r<=q_k, 则选vk
new_list = []
for num in range(len(rand_num)):
for num_ in range(len(q_select)):
if num_ == 0:
if(rand_num[num] <= q_select[num_]):
new_list.append(init_pop[num_])
else:
if (rand_num[num] > q_select[num_ - 1] and rand_num[num] <= q_select[num_]):
new_list.append(init_pop[num_])
#存放选择结果
roulette_select_value = np.array(new_list)
#还需要将选择出来的二进制表示也选择出来,用于后续交叉和变异
return roulette_select_value
#交叉运算
def Cross_Select(select_pop, cross_prob):
'''
首先判断是否满足交叉条件,即根据给定交叉概率,为每个染色体产生随机概率,与给定交叉概率比较
符合条件的则进行交叉操作
:param select_pop: 选择出来的结果
:return:返回交叉后的结果
'''
#为每个染色体产生(0, 1)内的交叉概率
pop_cross_prob = np.random.uniform(0, 1, select_pop.shape[0])
#判断哪些染色体可以进行交叉操作,哪些不可以,拆分成两部分
cross_pop = select_pop[np.where(pop_cross_prob < cross_prob)]
no_cross_pop = select_pop[np.where(pop_cross_prob >= cross_prob)]
#开始交叉
fo