本文是用Python语言写的遗传算法,初次尝试,效率不高,但能较好地理解简单的遗传算法。
在实际应用中,推荐学习geatpy库。
import numpy as np
class Ga:
@classmethod
def codeit(cls, n, length):
#
# 创建初始群体
# 传入参数, 初始群体数量n, 编码长度length
# 返回初始群体编码列表
#
inipol = []
for i in range(n):
tempb = ""
for j in range(length):
data = np.random.choice([0, 1])
tempb += str(data)
inipol.append(tempb)
return inipol
@classmethod
def decodeit(cls, coding, lowest, ranges):
#
# 解码
# 传入参数, 编码coding, 可行域最小值lowest, 取值长度ranges
# 返回解码列表decoding
#
decoding = np.copy(coding).tolist()
length = len(decoding[0])
for i in range(len(decoding)):
decoding[i] = np.round(lowest + int(decoding[i], base=2)*ranges/(2**length-1), 3)
return decoding
@staticmethod
def fits(x):
#
# 适应度函数
#
return x + 10*np.sin(5*x) + 7*np.cos(4*x)
@classmethod
def fitnessevaluations(cls, decoding):
#
# 个体适应度评价
# 传入参数,解码decoding
# 返回个体适应度值列表fitnessvalues
#
fitnessvalues = []
for i in decoding:
fitnessvalues.extend([np.round(Ga.fits(i), 3)])
return fitnessvalues
@classmethod
def copyoperator(cls, coding, fitnessvalues):
#
# 复制算子
# 传入参数,编码coding,适应度值fitnessvalues
# 返回复制算子编码copycoding
#
copycoding = np.copy(coding).tolist()
minindex = fitnessvalues.index(min(fitnessvalues))
maxindex = fitnessvalues.index(max(fitnessvalues))
copycoding[minindex] = copycoding[maxindex]
copycoding[minindex] = copycoding[maxindex]
return copycoding
@classmethod
def crossoveroprator(cls, copycoding, crossoverposssibility):
#
# 杂交算子
# 参入参数,复制算子编码copycoding,杂交概率crossoverposibility
# 返回杂交算子编码crossovercoding
#
crossovercoding = np.copy(copycoding).tolist()
copysave = []
crossover = []
for i in range(int(len(crossovercoding)*crossoverposssibility)):
copysave.append(crossovercoding[i])
for i in range(int(len(crossovercoding) * (1-crossoverposssibility))):
crossover.append(crossovercoding[-i-1])
crossoverpoit = len(crossovercoding)-1
for i in range(int(len(crossover)/2)):
crossover[i], crossover[-i-1] = \
crossover[i][:crossoverpoit]+crossover[-i-1][crossoverpoit:], \
crossover[-i - 1][:crossoverpoit] + crossover[-i][crossoverpoit:]
crossovercoding = copysave + crossover
return crossovercoding
@classmethod
def mutationoprator(cls, crossovercoding, mutationpossibility, lowest, ranges):
#
# 变异算子
# 传入参数, 杂交算子编码crossovercoding,变异概率crossoverpossibility
# 可行域最小值lowest, 取值长度ranges,
# 返回变异算子编码
#
mutationcoding = np.copy(crossovercoding).tolist()
crossoverfitnessvalues = Ga.fitnessevaluations(Ga.decodeit(mutationcoding, lowest, ranges))
tempfitvaleus = np.copy(crossoverfitnessvalues).tolist()
tempfitvaleus.sort()
mutationvalues = []
for i in range(int(len(tempfitvaleus)*mutationpossibility)):
mutationvalues.append(tempfitvaleus[i])
mutaionindex = []
for i in mutationvalues:
mutaionindex.append(crossoverfitnessvalues.index(i))
mutationposition = np.random.randint(0, len(mutationcoding[0]))
for i in mutaionindex:
if int(mutationcoding[i][mutationposition]) == 1:
mutationcoding[i] = mutationcoding[i][:mutationposition] + '0' + mutationcoding[i][mutationposition+1:]
else:
mutationcoding[i] = mutationcoding[i][:mutationposition] + '1' + mutationcoding[i][mutationposition + 1:]
return mutationcoding
from genetic_algorithm.ga import Ga as ga
import matplotlib.pyplot as plt
import numpy as np
def multiply(coding):
#
# 繁衍一代
# 传入参数,上一代编码coding
# 返回,新一代编码mutationcoding,新一代解码值decoding,新一代适应度值fitnessvalues
#
inipol = coding
decoding = ga.decodeit(inipol, boudary[0], brange)
fitnessvalues = ga.fitnessevaluations(decoding)
copycoding = ga.copyoperator(inipol, fitnessvalues)
crossovercoding = ga.crossoveroprator(copycoding, crossoverpossibility)
mutationcoding = ga.mutationoprator(crossovercoding, mutationpossibility, boudary[0], brange)
return mutationcoding, decoding, fitnessvalues
def generateit():
#
# 繁衍多代
# 返回,最终编码coding,每次繁衍的编码decodings,每次繁衍的适应度值fitnessvalues,初始编码iniplot,每代的适应度值fitness
#
inipol = ga.codeit(n, length)
decodings = []
fitnessvalues = []
fitness = []
iniplot = np.copy(inipol).tolist()
for i in range(g):
inipol = multiply(inipol)[0]
decodings.append(multiply(inipol)[1])
fitnessvalues.append(multiply(inipol)[2])
fitness.append(np.mean(multiply(inipol)[2]))
return inipol, decodings, fitnessvalues, iniplot, fitness
def plotit():
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
inicoding = generateit()[3]
inidecoding = ga.decodeit(inicoding, boudary[0], brange)
initfittness = ga.fitnessevaluations(inidecoding)
decoding = generateit()[1][-1]
fitnessvalue = generateit()[2][-1]
fitness = generateit()[4]
x = np.linspace(boudary[0], boudary[1], 1000)
fits = x + 10*np.sin(5*x) + 7*np.cos(4*x)
plt.suptitle("简单遗传算法")
plt.subplot(121)
ax = plt.gca()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.plot(x, fits) # 适应度曲线
plt.scatter(inidecoding, initfittness, c='blue') # 初始编码
plt.scatter(decoding, fitnessvalue, c='red') # 进化后的编码
plt.xlabel("编码")
plt.ylabel("适应度值")
plt.title("适应度曲线")
plt.subplots_adjust(wspace=0.5)
plt.subplot(122)
ax = plt.gca()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.plot(range(g), [j for j in fitness]) # 适应度值变化曲线
plt.xlabel("进化次数")
plt.ylabel("适应度值")
plt.title("适应度值变化曲线")
plt.savefig("简单遗传算法")
if __name__ == "__main__":
boudary = [0, 10] # 变量范围
brange = boudary[1] - boudary[0]
accuracy = 1 / 1000 # 精度
n = 50 # 初始群体数量
g = 100 # 代
crossoverpossibility = 0.65 # 杂交概率
mutationpossibility = 0.05 # 变异概率
length = int(np.rint(np.log2(brange / accuracy))) # 编码长度
with open("初始编码.txt", 'w', encoding="utf-8") as f:
for i in generateit()[3]:
f.writelines(i+'\n')
with open("进化编码.txt", 'w', encoding="utf-8") as f:
for i in generateit()[0]:
f.writelines(i + '\n')
with open("进化解码.txt", 'w', encoding="utf-8") as f:
for i in generateit()[1][-10:]:
f.writelines(str(i)+'\n')
with open("进化适应度值.txt", 'w', encoding="utf-8") as f:
for i in generateit()[2][-10:]:
f.writelines(str(i)+'\n')
plotit()