Tabu Search — 温和介绍

Tabu Search — 温和介绍

目录

Tabu Search — 温和介绍

一、说明

二、什么是禁忌搜索以及我可以在哪里使用它?

三、禁忌搜索原则

四、短期记忆和积极搜索:

五、举例时间 

六、结论:

七、参考:


一、说明

最近,我参加了 Corsera 上的离散优化课程。我试图解决的问题之一是旅行商问题,即著名的 NP-Hard 优化问题。该课程讲解了如何使用几种算法解决几个实际问题,其中一种算法是禁忌搜索。

今天,在这篇文章中,我将解释该算法并使用 Python 实现它来解决旅行商问题 TSP。

二、什么是禁忌搜索以及我可以在哪里使用它?

禁忌搜索是一种用于解决优化问题的元启发式程序,旨在指导其他方法摆脱局部最小值的陷阱。禁忌搜索用于为各种经典和实际问题寻找最佳和接近最佳的解决方案。从调度到电信,从字符识别到神经网络。为了避免陷入局部最小值,它使用内存,以便能够记住已经利用的动作和解决方案。此外,它还使用记忆功能来允许搜索策略,例如强化和多样化(稍后将对其进行解释)。

禁忌搜索可用于指导其他过程,该过程使用一组动作将一个解决方案转换为另一个解决方案,并为衡量这些动作的吸引力提供指导。动作的示例是在两个任务之间交换,改变变量的值(增加、减少)。

Tabu Search 应用的部分列表:

  1. 员工排班
  2. 最大可满足性问题
  3. 字符识别
  4. 空间规划与建筑设计
  5. 电信路径分配
  6. 概率逻辑问题
  7. 神经网络模式识别
  8. 机器调度
  9. 旅行商问题
  10. 图形着色

三、禁忌搜索原则

Tabu Search基于三个主要概念:

  1. 使用基于灵活属性的记忆结构,可以比严格的记忆结构或无记忆系统更彻底地利用评估标准和历史搜索信息。
  2. 禁忌搜索中根据特定标准评估移动的机制
  3. 使用从短期到长期的不同时间跨度的记忆功能来实施强化策略——专注于特定区域,再到多样化——推动在新区域的搜索。

四、短期记忆和积极搜索:

        禁忌搜索中的短期记忆可以表示为一种积极的利用,旨在使基本移动成为可能。通过列出可以从当前解决方案中得出新解决方案的候选移动列表。

        禁忌搜索提供了防止重复某些动作的限制。通过将这些动作视为禁忌(禁忌)……(啊,这就是它被称为禁忌搜索的原因!)。禁忌搜索旨在防止循环回到局部最小值,并广泛地引入搜索以遵循新的轨迹。

        但是.. Tabu 如何确定最佳候选人?很简单!使用目标函数!..事情还是不清楚?!别担心,在看到下面的框图之前,我也不明白:

        禁忌搜索短期记忆组件——取自[1]

选择最佳候选人——取自[1]

五、举例时间 

        ِ禁忌搜索的一个简单例子是最小成本生成树问题,其中包括防止某些边出现的约束。该问题可以用五个节点表示,因此生成树由四个边组成,每个边都有一个成本,如下图所示:

生成树问题

在这个问题中,我们需要最小化节点相互连接的成本。这里每条边都用 xi 表示,其中 i=[0..7],xi 可以取 0 或 1(0 表示边不存在)。每条边都有成本。例如,这里初始解决方案的成本是 6+2+8+0 = 16(相当不错吧)。

但是等等..不要忘记问题的另一部分,有些边是禁止出现..所以让我们在这里加上一些限制:

x1 + x2 + x6≤1

x1≤x3

当我们违反这些限制时,我们会对每个违反单位处以 50 的惩罚。因此,在上图中,我们有 2 次违反,因此惩罚为 100。该生成树的总成本为116 :)

我们需要找到一种成本低且不违反上述约束的解决方案。要应用禁忌搜索,我们需要应用交换变换,即删除一条边并添加另一条边以转换为另一个解决方案。

当我们选择添加一条边时,我们必须以不产生循环的方式删除另一条边。可接受的移动是考虑到违规惩罚成本而具有最低成本的移动。

此处的禁忌限制定义为我们定义为禁忌状态的添加边。这使得被选为禁忌的边只要是禁忌就不会从树中删除。在示例中,我们只允许两条边是禁忌。这意味着任何添加的边在两次迭代中仍然是禁忌。

此处的期望标准是,如果生成的树比迄今为止生成的最佳树更好,则覆盖禁忌状态。我们现在将运行该算法并讨论每次迭代。迭代如下图 1 所示:

