遗传算法

参考 https://blog.csdn.net/qq_27755195/article/details/56597467
https://blog.csdn.net/emiyasstar__/article/details/6938608/

应用

本质是一种高效、并行、全局搜索的方法,能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应地(遗传)控制搜索过程以求得最佳解.

如果是凸函数,凹函数,我们可以很快的得出最优解。
但如果是存在很多局部最优解的情况下,再用求n阶导的方法,就不能容易得到结果。

遗传算法的有趣应用很多,诸如寻路问题,8数码问题,囚犯困境,动作控制,找圆心问题(在一个不规则的多边形中,寻找一个包含在该多边形内的最大圆圈的圆心),TSP问题,生产调度问题,人工生命模拟等。下面我以袋鼠为例子讲讲遗传算法。(因为袋鼠会跳)

可以这样想象,这个多维曲面里面有数不清的“山峰”,而这些山峰所对应的就是局部最优解。而其中也会有一个“山峰”的海拔最高的,那么这个就是全局最优解。而遗传算法的任务就是尽量爬到最高峰,而不是陷落在一些小山峰。(另外,值得注意的是遗传算法不一定要找“最高的山峰”,如果问题的适应度评价越小越好的话,那么全局最优解就是函数的最小值,对应的,遗传算法所要找的就是“最深的谷底”)

袋鼠引入

引入“袋鼠跳”,理解下基本的算法流程。

既然我们把函数曲线理解成一个一个山峰和山谷组成的山脉。那么我们可以设想所得到的每一个解就是一只袋鼠,我们希望它们不断的向着更高处跳去,直到跳到最高的山峰(尽管袋鼠本身不见得愿意那么做)。所以求最大值的过程就转化成一个“袋鼠跳”的过程。
对比下面简单介绍“袋鼠跳”的几种方式:

  1. 爬山法(最速上升爬山法):
    从搜索空间中随机产生邻近的点,从中选择对应解最优的个体,替换原来的个体,不断重复上述过程。因为爬山法只对“邻近”的点作比较,所以目光比较“短浅”,常常只能收敛到离开初始位置比较近的局部最优解上面。对于存在很多局部最优点的问题,通过一个简单的迭代找出全局最优解的机会非常渺茫。(在爬山法中,袋鼠最有希望到达最靠近它出发点的山顶,但不能保证该山顶是珠穆朗玛峰,或者是一个非常高的山峰。因为一路上它只顾上坡,没有下坡。)
  2. 模拟退火:
    这个方法来自金属热加工过程的启发。在金属热加工过程中,当金属的温度超过它的熔点(Melting Point)时,原子就会激烈地随机运动。与所有的其它的物理系统相类似,原子的这种运动趋向于寻找其能量的极小状态。在这个能量的变迁过程中,开始时,温度非常高, 使得原子具有很高的能量。随着温度不断降低,金属逐渐冷却,金属中的原子的能量就越来越小,最后达到所有可能的最低点。利用模拟退火的时候,让算法从较大的跳跃开始,使到它有足够的“能量”逃离可能“路过”的局部最优解而不至于限制在其中,当它停在全局最优解附近的时候,逐渐的减小跳跃量,以便使其“落脚 ”到全局最优解上。(在模拟退火中,袋鼠喝醉了,而且随机地大跳跃了很长时间。运气好的话,它从一个山峰跳过山谷,到了另外一个更高的山峰上。但最后,它渐渐清醒了并朝着它所在的峰顶跳去。)
  3. 遗传算法:
    模拟物竞天择的生物进化过程,通过维护一个潜在解的群体执行了多方向的搜索,并支持这些方向上的信息构成和交换。是以面为单位的搜索,比以点为单位的搜索,更能发现全局最优解。(在遗传算法中,有很多袋鼠,它们降落到喜玛拉雅山脉的任意地方。这些袋鼠并不知道它们的任务是寻找珠穆朗玛峰。但每过几年,就在一些海拔高度较低的地方射杀一些袋鼠,并希望存活下来的袋鼠是多产的,在它们所处的地方生儿育女。)(或者换个说法。从前,有一大群袋鼠,它们被莫名其妙的零散地遗弃于喜马拉雅山脉。于是只好在那里艰苦的生活。海拔低的地方弥漫着一种无色无味的毒气,海拔越高毒气越稀薄。可是可怜的袋鼠们对此全然不觉,还是习惯于活蹦乱跳。于是,不断有袋鼠死于海拔较低的地方,而越是在海拔高的袋鼠越是能活得更久,也越有机会生儿育女。就这样经过许多年,这些袋鼠们竟然都不自觉地聚拢到了一个个的山峰上,可是在所有的袋鼠中,只有聚拢到珠穆朗玛峰的袋鼠被带回了美丽的澳洲。)

实现

把那些总是爱走下坡路的袋鼠射杀,这是遗传算法的精粹!
所以我们总结出遗传算法的一般步骤:

