Resolver el problema del vendedor ambulante basado en la optimización del enjambre de partículas genéticas combinadas

Descripción del problema
Un vendedor de mercaderías quiere ir a varias ciudades para vender mercadería, el vendedor parte de una ciudad y necesita pasar por todas las ciudades antes de regresar al lugar de partida. ¿Cómo se debe elegir la ruta de viaje para que el viaje total sea el más corto?
Para el TSP de n ciudades, este artículo utiliza Python para realizar el algoritmo de enjambre de partículas híbridas para resolver el problema.

Enjambre de partículas híbridas
El proceso de operación básico del algoritmo de enjambre de partículas híbridas es el siguiente

  1. Código de inicialización: establezca el número máximo de generación de evolución T_max, genere aleatoriamente un código de población de m cromosomas
  2. Función de aptitud: para cada cromosoma, hay un valor de aptitud individual
  3. Crossover: actualice a cada individuo con el valor extremo individual del individuo y el valor extremo de grupo del grupo actual.Sólo el nuevo individuo después del cruce tiene una mejor aptitud que el individuo anterior, entonces el cambio será reemplazado.
  4. Mutación: intercambia aleatoriamente las posiciones de dos puntos en un solo cromosoma. Si el individuo mutado tiene mejor aptitud que el individuo anterior, reemplácelo.

El diagrama de flujo se muestra en la figura.

Código

Idioma: python

El primer paso es inicializar los parámetros.

import numpy as np
import matplotlib.pyplot as plt


class Hybrid_POS_TSP(object):
    def __init__(self, data, num_pop=200):
        self.num_pop = num_pop  # 群体个数
        self.data = data  # 城市坐标
        self.num = len(data)  # 城市个数

        # 群体的初始化和路径的初始化
        self.chrom = np.array([0] * self.num_pop * self.num).reshape(self.num_pop, self.num)#shape(num_pop,num)
        self.fitness = [0] * self.num_pop#一个个体一个适应度函数

        # 路径矩阵,函数matrix_dis同遗传算法
        self.matrix_distance = self.matrix_dis()

Función de distancia, agregue la clase Hybrid_POS_TSP

# 计算城市间的距离函数  n*n, 第[i,j]个元素表示城市i到j距离
    def matrix_dis(self):
        res = np.zeros((self.num, self.num))
        for i in range(self.num):
            for j in range(i + 1, self.num):
                res[i, j] = np.linalg.norm(self.data[i, :] - self.data[j, :])  # 求二阶范数 就是距离公式
                res[j, i] = res[i, j]
        return res

Genere aleatoriamente la función del grupo de inicialización, agregue la clase Hybrid_POS_TSP

 # 随机产生初始化群体函数
    def rand_chrom(self):
        rand_ch = np.array(range(self.num))  ## num 城市个数 对应染色体长度   城市=14
        for i in range(self.num_pop):  # num_pop  # 群体个数 200
            np.random.shuffle(rand_ch)  # 打乱城市染色体编码
            self.chrom[i, :] = rand_ch#.chrom 父代
            self.fitness[i] = self.comp_fit(rand_ch)

    # 计算单个染色体的路径距离值,可利用该函数更新fittness
    def comp_fit(self, one_path):
        res = 0
        for i in range(self.num - 1):
            res += self.matrix_distance[one_path[i], one_path[i + 1]]  # matrix_distance n*n, 第[i,j]个元素表示城市i到j距离
        res += self.matrix_distance[one_path[-1], one_path[0]]  # 最后一个城市 到起点距离
        return res

Función de visualización de ruta, agregue la clase Hybrid_POS_TSP

 def out_path(self, one_path):
        res = str(one_path[0] + 1) + '-->'
        for i in range(1, self.num):
            res += str(one_path[i] + 1) + '-->'
        res += str(one_path[0] + 1) + '\n'
        print(res)

