问题描述:
有货场1 ,要送货到地点2 ,3,…,1 5 ,每个地点需要送货的质量为gi={ 0,1.2,3.2,2.5,0 .7,1.4,0.5,3.6,5.1,1.5,2.6,1.3,2.4,2.3,0.5},g1=0代表货场1给货场送的货为零,货车的标记载重为10 t,染色体采用 0-1编码,交叉概率为0.7,变异概率为0.03,种群规模为 2 0,迭代次数为100 次,算出最优方案为 x
目标函数为:
from itertools import count
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import MultipleLocator
DNA_SIZE = 15
POP_SIZE = 5 #这个太小啦,自行探索,种群规模是指任意一代中的个体总数,这个是人为设定的,种群规模越大越可能找到全局解,但运行时间也相对较长
CROSSOVER_RATE = 0.7 #交叉操作中的概率是用于判定两个个体是否进行交叉操作,一般都会大于0.9
MUTATION_RATE = 0.003 #变异操作的概率是允许少数个体存在变异情况,以避免限入局部最优解,其值一般都在0.1以下
N_GENERATIONS = 100
W=10
G=[0,1.2,3.2,2.5,0.7,1.4,0.5,3.6,5.1,1.5,2.6,1.3,2.4,2.3,0.5]
def F(pop): #F(pop)获得种群所有个体解
A=[]
for n in pop:
A.append(f(n))
return A
def f(n): #f(n)获得一个个体解
a=0
i=0
for i in range(15):
a=a+G[i]*n[i]
return a
def get_fitness(pop):
pred = F(pop)
return (pred - np.min(pred)) + 1e-3 #减去最小的适应度是为了防止适应度出现负数,choice函数的p值不能为负,通过这一步fitness的范围为[0, np.max(pred)-np.min(pred)],最后在加上一个很小的数防止出现为0的适应度
def crossover_and_mutation(pop, CROSSOVER_RATE = 0.7): #经过适应函数筛选后的解再通过交叉算子来维持解的多样性
new_pop = []
for father in pop: #遍历种群中的每一个个体,将该个体作为父亲,遗传算法采用循环交叉一般是因为个体是有某个序列组成,染色体不能有相同的情况,
child = father #孩子先得到父亲的全部基因(这里我把一串二进制串的那些0,1称为基因)
if np.random.rand() < CROSSOVER_RATE: #产生子代时不是必然发生交叉,而是以一定的概率发生交叉
mother = pop[np.random.randint(POP_SIZE)] #zai1种群中选择另一个个体,并将该个体作为母亲
cross_points = np.random.randint(low=0, high=DNA_SIZE) #随机产生交叉的点
child[cross_points:] = mother[cross_points:] #孩子得到位于交叉点后的母亲的基因,child[cross_points:]从cross_points+1开始往后取
for x in count(): #要满足载重总量小于10
if f(child)<=10: break
cross_points = np.random.randint(low=0, high=DNA_SIZE) #随机产生交叉的点
child[cross_points:] = mother[cross_points:]
# while f(child)>10:
# cross_points = np.random.randint(low=0, high=DNA_SIZE) #随机产生交叉的点
# child[cross_points:] = mother[cross_points:]
# print(f(child))
mutation(child) #每个后代有一定的机率发生变异
new_pop.append(child)
return new_pop
def mutation(child, MUTATION_RATE=0.003): #变异是为了产生新模式,摆脱局部最优解
if np.random.rand() < MUTATION_RATE: #以MUTATION_RATE的概率进行变异
mutate_point = np.random.randint(0, DNA_SIZE) #随机产生一个实数,代表要变异基因的位置
child[mutate_point] = child[mutate_point]^1 #将变异点的二进制为反转, ^在算术运算中,表示异或
# while f(child)>10: #while循环太慢了
# mutate_point = np.random.randint(0, DNA_SIZE) #随机产生一个实数,代表要变异基因的位置
# child[mutate_point] = child[mutate_point]^1
for x in count(): #要满足载重总量小于10
if f(child)<=10: break
mutate_point = np.random.randint(0, DNA_SIZE) #随机产生一个实数,代表要变异基因的位置
child[mutate_point] = child[mutate_point]^1 #将变异点的二进制为反转, ^在算术运算中,表示异或
def select(pop, fitness): # nature selection wrt pop's fitness,choice()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法
idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,p=(fitness)/(fitness.sum())) #choice返回一个列表,元组或字符串的随机项,p与a对应,arange() 函数的作用是创建一个数组,生成数组[ 0 1 2 3 4...199],p为轮盘对赌法
return pop[idx]
def plot_2d():
x_values=list(range(N_GENERATIONS))
y_values=FZ
if 'sca' in locals(): #locals()函数不需要参数,会以字典类型返回当前位置的全部局部变量
plt.sca.remove() #remove() 函数用于移除列表中某个值的第一个匹配项,定义过的话删除图上的点
plt.plot(x_values,y_values,c='green')
plt.tick_params(axis='both',which='major',labelsize=14)
plt.xlabel('generate_num',fontsize=14)
plt.ylabel('F_value',fontsize=14)
x_major_locator=MultipleLocator(10)
#把x轴的刻度间隔设置为1,并存在变量里
ax=plt.gca()
#ax为两条坐标轴的实例
ax.xaxis.set_major_locator(x_major_locator)
plt.ion()#将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
plt.ioff() #没有使用ioff()关闭的话,则图像会一闪而过,并不会常留。要想防止这种情况,需要在plt.show()之前加上ioff()命令
plt.pause(0.5)
plt.show()
if __name__ == "__main__": #指定主方法函数。在脚本执行时开启main函数,但是在其他文件import调用时不会执行。
pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE))
s=F(pop)
for x in count():
if max(s)<=10: break
pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE))
s=F(pop)
# while max(s)>10:
# pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE))
# s=F(pop)
# print(s)
FZ=[]
for _ in range(N_GENERATIONS):#迭代N代,N无明确规定,只要收敛就行,看x,y变化大不大,变化不大说明收敛了,根据散点图,(x,y)最后都是集中在一个地方
# x=crossover_and_mutation(pop, CROSSOVER_RATE)
# while max(F(x)):
# crossover_and_mutation(pop, CROSSOVER_RATE)
pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE)) #生成5个数组
fitness = get_fitness(pop)
pop = select(pop, fitness) #选择生成新的种群
fitness = get_fitness(pop)
max_fitness_index = np.argmax(fitness) #求自变量最大的函数
mx=pop[max_fitness_index]
b=f(mx)
FZ.append(b)
print(FZ)
fitness = get_fitness(pop)
max_fitness_index = np.argmax(fitness) #求自变量最大的函数
MX=pop[max_fitness_index]
print("max_fitness:", fitness[max_fitness_index])
print("最优的基因型:", pop[max_fitness_index])
print("最大值:", f(MX))
plot_2d()
运行结果如上,这次运行最大值是9.4,之前有达到10的,由于电脑配置不行,所以种群数量设置的少,所以存在运行差异,