基于粒子群算法(PSO)的TSP(Python实现)

        本篇文章是博主在最化优学习、人工智能等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在最优化算法:

       最优化算法(5)---《基于粒子群算法(PSO)的TSP(Python实现)》

基于粒子群算法(PSO)的TSP(Python实现)

目录

基于粒子群算法(PSO)的TSP(Python实现)

1.项目介绍

PSO算法介绍:

算法的核心思想包括以下几个方面:

PSO算法求解TSP的基本思路包括:

2.程序代码

3.运行结果


1.项目介绍

     基于粒子群算法(Particle Swarm Optimization, PSO)的TSP(Traveling Salesman Problem,旅行商问题),求解方法源自对集体智慧的模拟,通过模拟鸟群在搜索食物时的协作行为,不断调整每个“粒子”的位置和速度,以寻找全局最优解。在TSP问题中,粒子代表可能的路径解,通过不断更新粒子的位置,寻找一条最短的路径来访问所有城市。

PSO算法介绍:

        PSO算法的核心思想是模拟鸟群的搜索行为,每个粒子代表一个潜在的解,在搜索空间中移动,并与其他粒子共同寻找最优解。在搜索过程中,粒子会记忆历史搜索中的最佳位置,并根据全局最优和局部最优位置进行位置的调整,从而促进了全局搜索和局部优化之间的平衡。这种协作机制使得PSO算法在处理TSP等组合优化问题时具有很好的全局搜索能力和收敛性。

        实现PSO算法求解TSP问题的Python代码通常包括粒子位置更新、适应度评估、全局最优和局部最优更新等关键步骤。Python作为一种简洁而强大的编程语言,提供了丰富的科学计算库和可视化工具,非常适合实现PSO算法。通过合理的数据结构设计和算法实现,可以很好地完成TSP问题的求解,并将结果直观地展示出来。

        值得注意的是,PSO算法中的参数设置对算法的性能影响较大,如惯性权重、加速系数等参数需要合理设置以平衡全局探索和局部开发。此外,PSO算法也面临着早熟收敛和参数选择的问题,在实际使用中需要谨慎调整参数以获得更好的结果。

算法的核心思想包括以下几个方面:

  1. 粒子位置更新:每个粒子代表一个潜在的解,其位置表示TSP路径上城市的访问顺序,根据当前速度和位置信息更新粒子的位置
  2. 全局最优和局部最优:粒子会记忆历史搜索中的最佳位置,同时借鉴全局最优位置,这种协作机制促进了全局搜索和局部优化之间的平衡
  3. 适应度评估:根据TSP路径长度等指标计算每个粒子的适应度,并据此更新全局最优和局部最优解
  4. 参数设置:PSO算法中需要合理设置惯性权重、加速系数等参数来平衡全局探索和局部开发

PSO算法求解TSP的基本思路包括:

  • 初始化:初始化粒子群的位置和速度,记录全局最优和局部最优
  • 粒子位置更新:根据速度和位置信息更新粒子的位置
  • 适应度评估:计算每个粒子的适应度,并更新全局最优和局部最优解
  • 最优路径更新:记录全局最优路径
  • 终止条件:达到预设的迭代次数或满足特定条件时结束搜索,返回最优路径

        通过利用PSO算法求解TSP问题,可以有效地寻找到较为优秀的旅行路线,尽管无法保证找到全局最优解,但通常能获得接近最优解的结果。粒子群算法在处理TSP等组合优化问题上具有很好的全局搜索能力和快速收敛性。


2.程序代码

""""
题目:基于粒子群算法的TSP
姓名:Rainbook
最终修改时间:2024.1.15
"""
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import time

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 使用微软雅黑字体
plt.rcParams['axes.unicode_minus'] = False  # 处理负号显示异常


# 计算距离矩阵
def clac_distance(X, Y):
    """
    计算两个城市之间的欧氏距离,二范数
    :param X: 城市X的坐标.np.array数组
    :param Y: 城市Y的坐标.np.array数组
    :return:
    """
    distance_matrix = np.zeros((city_num, city_num))
    for i in range(city_num):
        for j in range(city_num):
            if i == j:
                continue

            distance = np.sqrt((X[i] - X[j]) ** 2 + (Y[i] - Y[j]) ** 2)
            distance_matrix[i][j] = distance

    return distance_matrix


# 定义总距离(路程即适应度值)
def fitness_func(distance_matrix, x_i):
    """
    适应度函数
    :param distance_matrix: 城市距离矩阵
    :param x_i: PSO的一个解(路径序列)
    :return:
    """
    total_distance = 0
    for i in range(1, city_num):
        start_city = x_i[i - 1]
        end_city = x_i[i]
        total_distance += distance_matrix[start_city][end_city]
    total_distance += distance_matrix[x_i[-1]][x_i[0]]  # 从最后的城市返回出发的城市

    return total_distance


# 定义速度更新函数
def get_ss(x_best, x_i, r):
    """
    计算交换序列,即x2结果交换序列ss得到x1,对应PSO速度更新公式中的 r1(pbest-xi) 和 r2(gbest-xi)
    :param x_best: pbest or gbest
    :param x_i: 粒子当前的解
    :param r: 随机因子
    :return:
    """
    velocity_ss = []
    for i in range(len(x_i)):
        if x_i[i] != x_best[i]:
            j = np.where(x_i == x_best[i])[0][0]
            so = (i, j, r)  # 得到交换子
            velocity_ss.append(so)
            x_i[i], x_i[j] = x_i[j], x_i[i]  # 执行交换操作

    return velocity_ss