Función de cruce de dos caminos: Operación cruzada de cada individuo con el valor extremo individual del individuo y el valor extremo grupal del grupo actual. Agregue el código a la clase Hybrid_POS_TSP

#两条路径的交叉函数:将每个个体与该个体的个体极值和当前群体的群体极值进行交叉操作
    def cross_1(self, path, best_path):#path为 个体最优 ,best_path为群体最优
        r1 = np.random.randint(self.num)#随机产生小于num的整数
        r2 = np.random.randint(self.num)#随机产生小于num的整数
        while r2 == r1:#如果两者相等
            r2 = np.random.randint(self.num)#重新产生r2

        left, right = min(r1, r2), max(r1, r2)#left 为(r1,r2)小者,right 为(r1,r2)大者
        cross = best_path[left:right + 1]#交叉片段为 群体最优中的(r1:r2)片段

        #下面的for 循环是为了确保 个体染色体(0:(num-(right-left+1)) 片段 不含有 cross中的元素。
        for i in range(right - left + 1):#有(r2-r1)次遍历
            for k in range(self.num):#遍历个体染色体中的每一个值
                if path[k] == cross[i]:#如果当前个体染色体元素path[k]  是cross之内
                    path[k:self.num - 1] = path[k + 1:self.num] #则修改path[k:num - 1] 片段,同时末尾补0  (也就是说把不属于cross的个体染色体元素 往前赶
                    path[-1] = 0
        path[self.num - right + left - 1:self.num] = cross#把个体染色体(num-(right-left+1):num ) 片段 和群体交叉
        return path

Función de variación: intercambia aleatoriamente las posiciones de dos puntos en un solo cromosoma. Agregue el código a la clase Hybrid_POS_TSP

    def mutation(self, path):#path 个体染色体
        r1 = np.random.randint(self.num)#随机生成小于num的整数
        r2 = np.random.randint(self.num)#随机生成小于num的整数
        while r2 == r1:#如果r1==r2
            r2 = np.random.randint(self.num)#则r2再重新生成
        path[r1], path[r2] = path[r2], path[r1]#交换片段
        return path

Función principal