while(开始循环直至找到满意的解):
1.评估每条染色体所对应个体的适应度。
2.遵照适应度越高,选择概率越大的原则,从种群中选择两个个体作为父方和母方。
3.抽取父母双方的染色体,进行交叉,产生子代。
4.对子代的染色体进行变异。
5.重复2,3,4步骤,直到新种群的产生。
结束循环。

评分函数及选择函数

1、物竞
适应度函数
我们的衡量标准是:袋鼠所在的海拔高度,越高越好
可直接用袋鼠的海拔高度作为适应性评分。
2、天择
选择函数:对环境适应性越强的越有利于生存下去,繁衍后代。
对适应性打分,分别为 x 1 x_1 x1 x 2 x_2 x2,,,,, x i x_i xi,然后按照评分大小排序进行选择。

伪代码

具体求解TSP问题

背景:TSP旅行问题

问题:
从某物流中心用多台配送车辆向多个客户送货,每个客户的位置和货物需求量一定,每台配送车辆的载重量一定,其一次配送的最大行驶距离一定,要求合理安排车辆配送路线,使目标函数得到优化,并满足以下条件:
(1) 每条配送路径上各客户的需求量之和不超过配送车辆的载重量;
(2) 每条配送路径的长度不超过配送车辆一次配送的最大行驶距离;
(3) 每个客户的需求必须满足,且只能由一台配送车辆送货。
以配送总里程最短为目标函数

实例:
某物流中心有2 台配送车辆,其载重量均为8t ,车辆每次配送的最大行驶距离为50km ,配送中心(其编号为0) 与8 个客户之间, 8 个客户相互之间的距离 d i , j d_{i,j} di,j 为:

123456789
10467.592010168
2406.541057.51110
366.507.510107.57.57.5
47.547.501059915
591010100107.57.510
6205105100797.5
7107.57.597.570710
816117.597.597010
98107.515107.510100

8 个客户的货物需求量 q j q_j qj为:q = [ 0, 1, 2, 1, 2, 1, 4, 2, 2 ],0值为配送中心

要求合理安排车辆配送路线,使配送总里程最短。
采用以下参数:
群体规模取20 ;
进化代数取25 ;
交叉概率取0.9 ;JCL = 0.9
变异概率取0.09 ;BYL = 0.09
变异时基因换位次数取5;JYHW = 5
实施爬山操作时爬山次数取20 ;PSCS = 20
对不可行路径的惩罚权重取100km;
对实例随机求解10 次;

代码

总流程迭代

1、初始化
2、计算适应度
3、产生新的集群
4、重复123

初始化

    def __init__(self, rows, times, mans, cars, tons, distance, PW):
        self.rows = rows                            '''排列个数'''
        self.times = times                          '''迭代次数'''
        self.mans = mans                            '''客户数量'''
        self.cars = cars                            '''车辆总数'''
        self.tons = tons                            '''车辆载重'''
        self.distance = distance                    '''车辆一次行驶的最大距离'''
        self.PW = PW                                '''当生成一个不可行路线时的惩罚因子'''

适应度函数计算

'''
计算适应度
计算的规则:每条配送路径要满足题设条件,并且目标函数即 车辆行驶的总里程越小,适应度越高
'''
def calFitness(self, line, isShow):
    carTon = 0 '''当前车辆的载重'''
    carDis = 0 '''当前车辆行驶的总距离'''
    newTon = 0
    newDis = 0
    totalDis = 0

    r = 0      '''表示当前需要车辆数'''
    fore = 0   '''正在运送的客户编号'''
    M = 0      '''当前的路径规划所需要的总车辆和总共拥有的车辆之间的差,如果大于0,表示是一个失败的规划,乘以一个很大的惩罚因子用来降低适应度'''
    '''遍历每个客户点'''
    for i in range(0, self.mans):
        '''行驶的距离'''
        newDis = carDis + self.d[fore][line[i]]
        '''当前车辆的载重'''
        newTon = carTon + self.q[line[i]]
        '''如果已经超过最大行驶距离或者超过车辆的最大载重,切换到下一辆车'''
        if newDis + self.d[line[i]][0] > self.distance or newTon > self.tons:
            '''下一辆车'''
            totalDis += carDis + self.d[fore][0]  '''后面加这个d[fore][0]表示需要从当前客户处返程的距离'''
            r += 1
            fore = 0
            i -= 1  '''表示当前这个点的配送还没有完成'''
            carTon = 0
            carDis = 0
        else:
            carDis = newDis
            carTon = newTon
            fore = line[i]
    '''加上最后一辆车的距离和返程的距离'''
    totalDis += carDis + self.d[fore][0]
    if isShow:
        print "总行驶里程为: %.1fkm" %(totalDis)
    else:
        # print "中间过程尝试规划的总行驶里程为: %.1fkm" %(totalDis)
        pass
    '''判断路径是否可用,所使用的车辆数量不能大于总车辆数量'''
    if r - self.cars + 1 > 0:
        M = r - self.cars + 1
    '''目标函数,表示一个路径规划行驶的总距离的倒数越小越好'''
    result = 1 / (totalDis + M * self.PW)
    return result

新增集群

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值