# 定义位置更新函数
def do_ss(x_i, ss):
    """
    执行交换操作
    :param x_i:
    :param ss: 由交换子组成的交换序列
    :return:
    """
    for i, j, r in ss:
        rand = np.random.random()
        if rand <= r:
            x_i[i], x_i[j] = x_i[j], x_i[i]
    return x_i


def draw(best):
    result_x = [0 for col in range(city_num + 1)]
    result_y = [0 for col in range(city_num + 1)]

    for i in range(city_num):
        result_x[i] = city_x[best[i]]
        result_y[i] = city_y[best[i]]
    result_x[city_num] = result_x[0]
    result_y[city_num] = result_y[0]
    plt.xlim(0, 5)  # 限定横轴的范围
    plt.ylim(0, 4)  # 限定纵轴的范围
    plt.plot(result_x, result_y, marker='>', mec='r', mfc='w', label=u'路线')
    plt.legend()  # 让图例生效
    plt.margins(0)
    plt.subplots_adjust(bottom=0.15)
    for i in range(len(best)):
        plt.text(result_x[i] + 0.05, result_y[i] + 0.05, str(best[i] + 1), color='red')
    plt.xlabel('横坐标')
    plt.ylabel('纵坐标')
    plt.title('轨迹图')
    plt.show()


def print_route(route):
    result_cur_best = []
    for i in route:
        result_cur_best += [i]
    for i in range(len(result_cur_best)):
        result_cur_best[i] += 1
    result_path = result_cur_best
    result_path.append(result_path[0])
    return result_path


if __name__ == "__main__":
    # 参数定义
    CityCount = 30  # 定义城市个数
    # uniform()生成10个二维数组,数值范围是0到2000
    city_x = np.random.uniform(0, 2000, (1, CityCount))
    city_x = city_x[0, :].tolist()
    city_y = np.random.uniform(0, 2000, (1, CityCount))
    city_y = city_y[0, :].tolist()
    city_num = CityCount

    size = 500  # 粒子数量
    r1 = 0.7  # 个体学习因子
    r2 = 0.8  # 社会学习因子
    iter_max_num = 500  # 迭代次数
    fitness_value_lst = []

    distance_matrix = clac_distance(city_x, city_y)

    # 初始化种群各个粒子的位置,作为个体的历史最优pbest
    pbest_init = np.zeros((size, city_num), dtype=np.int64)
    for i in range(size):
        pbest_init[i] = np.random.choice(list(range(city_num)), size=city_num, replace=False)

    # 计算每个粒子对应的适应度
    pbest = pbest_init
    pbest_fitness = np.zeros((size, 1))
    for i in range(size):
        pbest_fitness[i] = fitness_func(distance_matrix, x_i=pbest_init[i])

    # 计算全局适应度和对应的gbest
    gbest = pbest_init[pbest_fitness.argmin()]
    gbest_fitness = pbest_fitness.min()

    # 记录算法迭代效果
    fitness_value_lst.append(gbest_fitness)

    # 迭代过程
    for i in range(iter_max_num):
        # 控制迭代次数
        for j in range(size):
            # 遍历每个粒子
            pbest_i = pbest[j].copy()
            x_i = pbest_init[j].copy()

            # 计算交换序列,即 v = r1(pbest-xi) + r2(gbest-xi)
            ss1 = get_ss(pbest_i, x_i, r1)
            ss2 = get_ss(gbest, x_i, r2)
            ss = ss1 + ss2
            x_i = do_ss(x_i, ss)

            fitness_new = fitness_func(distance_matrix, x_i)
            fitness_old = pbest_fitness[j]
            if fitness_new < fitness_old:
                pbest_fitness[j] = fitness_new
                pbest[j] = x_i

            gbest_fitness_new = pbest_fitness.min()
            gbest_new = pbest[pbest_fitness.argmin()]
            if gbest_fitness_new < gbest_fitness:
                gbest_fitness = gbest_fitness_new
                gbest = gbest_new
        fitness_value_lst.append(gbest_fitness)
        print("第%d迭代,最优值为:%s" % (i, gbest_fitness))

    # 输出迭代结果
    print("===最优路线:", print_route(gbest))
    print("===最优值:", gbest_fitness)

    # 绘图
    # 迭代完成后最优路线的示意图
    X = city_x
    Y = city_y
    x = []
    y = []
    for city in gbest:
        x.append(X[city])
        y.append(Y[city])
    x.append(X[gbest[0]])
    y.append(Y[gbest[0]])

    plt.figure(1)
    for j in range(len(gbest)):
        plt.quiver(x[j], y[j], x[j + 1] - x[j], y[j + 1] - y[j], color='r', width=0.005, angles='xy', scale=1,
                   scale_units='xy')
    plt.quiver(x[-1], y[-1], x[0] - x[-1], y[0] - y[-1], color='r', width=0.005, angles='xy', scale=1,
               scale_units='xy')
    plt.title("基于蚁群算法的TSP")

    plt.figure(2)
    plt.plot(fitness_value_lst)
    plt.title('优化过程')
    plt.ylabel('最优值')
    plt.xlabel('迭代次数')
    plt.show()


3.运行结果


        参考资料来源:CSDN、百度搜索、维基百科等

        文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者关注VX公众号:Rain21321,联系作者。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不去幼儿园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值