#data = np.random.rand(20, 2) * 10  # 随机产生20个城市坐标
def main(data, max_n=200, num_pop=200):#迭代次数max_n200  群体个数num_pop=200
    Path_short = Hybrid_POS_TSP(data, num_pop=num_pop)  # 混合粒子群算法类
    Path_short.rand_chrom()  # 初始化种群

    # 初始化路径绘图
    fig, ax = plt.subplots()
    x = data[:, 0]
    y = data[:, 1]
    ax.scatter(x, y, linewidths=0.1)
    for i, txt in enumerate(range(1, len(data) + 1)):
        ax.annotate(txt, (x[i], y[i]))
    res0 = Path_short.chrom[0]
    x0 = x[res0]
    y0 = y[res0]
    for i in range(len(data) - 1):
        plt.quiver(x0[i], y0[i], x0[i + 1] - x0[i], y0[i + 1] - y0[i], color='r', width=0.005, angles='xy', scale=1,
                   scale_units='xy')
    plt.quiver(x0[-1], y0[-1], x0[0] - x0[-1], y0[0] - y0[-1], color='r', width=0.005, angles='xy', scale=1,
               scale_units='xy')
    plt.show()
    print('初始染色体的路程: ' + str(Path_short.fitness[0]))

    #定义6个容器 分别存放个体极值,个体染色体,群体最优极值,群体最优染色体,每一次迭代后的最优极值,每一次迭代后最优个体染色体 (容器定义的样子要和染色体个数等一致)
    # 存储个体极值的路径和距离
    best_P_chrom = Path_short.chrom.copy()# 个体极值 路径 (个体染色体)
    best_P_fit = Path_short.fitness.copy()#个体极值 距离

    min_index = np.argmin(Path_short.fitness)#最优个体的index序号

    #存储当前种群极值的路径和距离
    best_G_chrom = Path_short.chrom[min_index, :]#存储当前种群极值的路径(群体最优染色体)
    best_G_fit = Path_short.fitness[min_index]#存储当前种群极值的距离(群体最优极值)

    # 存储每一步迭代后的最优路径和距离
    best_chrom = [best_G_chrom]#当代最优个体
    best_fit = [best_G_fit]#当代最优极值

    # 复制当前群体进行交叉变异
    x_new = Path_short.chrom.copy()

    # 进入迭代 更新个体极值,个体染色体,群体最优极值,群体最优个体,存放当代最优个体,存放当代最优极值

    for i in range(max_n):#遍历迭代
        # 更新当前的个体极值 和路径 #
        for j in range(num_pop):#遍历每一个个体
            if Path_short.fitness[j] < best_P_fit[j]:#
                best_P_fit[j] = Path_short.fitness[j]#更新个体极值
                best_P_chrom[j, :] = Path_short.chrom[j, :]#更新个体极值路径

        # 更新当前种群的群体极值
        min_index = np.argmin(Path_short.fitness)
        best_G_chrom = Path_short.chrom[min_index, :]#群体极值 路径
        best_G_fit = Path_short.fitness[min_index]#群体极值

        # 添加 每一次迭代后的 当代全局最优个体和解极值
        if best_G_fit < best_fit[-1]:#best_G_fit 全局极值  best_fit每一步迭代后的最优极值
            best_fit.append(best_G_fit)#
            best_chrom.append(best_G_chrom)
        else:
            best_fit.append(best_fit[-1])
            best_chrom.append(best_chrom[-1])


        #遍历每一个个体,将个体与当代最优个体进行有条件交叉;个体有条件自我变异。条件都为(个体适应度是否更好,如果是则交叉变异

        # 将每个个体与个体极值和当前的群体极值进行交叉
        for j in range(num_pop):#遍历每一个个体     
            # 与当代极值交叉
            x_new[j, :] = Path_short.cross_1(x_new[j, :], best_G_chrom)
            fit = Path_short.comp_fit(x_new[j, :])
            if fit < Path_short.fitness[j]:
                Path_short.chrom[j, :] = x_new[j, :]
                Path_short.fitness[j] = fit
            # 变异
            x_new[j, :] = Path_short.mutation(x_new[j, :])
            fit = Path_short.comp_fit(x_new[j, :])
            if fit <= Path_short.fitness[j]:
                Path_short.chrom[j] = x_new[j, :]
                Path_short.fitness[j] = fit

        if (i + 1) % 20 == 0:
            print('第' + str(i + 1) + '步后的最短的路程: ' + str(Path_short.fitness[min_index]))
            print('第' + str(i + 1) + '步后的最优路径:')
            Path_short.out_path(Path_short.chrom[min_index, :])  # 显示每一步的最优路径

    Path_short.best_chrom = best_chrom
    Path_short.best_fit = best_fit
    #画出最优路径
    res1 = Path_short.best_chrom[-1]
    x0 = x[res1]
    y0 = y[res1]
    for i in range(len(data) - 1):
        plt.quiver(x0[i], y0[i], x0[i + 1] - x0[i], y0[i + 1] - y0[i], color='r', width=0.005, angles='xy', scale=1,
                   scale_units='xy')
    plt.quiver(x0[-1], y0[-1], x0[0] - x0[-1], y0[0] - y0[-1], color='r', width=0.005, angles='xy', scale=1,
               scale_units='xy')
    plt.show()



    return Path_short  # 返回结果类

if __name__ == '__main__':
    # 路径坐标
    np.random.seed(10)
    data = np.random.rand(20, 2) * 10  # 随机产生20个城市坐标
    main(data,)

Resultado:
ruta de inicio

Ruta de resultado

Inserte la descripción de la imagen aquí
Autor: Eléctrico Yudeng Wu. Escribir no es fácil, como antes de irse.
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/kobeyu652453/article/details/114830751
Recomendado
Clasificación