模拟退火算法与遗传算法之Python

实验一实验报告 模拟退火算法与遗传算法 一, 实验要求 模拟退火算法: 在 TSPLIB(http://comopt,ifi

本文包含相关资料包-----> 点击直达获取<-------

实验一实验报告

模拟退火算法与遗传算法

一. 实验要求

模拟退火算法:

在 TSPLIB(http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/,多个地址有备份;其他网站还可以找到有趣的 art TSP 和 national TSP)中选一个大于 100 个城市数的 TSP 问题,

  1. 采用多种邻域操作的局部搜索 local search 策略求解;
  2. 在局部搜索策略的基础上,加入模拟退火 simulated annealing 策略,并比较两者的效果;
  3. 要求求得的解不要超过最优值的 10%,并能够提供可视化,观察路径的变化和交叉程度。

遗传算法:

用遗传算法求解 TSP 问题(问题规模等和模拟退火求解 TSP 实验同),要求:

1.设计较好的交叉操作,并且引入多种局部搜索操作(可替换通常遗传算法的变异操作)

2.和之前的模拟退火算法(采用相同的局部搜索操作)进行比较

3.得出设计高效遗传算法的一些经验,并比较单点搜索和多点搜索的优缺点。

二、算法原理

1. TSP 问题

TSP 问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访 n 个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

TSP 问题是一个组合优化问题。该问题可以被证明具有 NPC 计算复杂性。所有的 TSP 问题都可以用一个图(Graph)来描述:

  • $V={c1, c2, …, ci, …, cn}$,$i = 1,2, …, n$,是所有城市的集合,ci 表示第 i 个城市, n 为城市的数目
  • $E={(r, s): r,s∈ V}$是所有城市之间连接的集合
  • $C = {c_{rs}: r,s∈ V}$是所有城市之间连接的成本度量(一般为城市之间的距离)

那么一个 TSP 问题可以表达为:

求解遍历图$G = (V, E, C)$所有的节点一次并且回到起始节点,并使得连接这些节点的路径成本最低。

2. 局部搜索求解

局部搜索是一种局部择优的方法,采用启发式方法,每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解。

用局部搜索求解的步骤如下:

  • 首先随机生成一段遍历所有城市的序列
  • 采用某种邻域操作并比较操作前后的总距离,若距离变小则使这个邻域操作生效
  • 重复以上过程,直到采用邻域操作后的总距离和之前的差小于某一阀值后停止
  • 此时便得到了最优的序列

其中,邻域操作可以有很多种,我使用了如下三种:

  • 随机找到一段序列后翻转
  • 随机找到两段连续的序列后交换这两段序列的位置
  • 随机找到两段连续的序列后将后一段序列翻转并交换这两段序列的位置

3. 模拟退火

  • 初始化温度 $T_{0,}$ 令当前温度 $T=T_{0}$, 任取初始解
  • 对当前解 $S_{1}$ 进行邻域操作,然后产生一个新解 $S_{2}$
  • 计算 $S_{2}$ 的增量 $d f=f\left(S_{2}\right)-f\left(S_{1}\right)$
  • 若 $d f<0$, 则接受 $S_{2}$ 作为新的当前解; 否则计算 $S_{2}$ 的接受概率 $\exp \left(-\frac{d f}{T}\right)$, 然后产生一个在 $(0,1)$ 区间上均匀分布的随机数 $r a n d$ ,若$\exp \left(-\frac{d f}{T}\right)>\ rand$ 则接受 $S_{2}$ 作为新的当前解 $S_{1}=S_{2}$ , 否则保留当前解 $S_{1}$
  • 如果温度低于某一个值则输出当前解 $S_{1}$ 为最优解,程序结束; 否则将温度 T 乘上退火系数后返回第 3 步

4. 遗传算法

遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,通过模拟自然进化过程搜索最优解。通常的流程是先建立一个包含潜在的解的群体作为种群,在环境作用下通过选择、交叉和变异一代代繁衍,由于子代的环境适应力一般优于父代,因此算法最终能够得到问题的较优解。

① 选择

选择算法是指参照适应值函数,按照预先选定的策略随机从父代中挑选一些个体生存下来,剩下的个体则被淘汰。

这次实验我选择的是轮盘赌选择法。轮盘赌选择法是依据个体的适应度值计算每个个体在子代中出现的概率,并按照此概率随机选择个体构成子代种群。轮盘赌选择策略的出发点是适应度值越好的个体被选择的概率越大,步骤如下:

  • 计算群体中每个个体的适应度
  • 计算每个个体遗传到下一代的概率
  • 计算每个个体的累计概率
  • 产生一个[0,1]区间内的随机数,若该随机数小于或等于个体的累积概率且大于个体 1 的累积概率,选择个体进入子代种群
  • 重复上述步骤

② 交叉

交叉是指仿照自然界基因传递的过程交配,对存活下来的父代个体的某些基因进行优化组合,办法是将两个父代个体某些对应位置的基因互换,以产生新的个体。

这次实验我选择的是次序交叉法 Order Crossover (OX):

  • 随机选择一对染色体(父代)中几个基因的起止位置
  • 生成一个子代,并保证子代中被选中的基因的位置与父代相同
  • 先找出第一步选中的基因在另一个父代中的位置,再将其余基因按顺序放入上一步生成的子代中

③ 变异

变异操作我按照要求就是使用各种邻域操作。

三、算法实现

0. 初始化

  • 首先定义一个城市类,用于保存编号及坐标

python class city: # 初始化城市编号及坐标 def __init__(self, index, x, y): self.cityIndex = index self.x = x self.y = y - 读取 tsp 文件获取城市信息

python cities = [] # 读取tsp文件初始化城市 with open("../tc/rat195.tsp") as file: cities = [] begin = False for line in file.readlines()[0:-1]: # 读取结束 if line.startswith('EOF'): break # 跳过开头开始读取 if line.startswith('NODE_COORD_SECTION'): begin = True elif begin == True: info = re.split('[ ]+', line.strip()) cities.append(city(info[0], float(info[1]), float(info[2]))) numOfCity = len(cities) - 由于城市间的距离需要反复访问,所以在一开始就计算每两个城市的距离存入表中

python # 计算每两个城市的距离 for i in range(numOfCity): dis = [] for j in range(len(cities)): dis.append(int(math.sqrt(math.pow(cities[i].x - cities[j].x, 2) + math.pow(cities[i].y - cities[j].y, 2)))) distance.append(dis)

1. 局部搜索

  • 先随机一条路径并计算当前总距离

python path = [i for i in range(numOfCity)] random.shuffle(path) path.append(path[0]) # 计算当前的总距离 dis = 0.0 for i in range(len(path) - 1): dis += distance[path[i]][path[i+1]] - 接下来进行邻域操作

  • 随机交换两段序列

    ```python first = random.randint(1, len(path)-3) second = random.randint(first+1, len(path)-2)

    计算总距离的改变

    dE = distance[path[first-1]][path[second]] + distance[path[first]][path[second+1] ] - distance[path[first-1]][path[first]] - distance[path[second]][path[second+1]]

    若距离更短则改变有效

    if dE < 0: path[first:second+1] = path[second:first-1:-1] dis = dis + dE ``` - 随机找到两段连续的序列后交换这两段序列的位置

    python first = random.randint(1, len(path)-4) second = random.randint(first+1, len(path)-3) third = random.randint(second+1, len(path)-2) dE = distance[path[first-1]][path[second+1]] + distance[path[second]][path[third+1]] + distance[path[third]][path[first]] - distance[path[first-1]][path[first]] - distance[path[second]][path[second+1]] - distance[path[third]][path[third+1]] if dE < 0: path[first:third+1] = path[second+1:third+1]+path[first:second+1] dis = dis + dE - 随机找到两段连续的序列后将后一段序列翻转并交换这两段序列的位置

    python first = random.randint(1, len(path)-4) second = random.randint(first+1, len(path)-3) third = random.randint(second+1, len(path)-2) dE = distance[path[first-1]][path[third]] + distance[path[second+1]][path[first]] + distance[path[second]][path[third+1]] - distance[path[first-1]][path[first]] - distance[path[second]][path[second+1]] - distance[path[third]][path[third+1]] if dE < 0: path[first:third+1] = path[third:second:-1]+path[first:second+1] dis = dis + dE

2. 模拟退火

大框架与前面一致,只是当新路径距离变大时以接受概率$\exp \left(-\frac{d f}{T}\right)$更新,核心代码如下:

python while(T > 0.001): for i in range(1000): # 邻域操作 first = random.randint(1, len(path)-3) second = random.randint(first+1, len(path)-2) dE = distance[path[first-1]][path[second]] + distance[path[first]][path[second+1]] - distance[path[first-1]][path[first]] - distance[path[second]][path[second+1]] # 若距离变小直接更新若距离变大则以接受概率更新 if dE < 0 or random.random() < math.exp(-dE / T): path[first:second+1] = path[second:first-1:-1] dis = dis + dE # 降温 T *= alpha

其中邻域操作与前面一致,便不再叙述

3. 遗传算法

  • 初始化种群

我原本是想直接随机生成种群的,但是课上听了同学们的分享之后知道这样会使收敛效果较差,于是采用贪心从而加快成熟速度,每个结点都选择下一个未被加入路径的最近结点

python population = [] individual = [i for i in range(numOfCity)] for r in range(int(POP_NUM * 2 / 10)): random.shuffle(individual) population.append(individual[:]) for r in range(int(POP_NUM - len(population))): start = random.randint(0, numOfCity-1) t = [] t.append(start) j = 1 while j < numOfCity: m = float_info.max i, best = 0, 0 while i < numOfCity: if (i not in t) and i != t[-1] and distance[t[-1]][i] < m: best = i m = distance[t[-1]][i] i += 1 j = j + 1 t.append(best) population.append(t[:]) random.shuffle(population) - 接下来的主函数核心部分如下:

python curGen = 0 while curGen < MAX_GEN: random.shuffle(population) # 选择 population = select(population) # 交叉 population = OX(population, numOfCity) # 变异,即局部搜索 population = localSearch(population, numOfCity) population.sort(key=lambda x: calFitness(x)) - 计算个体适应度,适应度定义为总距离的倒数

python def calFitness(individual): fitness = 0.0 for i in range(len(individual) - 1): fitness += distance[individual[i]][individual[i+1]] fitness += distance[individual[len(individual)-1]][individual[0]] return fitness - 轮盘赌选择,流程与上面介绍的步骤是一致的

python def select(population): new = [] best = float_info.max best = 0 fitness = [] fitnessTotal = 0.0 # 计算个体的适应度 for i in range(POP_NUM): fit = calFitness(population[i]) fitness.append(1 / fit) fitnessTotal += 1 / fit if (best > fit): best = fit best = i new.append(population[best]) # 计算累计概率 p = [] for i in range(POP_NUM): if i == 0: p.append(fitness[i] / fitnessTotal) else: p.append(fitness[i] / fitnessTotal + p[i-1]) # 轮盘赌选择 for i in range(POP_NUM-1): pro = random.random() for j in range(POP_NUM): if p[j] >= pro: new.append(population[j]) break return new - 次序交叉

python def OX(population, numOfCity): sub = [] for i in range(POP_NUM): if random.random() <= p1: first = random.randint(0, POP_NUM - 1) second = random.randint(0, POP_NUM - 1) while first == second: second = random.randint(0, POP_NUM - 1) start = random.randint(0, numOfCity - 2) end = random.randint(start + 1, numOfCity - 1) new1 = [] new2 = [] k = 0 for j in range(numOfCity): if j >= start and j < end: new1.append(population[first][j]) j = end else: while k < numOfCity: if population[second][k] not in population[first][start:end]: new1.append( population[second][k]) k += 1 break k += 1 k = 0 for j in range(numOfCity): if population[second][j] in population[first][start:end]: new2.append(population[second][j]) else: if k == start: k = end new2.append(population[first][k]) k += 1 sub.append(new1[:]) sub.append(new2[:]) sub.sort(key=lambda x: calFitness(x)) for i in range(len(sub)): for j in range(POP_NUM): if calFitness(sub[i]) < calFitness(population[j]): population[j] = sub[i] break return population - 局部搜索

  • 随机交换两段序列

    python def localSearch(population, numOfCity): for i in range(len(population)): if random.random() <= p2: best = population[i][:] for _ in range(100): first = random.randint(1, numOfCity - 2) second = random.randint(first + 1, numOfCity - 1) population[i][first:second] = population[i][second-1:first-1:-1] if calFitness(best) > calFitness(population[i]): best = population[i][:] population[i] = best return population - 随机找到两段连续的序列后交换这两段序列的位置

    python def localSearch(population, numOfCity): for i in range(len(population)): if random.random() <= p2: best = population[i][:] for _ in range(100): first = random.randint(1, numOfCity - 3) second = random.randint(first + 1, numOfCity - 2) third = random.randint(second + 1, numOfCity - 1) population[i][first:third] = population[i][second +1:third]+population[i][first:second+1] if calFitness(best) > calFitness(population[i]): best = population[i][:] population[i] = best return population - 随机找到两段连续的序列后将后一段序列翻转并交换这两段序列的位置

    python def localSearch(population, numOfCity): for i in range(len(population)): if random.random() <= p2: best = population[i][:] for _ in range(100): first = random.randint(1, numOfCity - 3) second = random.randint(first + 1, numOfCity - 2) third = random.randint(second + 1, numOfCity - 1) population[i][first:third] = population[i][third - 1:second:-1]+population[i][first:second+1] if calFitness(best) > calFitness(population[i]): best = population[i][:] population[i] = best return population

三、实验结果与分析

我使用了 kroA150 和 rat195 这两个数据集进行测试,对于三种方法的三种邻域操作在 kroA150 上的结果图如下所示:

分别计算误差率可得:

从上面的结果图可以得到以下结论:

  • 对于三种邻域操作,翻转一段序列的效果最好,将后一段序列翻转并与前一段交换次之
  • 对于三种算法,模拟退火是最优的,遗传算法次之,这是因为局部搜索很容易被限制在局部最优,至于遗传算法不如模拟退火的原因可能是交叉算法还不够好;但同时遗传算法的效率也是最低的

以上便是三种算法及三种邻域操作的对比。

参考文献

  • 改进的伪并行遗传算法在车间调度中的应用研究(大连交通大学·谷晓琳)
  • 基于Petri网和混合遗传算法的双资源车间调度(哈尔滨工业大学·黄跃龙)
  • 蜂群算法及其在垂直Web搜索中的应用(广州大学·李海生)
  • 生块质量与煅烧生产工艺参数间的关系模型研究(北方工业大学·王博)
  • 基于.NET的预测决策算法研究及系统实现(暨南大学·张科)
  • 改进的小生境遗传算法求解Job Shop问题(大连交通大学·程国力)
  • 基于遗传算法的高校排课系统的设计与实现(贵州大学·郭剑)
  • 生物地理学算法的研究及应用(新疆大学·罗丹)
  • 基于Petri网和混合遗传算法的双资源车间调度(哈尔滨工业大学·黄跃龙)
  • 生物地理学算法的研究及应用(新疆大学·罗丹)
  • 具有学习能力的免疫遗传算法在车间调度中的应用(大连交通大学·常征)
  • 基于改进型遗传算法的军队院校排课系统研究(南昌航空大学·岳翠翠)
  • 基于改进NSGA-Ⅱ的协同过滤推荐算法(天津工业大学·张海潮)
  • 基于车间调度问题的智能优化算法研究(浙江大学·祁建程)
  • 蚁群算法的改进与应用(扬州大学·秦玲)

本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:毕设港湾 ,原文地址:https://m.bishedaima.com/yuanma/35992.html

相关推荐

  • 新手python简单的飞机游戏

    game 一个新手做的python简单的飞机游戏 参考文献 基于Java EE的个人博客管理系统的设计和实现(内蒙古大学·闫伟光) 深度可定制的工具化爬虫系统的设计与实现(北京邮电大学·李笑语) 航空订票服务器爬虫检测技术研究(杭州电子科技大学·陈万烤) 主题爬虫关键技术研究(哈尔滨工程大学·黄正德) 机票票价预测系统设计与实现(大连理工大学·陈岩松) 深度可定制的工具化爬虫系统的设计与实现(北京邮电大学·李笑语) 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航) 基于B/S架构的酷跑社区系统的设计与实现(内蒙古大学·张晓乐) 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航) 机票票价预测系统设计与实现(大连理工大学·陈岩松) 山东航空货运业务管理系统的设计与实现(山东大学·高辉) 飞行情报资料管理信息系统设计与实现(中国地质大学(北京)·张晓琴) 山东航空货运业务管理系统的设计与实现(山东大学·高辉) 豆玩手机游戏平台的设计与实现(吉林大学·李天明) 面向高职信息技术教育的严肃游戏设计与实施(大连理工大学·王晓姝)
    2024年05月14日
    1 1 1
  • 基于python制作一个打砖块小游戏

    基于 python 制作一个打砖块小游戏 导语 想起来好久没更这个系列的文章了,周末过来补一波好了,本期我们将利用 python 制作一个打砖块小游戏
    2024年05月14日
    1 1 1
  • 基于python实现的电梯调度

    基于python实现的电梯调度 1 项目说明 1,1 项目目的 通过实现电梯调度,体会操作系统调度过程 学习特定环境下多线程编程方法 学习调度算法 1
    2024年05月14日
    5 1 3
  • 基于JSP的校园论坛BBS网站的设计与实现

    基于JSP的校园论坛BBS网站的设计与实现 1 概述 开发校园论坛系统的目的是提供一个供我校学生交流的平台,为我校学生提供交流经验,探讨问题的社区,因此
    2024年05月14日
    21 1 1
  • 基于SSM框架实现的员工信息管理系统

    1,项目简介 这是完整使用SSM框架开发的第一个项目,项目来源于北京动力节点的SSM框架整合教程,其中加入了一些自己的理解,增加了一个搜索功能的页面,这个项目总体来说对于新手是很友好的
    2024年05月14日
    2 1 1
  • 基于JSP的聊天器

    基于JSP的聊天器 1 可行性研究 1,1 技术条件方面的可行性 系统:Windows 8,1 Update 服务器环境:nodejs 0
    2024年05月14日
    7 1 1
  • 基于SpringBoot框架的在线互动学习网站

    这是一套采用Java语言,基于SpringBoot框架构建的在线教育互动平台的源代码,项目采用了SpringBoot和Vue技术栈,开发工具为Idea或Eclipse
    2024年05月23日
    5 1 3
  • 解谜类游戏之Python

    解谜类游戏 一,摘要 作者:霍禹佳,高铭星,朱子仪,梁鞍華 [摘要] 本作融合了企鹅,史诗英雄故事,解谜和游戏这四种元素,创造出一款全新的解谜类游戏,通过对故事
    2024年05月14日
    1 1 1
  • 基于Python制作愤怒的小鸟小游戏

    基于 Python 制作愤怒的小鸟小游戏 导语 小伙伴们周末愉快呀~楼主又好久没更新公众号的样子,为了避免继续被某些小伙伴吐槽,还是上来更新一波吧,既然是周末
    2024年05月14日
    6 1 2
  • 基于SpringBoot框架的网页时装购物系统

    这是一套采用Java语言开发的🔥🔥SpringBoot为核心的电商时装网站项目源代码🔥🔥,该项目运用了SpringBoot框架和Vue技术,支持在Idea或Eclipse开发环境中运行
    2024年05月23日
    10 1 2

发表回复

登录后才能评论