注:由于编码选择二进制编码,所以只能在整数范围进行搜索,也就是说求解到的最优解一定是最优的整数解,如果选择一些映射方法可以将离散问题连续化,但这样就和进化算法本身无关了,所以本文只写了基本的遗传算法
超参设置
- 染色体长度:10
- 种群:20
- 进化次数:50代
- 变异靶点:3
- 变异方式:插入,交换,局部逆序
- 变异概率:0.1
- 交叉方式:PMX修订两点交叉
import matplotlib.pyplot as plt
from math import *
import numpy as np
import random
import copy
minNum = 10
maxNum = 101
long = 10
population = 20
target_points = [1, 2, 3]
gens = 50
genRate = 0.1
def parseInt(bit):
if isinstance(bit, str):
n = '0b' + bit
return int(eval(n))
else:
return int(eval('0b' + ''.join(bit)))
def parseBin(i, t=str):
if t == str:
return str(bin(i)[2:])
else:
return bin(i)[2:]
def fitness(x):
if type(x) != int:
x = parseInt(x)
return x ** 3
def translong(i):
length = len(i)
n = long - length
if n != 0:
for h in range(n):
i = '0' + i
return i
def initPop(num):
population = []
xset = [random.randrange(minNum,maxNum) for i in range(num)]
for j in xset:
i = str(bin(j)[2:])
length = len(i)
n = long - length
if n != 0:
for h in range(n):
i = '0' + i
population.append(i)
return population
def overSection(bit):
n = parseInt(bit)
if minNum < n < maxNum:
return False
else:
return True
def twoPontsCross(p1, p2):
p1_ = list(copy.deepcopy(p1))
p2_ = list(copy.deepcopy(p2))
point1 = random.randint(0, len(p1_))
point2 = random.randint(0., len(p1))
while point1 > point2 or point1 == point2:
point1 = random.randint(0, len(p1))
point2 = random.randint(0., len(p1))
p1_[point1:point2], p2_[point1:point2] = p2_[point1:point2], p1_[point1:point2]
p1_ = ''.join(p1_)
p2_ = ''.join(p2_)
return str(p1_), str(p2_)
def gene_exchange(n):
n = list(n)
point1 = random.randint(0, len(n) - 1)
point2 = random.randint(0, len(n) - 1)
while point1 == point2 or point1 > point2:
point1 = random.randint(0, len(n) - 1)
point2 = random.randint(0, len(n) - 1)
n[point1], n[point2] = n[point2], n[point1]
n = ''.join(n)
return n
def gene_insertion(n):
n = list(n)
point1 = random.randint(0, len(n) - 1)
point2 = random.randint(0, len(n) - 1)
while point1 == point2:
point1 = random.randint(0, len(n) - 1)
point2 = random.randint(0, len(n) - 1)
x = n.pop(point1)
n.insert(point2, x)
n = ''.join(n)
return n
def gene_reverse(n):
n = list(n)
point1 = random.randint(0, len(n) - 1)
point2 = random.randint(0, len(n) - 1)
while point1 == point2 or point1 > point2:
point1 = random.randint(0, len(n) - 1)
point2 = random.randint(0, len(n) - 1)
ls_res = n[point1:point2]
ls_res.reverse()
l1 = n[:point1]
l2 = n[point2:]
n_res_end = l1 + ls_res + l2
n = ''.join(n)
return n_res_end
class node:
def __init__(self, bit):
self.bit = bit
self.fitness = fitness(bit)
def main():
best = []
pops = initPop(population)
popsfit = [node(i) for i in pops]
popsfit.sort(key=lambda x: x.fitness)
popsfit.reverse()
print(parseInt(popsfit[0].bit))
print('--' * 20)
for gen in range(gens):
children = []
pop_children1 = pops[1::2]
pop_children2 = pops[::2]
for r in range(len(pop_children1)):
child1, child2 = twoPontsCross(pop_children1[r], pop_children2[r])
if overSection(child1):
child1 = initPop(1)[0]
if overSection(child2):
child2 = initPop(1)[0]
children.append(translong(child1))
children.append(translong(child2))
for i in children:
rate = random.random()
if rate < genRate:
target = random.choice(target_points)
if target == 1:
c_exchange = gene_exchange(i)
if overSection(c_exchange):
children[children.index(i)] = initPop(1)[0]
else:
children[children.index(i)] = c_exchange
elif target == 2:
c_insert = gene_insertion(i)
if overSection(c_insert):
children[children.index(i)] = initPop(1)[0]
else:
children[children.index(i)] = c_insert
else:
c_reverse = gene_reverse(i)
if overSection(c_reverse):
children[children.index(i)] = initPop(1)[0]
else:
children[children.index(i)] = c_reverse
childrenFitness = [node(i) for i in children]
initpopulationFitness = [node(i) for i in pops]
initpopulationFitness += childrenFitness
initpopulationFitness.sort(key=lambda x: x.fitness)
initpopulationFitness.reverse()
del initpopulationFitness[10:]
pops = [i.bit for i in initpopulationFitness]
best.append(parseInt(pops[0]))
if gen % 10 == 0:
print(f'第{gen}代,当前最优解{parseInt(pops[0])}')
print(f'全局最优为:{parseInt(pops[0])}')
return parseInt(pops[0]), fitness(pops[0])
if __name__ == '__main__':
a, b = main()
x = np.linspace(10, 100, 1000)
y = [i ** 3 for i in x]
plt.plot(x, y)
plt.plot(a, b, '.r')
plt.show()