迭代 1:从迭代 1 开始,我们可以采取的最佳措施是添加 x3 并删除 x1,这样既不违反约束,又能达到最佳效果。这会将惩罚从 100 减少到 0。同时将成本从 16 增加到 28。X3 现在被视为禁忌。

迭代 2:现在根据禁忌状态规则,我们将 x3 设为禁忌。因此我们不能删除 x3。从剩余的选项中,最佳选择是添加 x7 并删除 x6。然后将 x7 设为禁忌。所选的举动产生的成本比前一个更糟糕。

现在我们有 x3,x7 被视为禁忌。如果我们想采取任何行动,我们都会使成本变得更糟。所以我们处于一种成本很高的状态,我们无法采取任何其他行动,这被称为局部最小值。

迭代 3:现在,由于我们达到了局部最小值,我们可以通过添加 x2 并删除 x3 来覆盖禁忌状态。此举通过生成具有更佳成本的树来满足期望标准,因此我们采取此举。

迭代 4:X2、X7 现在是禁忌。算法将继续添加 x3 并删除 X5。X3 和 X2 现在是禁忌

执行:

我在 Python 中分叉了一个禁忌搜索的实现,并对其进行了改进,以解决旅行商问题,请随意使用和修改代码:

"""
This implementation for tabu search is modified from:
https://www.techconductor.com/algorithms/python/Search/Tabu_Search.php
Reference:
https://www.researchgate.net/publication/242527226_Tabu_Search_A_Tutorial
"""
import copy
import mathdef distance(point1, point2):return math.sqrt((point1.x - point2.x)**2 + (point1.y - point2.y)**2)def generate_neighbours(points):"""This function geenrates a 2D distance matrix between all pointsParameters----------points : typeDescription of parameter `points`.Returns-------typeDescription of returned object."""dict_of_neighbours = {}for i in range(len(points)):for j in range(i+1, len(points)):if i not in dict_of_neighbours:dict_of_neighbours[i] = {}dict_of_neighbours[i][j]= distance(points[i], points[j])else:dict_of_neighbours[i][j] = distance(points[i], points[j])# dict_of_neighbours[i] = sorted(dict_of_neighbours[i].items(), key=lambda kv: kv[1])if j not in dict_of_neighbours:dict_of_neighbours[j] = {}dict_of_neighbours[j][i] = distance(points[j], points[i])else:dict_of_neighbours[j][i] = distance(points[j], points[i])# dict_of_neighbours[i] = sorted(dict_of_neighbours[i].items(), key=lambda kv: kv[1])return dict_of_neighboursdef generate_first_solution(nodes, dict_of_neighbours):start_node = nodes[0]end_node = start_nodefirst_solution = []distance = 0visiting = start_nodepre_node = Nonewhile visiting not in first_solution:_tmp = copy.deepcopy(dict_of_neighbours[visiting])_tmp.pop(pre_node, None)next_node = min(_tmp.items(), key=lambda x: x[1])[0]distance += dict_of_neighbours[visiting][next_node]first_solution.append(visiting)pre_node = visitingvisiting = next_nodefirst_solution.append(nodes[0])distance += dict_of_neighbours[pre_node][end_node]return first_solution, distancedef find_neighborhood(solution, dict_of_neighbours, n_opt=1):neighborhood_of_solution = []for n in solution[1:-n_opt]:idx1 = []n_index = solution.index(n)for i in range(n_opt):idx1.append(n_index+i)for kn in solution[1:-n_opt]:idx2 = []kn_index = solution.index(kn)for i in range(n_opt):idx2.append(kn_index+i)if bool(set(solution[idx1[0]:(idx1[-1]+1)]) &set(solution[idx2[0]:(idx2[-1]+1)])):continue_tmp = copy.deepcopy(solution)for i in range(n_opt):_tmp[idx1[i]] = solution[idx2[i]]_tmp[idx2[i]] = solution[idx1[i]]distance = 0for k in _tmp[:-1]:next_node = _tmp[_tmp.index(k) + 1]distance = distance + dict_of_neighbours[k][next_node]_tmp.append(distance)if _tmp not in neighborhood_of_solution:neighborhood_of_solution.append(_tmp)indexOfLastItemInTheList = len(neighborhood_of_solution[0]) - 1neighborhood_of_solution.sort(key=lambda x: x[indexOfLastItemInTheList])return neighborhood_of_solutiondef tabu_search(first_solution, distance_of_first_solution, dict_of_neighbours, iters, size, n_opt=1):count = 1solution = first_solutiontabu_list = list()best_cost = distance_of_first_solutionbest_solution_ever = solutionwhile count <= iters:neighborhood = find_neighborhood(solution, dict_of_neighbours, n_opt=n_opt)index_of_best_solution = 0best_solution = neighborhood[index_of_best_solution]best_cost_index = len(best_solution) - 1found = Falsewhile found is False:i = 0first_exchange_node, second_exchange_node = [], []n_opt_counter = 0while i < len(best_solution):if best_solution[i] != solution[i]:first_exchange_node.append(best_solution[i])second_exchange_node.append(solution[i])n_opt_counter += 1if n_opt_counter == n_opt:breaki = i + 1exchange = first_exchange_node + second_exchange_nodeif first_exchange_node + second_exchange_node not in tabu_list and second_exchange_node + first_exchange_node not in tabu_list:tabu_list.append(exchange)found = Truesolution = best_solution[:-1]cost = neighborhood[index_of_best_solution][best_cost_index]if cost < best_cost:best_cost = costbest_solution_ever = solutionelif index_of_best_solution < len(neighborhood):best_solution = neighborhood[index_of_best_solution]index_of_best_solution = index_of_best_solution + 1while len(tabu_list) > size:tabu_list.pop(0)count = count + 1best_solution_ever.pop(-1)return best_solution_ever, best_cost

