import numpy as np
import random
from scipy.optimize import fsolve
‘’’
对数自适应排挤遗传算法LGCCGA
引入爬山算子
author:sugarMei
date:2020/7/7
version:1.0
‘’’
‘’’
n:种群个数
min_d:爬上距离下限
max_d:爬山距离上限
gens:迭代的最大次数
Vars:定义域大小
dimension:问题维度
fits:适应度值
delta:精度 编码时精度
mutation_prob:变异概率
cross_prob:交叉概率
‘’’
参数初始化
n = 500
Vars = [-10, 10]
dimension = 2
min_d = 0.000001
max_d = 0.001
gens = 500
fits = np.zeros(n)
mutation_prob = 0.05
delta = 0.0001
cross_prob = 0.7
Cross-in-tray函数表示
def CrossInTray(x1, x2):
fact1 = np.sin(x1) * np.sin(x2)
fact2 = np.exp(np.abs(100 - np.sqrt(x1 ** 2 + x2 ** 2) / np.pi))
res = -0.0001 * (np.abs(fact1 * fact2) + 1) ** 0.1
return res
编码长度
def getEncodeLength(var, delta):
lengths = []
# 由于两个变量的上下界一致 只需要计算一次
res = fsolve(lambda x: ((var[1] - var[0]) / delta - 2 ** x + 1), [20])
# 向上取整
length = int(np.ceil(res[0]))
lengths.append(length)
lengths.append(length)
# 返回list lengths[0]代表第一个变量的编码长度
return lengths
初始化种群
def initPopulation(length_dna, size):
tmp = np.zeros((size, length_dna))
for i in range(size):
# 对每一行 即一个个体进行随机初始化
tmp[i, :] = np.random.randint(0, 2, length_dna)
return tmp
二进制的解码 针对一个个体的解码
def decode(x, lengths, var, delta):
# 多少个变量
length = len(lengths)
tmp = np.zeros(length)
start = 0
for i in range(length):
# 解码的值
decimal = 0
# 次方
power = lengths[i] - 1
for j in range(start, lengths[i] + start):
decimal += x[j] * (2 ** power)
# 次方减1 进行下一计算
power -= 1
# 更新start
start += lengths[i]
value = var[0] + decimal * (var[1] - var[0]) / (2 ** lengths[i] - 1)
tmp[i] = value
return tmp
两个个体交叉运算 单点交叉
def crossover(x1, x2):
# 随机找到一个交叉点
crossPoint = np.random.randint(0, sum(lengthDna), 1)[0]
x1[:crossPoint], x2[:crossPoint] = x2[:crossPoint], x1[:crossPoint]
return x1, x2
变异运算
def mutation(x):
# print(x)
if np.random.random() < mutation_prob:
mutation_point = np.random.randint(0, sum(lengthDna), 1)[0]
x[mutation_point] = int(x[mutation_point]) ^ 1
return x
爬山算子计算
def climb(x, m):
# 定义8个方向 上下前后以及对角线
dx, dy = [0, 0, 1, -1, 1, 1, -1, -1], [1, -1, 0, 0, 1, -1, 1, -1]
# 线性自适应
d = min_d - (gens - m) / (gens - 1) * (min_d - max_d)
# 对x进行解码
value = decode(x, lengthDna, Vars, delta)
for i in range(len(dx)):
new_x, new_y = value[0] + d, value[1] + d
# 满足定义域
if Vars[0] <= new_x <= Vars[1] and Vars[0] <= new_y <= Vars[1]:
if CrossInTray(value[0], value[1]) > CrossInTray(new_x, new_y):
new_x_y = [new_x, new_y]
# 新值更好 将new_x、new_y数值编码
# 定义新的二进制编码变量
start = 0
encode = np.zeros(sum(lengthDna))
for j in range(len(lengthDna)):
# 根据公式计算原始的decimal
decimal = (2 ** lengthDna[j] - 1) * (new_x_y[j] - Vars[0]) / (Vars[1] - Vars[0])
# 将十进制数转化为二进制数
b = bin(int(decimal))[2:]
# 补0操作
for k in range(lengthDna[j] - len(b)):
b = "0" + b
# 赋值操作
for k in range(start, start + lengthDna[j]):
encode[k] = int(b[k - start])
# 更新起始位置
start += lengthDna[j]
# print("encode", encode)
return encode
return x
lengthDna = getEncodeLength(Vars, delta)
print(sum(lengthDna))
X = initPopulation(sum(lengthDna), n)
print(X[0])
print(decode(X[0], lengthDna, Vars, delta))
m = 2 # 当前遗传代数
allowed = [i for i in range(n)] # 随机选择允许选择的父代个体
计算所有的个体的适应度值
for i in range(n):
# 解码
tmp = decode(X[i], lengthDna, Vars, delta)
# 计算函数值
fits[i] = CrossInTray(tmp[0], tmp[1])
while m < gens:
allowed = [i for i in range(n)]
# 总共n个个体 每次随机选择两个 需要n/2次迭代
for i in range(int(n / 2)):
if np.random.random() < cross_prob:
# 从种群中随机选择两个个体作为父代
[idx1, idx2] = random.sample(allowed, 2)
# 从allowed中删除选中的父代序号
allowed.remove(idx1)
allowed.remove(idx2)
f1 = X[idx1]
f2 = X[idx2]
# 对父代进行交叉运算 生成s1、s2
s1, s2 = crossover(f1, f2)
# 对子代进行变异运算
s1, s2 = mutation(s1), mutation(s2)
# 在对两个子代进行爬山算子计算
s1, s2 = climb(s1, m), climb(s2, m)
# 重新计算两个子代的是适应度值
# 解码
s_d_1, s_d_2 = decode(s1, lengthDna, Vars, delta), decode(s2, lengthDna, Vars, delta)
# 计算适应度值
s_f_1, s_f_2 = CrossInTray(s_d_1[0], s_d_1[1]), CrossInTray(s_d_2[0], s_d_2[1])
# 计算两个父代与两个子代分别的欧式距离
d1 = np.linalg.norm(f1 - s1)
d2 = np.linalg.norm(f1 - s2)
d3 = np.linalg.norm(f2 - s1)
d4 = np.linalg.norm(f2 - s2)
# print(d1, d2, d3, d4)
# 排挤过程
if d1 + d4 <= d2 + d3:
if s_f_1 > fits[idx1]:
X[idx1] = s1
if s_f_2 > fits[idx2]:
X[idx2] = s2
else:
if s_f_2 > fits[idx1]:
X[idx1] = s2
if s_f_1 > fits[idx2]:
X[idx2] = s1
# 计算所有的个体的适应度值
for i in range(n):
# 解码
tmp = decode(X[i], lengthDna, Vars, delta)
# 计算函数值
fits[i] = CrossInTray(tmp[0], tmp[1])
m += 1
if min(fits) < -2.062:
print("第", m, "次迭代", "最小值:", min(fits))
print("具体坐标:", decode(X[np.argmin(fits)], lengthDna, Vars, delta))