python 遗传算法 车辆调度

问题描述:

有货场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的,由于电脑配置不行,所以种群数量设置的少,所以存在运行差异,

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值