六、结论:

禁忌搜索是一种元启发式搜索算法,利用短期记忆的思想来避免陷入局部最小值。它已用于许多应用,其中之一就是旅行商问题。谈到 TSP,值得一提的是,解决它的最佳算法是引导局部搜索算法。

七、参考:

我使用以下参考资料作为本文所写的主要信息来源(这确实是禁忌搜索的最佳资源:

  1. https://www.researchgate.net/publication/242527226_Tabu_Search_A_Tutorial
  2. https://en.wikipedia.org/wiki/Tabu_search
  3. http://www.cleveralgorithms.com/nature-inspired/stochastic/tabu_search.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/42404.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【INTEL(ALTERA)】Nios® II/f 处理器可能会误清除处理器中断启用位

目录 说明 解决方法 说明 由于Nios II处理器出现问题&#xff0c;当作为具有数据紧密耦合内存 &#xff08;DTCM&#xff09; 的 Nios II/f 实施时&#xff0c;可能会有一个特定的指令序列可能导致状态寄存器中的处理器中断启用 &#xff08;PIE&#xff09; 位在进入中断处…

在DevEco运行typeScript代码,全网详细解决执行Set-ExecutionPolicy RemoteSigned报出的错

目录 基本思路 网络推荐 本人实践 如下操作,报错: 基本思路 //在DevEco运行typeScript代码 /** * 1.保证node -v出现版本,若没有,配置环境变量(此电脑-属性-高级系统变量配置-path-粘贴路径);DevEco在local.properties中可看到当前nodejs的路径 * 2.npm install …

海外仓一件代发功能自动化:海外仓WMS系统配置方法

根据数据显示&#xff0c;2014-2019年短短几年之间&#xff0c;跨境电商销售总额增长了160%以上。这为跨境电商商家和海外仓&#xff0c;国际物流等服务端企业都提供了巨大的发展机遇。 然而&#xff0c;作为海外仓&#xff0c;要想服务好跨境电商&#xff0c;仓库作业的每一个…

C++之break / continue陈述九州地址QA98嚸CC语言

break陈述 关键字 break 用于跳出 switch 陈述或跳出回圈。 以下程式示范switch陈述中使用break #include <iostream>int main() {int data 0;switch (data) {case 0:std::cout << "0" << std::endl;case 1: case 2:std::cout << "…

车载测试之-CANoe创建仿真工程

在现代汽车工业中&#xff0c;车载测试是确保车辆电子系统可靠性和功能性的关键环节。而使用CANoe创建仿真工程&#xff0c;不仅能够模拟真实的车辆环境&#xff0c;还能大大提升测试效率和准确性。那么&#xff0c;CANoe是如何实现这些的呢&#xff1f; 车载测试中&#xff0…

06:C语言数组

C语言数组 1、怎么定义数组2、怎么使用数组&#xff1f;3、不同数据类型的数组4、sizeof运算符5、字符数组 数组就是数组成一个组&#xff0c;数就是一个特定 数据类型相同的变量&#xff0c;组就是说好多数放在了一起。 1、怎么定义数组 int a[5] {1&#xff0c;2&#xff…

刷题之合并两个有序数组(leetcode)

因为换了手机号码&#xff0c;之前leetcode的账号登不上去了&#xff0c;正好太久不刷题&#xff0c;很多思路都没了&#xff0c;所以重新开始刷leetcode&#xff01; 这道题很简单&#xff0c;指针模拟一下&#xff0c;从后往前考虑&#xff0c;先看最大值。 class Solution…

【大语言模型系列之Transformer】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

PLC电源模块

PM电源模块 为CPU信号模块及 其他的扩展设备、其他用电设备&#xff08;如传感器&#xff09;提供工作供电 接线和开关 状态显示 灯的闪烁示意看手册 PS电源模块 为CPU信号模块及其他的扩展设备提供工作供电。PS(System Power Supply) 外形与PM电源模块类似&#xff0c;状…

洛谷 P1491 集合位置

题意 给定一张 n n n 点 m m m 边的无向图&#xff0c;第 i i i 个点坐标为 ( x i , y i ) (x_i,y_i) (xi​,yi​)&#xff0c;求 1 → n 1 \to n 1→n 的非严格次短路&#xff08;不允许重复经过点和边&#xff09;。 思路 我们采用删边的思想&#xff0c;先跑一遍最短…

常用的MRI分析软件

MRI&#xff08;磁共振成像&#xff09;分析软件种类繁多&#xff0c;涵盖了从基础图像处理到高级数据分析的各个方面。这些软件广泛应用于临床诊断、研究和教育等领域。以下是一些常用的MRI分析软件&#xff1a; 开源软件 商用软件 特殊用途软件 在线工具和云平台 这些软件各…

仓颉编程语言

仓颉编程语言 1、仓颉编程语言官网文档 1、仓颉编程语言官网文档 -- 华为技术有限公司-编译器与编程语言实验室仓颉语言团队仓颉 仓颉编程语言是一款面向全场景智能的新一代编程语言&#xff0c;主打原生智能化、天生全场景、高性能、强安全。融入鸿蒙生态&#xff0c;为开发者…

MATLAB制作一个简单的函数绘制APP

制作一个函数绘制APP&#xff0c;输入函数以及左右端点&#xff0c;绘制出函数图像。 编写回调函数&#xff1a; 结果&#xff1a;

图片高效管理神器,随机高度切割,一键生成灰色图片,个性化处理随心所欲

在数字化时代&#xff0c;图片已成为我们生活和工作中不可或缺的一部分。然而&#xff0c;面对海量的图片资源&#xff0c;如何高效管理、快速处理&#xff0c;成为了许多人头疼的问题。今天&#xff0c;我们为您带来了一款全新的图片高效管理神器_——首助编辑高手&#xff0c…

FastApi+WebSocket 解析

FastAPI 比较简单&#xff0c;就是加一个路由装饰器就可以运行函数了&#xff0c;一般来说是结合async来进行异步编程&#xff0c;同时结合websocket来使用。 目录 特点运行Websocket进阶 特点 FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0…

Nginx 报错问题汇总

目录 一、nginx: [emerg] invalid number of arguments in "include" directive in C:\Program Files\nginx-1.15.4/conf/nginx.conf:61 总结&#xff1a; 二、nginx: [error] OpenEvent("Global\ngx_reload_2152") failed (5: Access is denied) 解决…

51-3 内网信息收集 - 获取RDP密码信息(没有实验成功)

获取常见应用软件凭据 注意: %USERPROFILE% 是环境变量。在使用系统权限时,可以将 %USERPROFILE% 替换为绝对路径,或使用其他用户的令牌进行操作。 获取 RDP 保存的凭据(远程桌面) 为了避免每次连接服务器都进行身份验证,经常使用 RDP 远程桌面连接远程服务器的用户可能…

【bazel】 一文读懂Starlark

Starlark 的语言编码 当我们编写工作区和构建文件时&#xff0c;我们使用一种名为 Starlark 的语言进行编码&#xff0c;它是 Python 的一种自定义变体。现在&#xff0c;对于所有 Python 开发人员来说&#xff0c;请保持您的敬意。Starlark 是 Python 的一种变体 - 即该语言的…

LeetCode436:寻找右区间

题目链接&#xff1a;436. 寻找右区间 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> findRightInterval(vector<vector<int>>& intervals) {vector<pair<int, int>> startIntervals;int n intervals.size…

H5小游戏开发,广告游戏开发制作

以下是一个 H5 小游戏开发的基本步骤和流程&#xff1a; 需求分析 确定游戏的类型&#xff0c;如益智类、动作类、冒险类等。明确游戏的目标、玩法规则、难度级别、关卡设计等。 技术选型 选择开发框架和工具&#xff0c;常用的 H5 游戏开发框架有 Phaser、CreateJS 等。确定使…