离散免疫算法求解旅行商问题(源码实现)

旅行商问题
    旅行商问题(TSP 问题)。假设有一个旅行商人要拜访全国31个省会城市,他需要选择所要走的路径,路径的限制是每个城市只能拜访-一次, 而且最后要回到原来出发的城市。路径的选择要求是:所选路径的路程为所有路径之中的最小值。

免疫算法原理
     见链接:
万字长文了解免疫算法原理 及求解复杂约束问题(源码实现)

二进制编码
免疫算法(二进制)算例(源码实现)

MATLAB版求解
注意事项:由于旅行商问题中,各个个体不存在相同个体,所以无需计算浓度。

%%%%%%%%%%%%%%%%%%%%%%%免疫算法求解决TSP问题%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%初始化%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all;                        %清除所有变量
close all;                        %清图
clc;                              %清屏
C=[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;...
    3238 1229;4196 1044;4312  790;4386  570;3007 1970;2562 1756;...
    2788 1491;2381 1676;1332  695;3715 1678;3918 2179;4061 2370;...
    3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2376;...
    3394 2643;3439 3201;2935 3240;3140 3550;2545 2357;2778 2826;...
    2370 2975];                  %31个省会城市坐标
N=size(C,1);                     %TSP问题的规模,即城市数目
D=zeros(N);                      %任意两个城市距离间隔矩阵
%%%%%%%%%%%%%%%%%%%%%求任意两个城市距离间隔矩阵%%%%%%%%%%%%%%%%%%%%%
for i=1:N
    for j=1:N
        D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5;
    end
end
NP=200;                           %免疫个体数目
G=1000;                           %最大免疫代数
f=zeros(N,NP);                    %用于存储种群
for i=1:NP
    f(:,i)=randperm(N);           %随机生成初始种群
end
len=zeros(NP,1);                  %存储路径长度
for i=1:NP
    len(i)=func(D,f(:,i),N);     %计算路径长度
end
[Sortlen,Index]=sort(len);
Sortf=f(:,Index);                 %种群个体排序
gen=0;                            %免疫代数
Ncl=10;                            %克隆个数
%%%%%%%%%%%%%%%%%%%%%%%%%%%免疫循环%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while gen<G
    for i=1:NP/2
        %%%%%%%%%%%%选激励度前NP/2个体进行免疫操作%%%%%%%%%%%%%%%
        a=Sortf(:,i);
        Ca=repmat(a,1,Ncl);
        for j=1:Ncl
            p1=floor(1+N*rand());
            p2=floor(1+N*rand());
            while p1==p2
                p1=floor(1+N*rand());
                p2=floor(1+N*rand());
            end
            tmp=Ca(p1,j);
            Ca(p1,j)=Ca(p2,j);
            Ca(p2,j)=tmp;
        end
        Ca(:,1)=Sortf(:,i);            %保留克隆源个体
        %%%%%%%%%%%%克隆抑制,保留亲和度最高的个体%%%%%%%%%%%%%%
        for j=1:Ncl
            Calen(j)=func(D,Ca(:,j),N);
        end
        [SortCalen,Index]=sort(Calen);
        SortCa=Ca(:,Index); 
        af(:,i)=SortCa(:,1);
        alen(i)=SortCalen(1);
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%种群刷新%%%%%%%%%%%%%%%%%%%%%%%%%%
    for i=1:NP/2
        bf(:,i)=randperm(N);          %随机生成初始种群
        blen(i)=func(D,bf(:,i),N);   %计算路径长度
    end  
    %%%%%%%%%%%%%%%%%%%%免疫种群与新种群合并%%%%%%%%%%%%%%%%%%%%%
    f=[af,bf];
    len=[alen,blen];
    [Sortlen,Index]=sort(len);
    Sortf=f(:,Index);
    gen=gen+1;
    trace(gen)=Sortlen(1);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%输出优化结果%%%%%%%%%%%%%%%%%%%%%%%%%%%
Bestf=Sortf(:,1);                 %最优变量
Bestlen=trace(end);               %最优值
figure
for i=1:N-1
    plot([C(Bestf(i),1),C(Bestf(i+1),1)],...
        [C(Bestf(i),2),C(Bestf(i+1),2)],'bo-');
    hold on;
end
plot([C(Bestf(N),1),C(Bestf(1),1)],...
    [C(Bestf(N),2),C(Bestf(1),2)],'ro-');
title(['优化最短距离:',num2str(trace(end))]);
figure,plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('亲和度进化曲线')

 %%%%%%%%%%%%%%%%%%%%%%%%%%%%计算路线总长度%%%%%%%%%%%%%%%%%%%%%%%%
 function len=func(D,f,N)
 len=D(f(N),f(1));
 for i=1:(N-1)
     len=len+D(f(i),f(i+1));
 end
 end

python版求解


import numpy as np
import pandas as pd
from tqdm import tqdm#进度条设置
import matplotlib.pyplot as plt
from pylab import *
import matplotlib; matplotlib.use('TkAgg')
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

city_num = 31  # 城市的数量
#############1.数据集 城市坐标
C=[1304 ,2312,3639 ,1315,4177 ,2244,3712 ,1399,3488, 1535,3326, 1556,
    3238 ,1229,4196 ,1044,4312,790,4386,570,3007,1970,2562 ,1756,
    2788, 1491,2381 ,1676,1332,695,3715 ,1678,3918,2179,4061,2370,
    3780, 2212,3676, 2578,4029,2838,4263,2931,3429,1908,3507,2376,
    3394 ,2643,3439,3201,2935,3240,3140,3550,2545,2357,2778,2826,
    2370 ,2975]                 #31个省会城市坐标
C=np.array(C).reshape(-1,2)#shape=(31, 2)



###############相关函数:距离和亲和度函数(路程) 路径画图函数################

####.函数:计算城市之间的距离
def calculate_distance(X, Y):
    """
    计算城市两辆之间的欧式距离,结果用numpy矩阵存储
    :param X: 城市的X坐标,np.array数组
    :param Y: 城市的Y坐标,np.array数组
    """
    distance_matrix = np.zeros((city_num, city_num))
    for i in range(city_num):
        for j in range(city_num):
            if i == j:
                continue
            dis = np.sqrt((X[i] - X[j]) ** 2 + (Y[i] - Y[j]) ** 2)  # 欧式距离计算
            distance_matrix[i][j] = dis
    return distance_matrix


##适应度函数 计算总距离
def fitness_func(distance_matrix, xi):
    """
    适应度函数,计算目标函数值.
    :param distance: 城市的距离矩阵
    :param xi: PSO的一个解
    :return: 目标函数值,即总距离
    """
    total_distance = 0
    for i in range(1, city_num):
        start = xi[i - 1]
        end = xi[i]
        total_distance += distance_matrix[start][end]
    total_distance += distance_matrix[end][xi[0]]  # 从最后一个城市回到出发城市
    return total_distance


#路径画图
def plot_tsp(gbest):
    """绘制最优解的图形"""
    X=D[:,0]#城市坐标的X轴
    Y=D[:,1]#城市坐标的Y轴
    plt.scatter(X, Y, color='r')
    for i in range(1, city_num):
        start_x, start_y = X[gbest[i - 1]], Y[gbest[i - 1]]
        end_x, end_y = X[gbest[i]], Y[gbest[i]]
        plt.plot([start_x, end_x], [start_y, end_y], marker='>',alpha=0.8)
    start_x, start_y = X[gbest[0]], Y[gbest[0]]
    plt.plot([start_x, end_x], [start_y, end_y], color='b', alpha=0.8)
    plt.show()


#############免疫算法相关函数###########

#免疫操作函数:克隆、变异、变异抑制
def variation(Sortf):
    """
      param Sortf:按亲和度大小排序后的群体
      return :af 经过克隆、变异、变异抑制后的群体

      #变异原理:交换个体中两个元素的位置
    """
    Ncl = 10  # 克隆个数
    af = np.zeros((np.int(NP / 2), city_num),dtype=np.int)  # 存储变异后的个体
    for i in range(np.int(NP / 2)):  # 遍历前一半个体
        # 选激励度前NP/2个体进行免疫操作
        a = Sortf[i]  # 当前个体 .shape(city_num,)
        a = a.reshape(-1, city_num)  # (-1,维度city_num)
        Na = np.tile(a, (Ncl, 1))  # 对当前个体进行克隆 Na.shape=(Ncl, city_num)
        for j in range(Ncl):  # 遍历每一个克隆样本
            p1=np.random.randint(0,city_num,1)[0]  # 随机产生一个整数[0,31)
            p2 = np.random.randint(0, city_num, 1)[0]  # [0,31)
            while p1 == p2:
                p1 = np.random.randint(0, city_num, 1)[0]  # 随机产生一个整数[0,31)
                p2 = np.random.randint(0, city_num, 1)[0]  # [0,31)
            tmp = Na[j,p1]
            Na[j,p1] = Na[j,p2]
            Na[j,p2] = tmp
        # 保留克隆源个体
        Na[0, :] = Sortf[i]
        #####克隆抑制,保留亲和度最高的个体
        NaMSLL = np.zeros((Ncl, 1))  # 存储变异种群亲和度值
        for j in range(Ncl):  # 遍历每一个克隆样本
            NaMSLL[j] = fitness_func(D, xi=Na[j]) # 亲和度=距离
        Index = np.argsort(NaMSLL, axis=0)  # 激励度按升序排序
        Index = Index[:, 0]
        NaSortf = Na[Index]  # 排序后的种群
        af[i] = NaSortf[0]  # 取最优
    return af


#免疫操作:创建新生种群
def refresh():
    bf = np.zeros((np.int(NP/2), city_num), dtype=np.int)
    for i in range(np.int(NP/2)):  # 遍历每一个个体
        bf[i, :] = np.random.choice(list(range(0, city_num)), size=city_num, replace=False)  # 群体初始化
    return bf





#############免疫算法开始############
D=calculate_distance(C[:,0], C[:,1])#任意两个城市距离间隔矩阵 shape=(31, 31)

NP=200                           #免疫个体数目
G=600                          #最大免疫代数
f=np.zeros((NP,city_num),dtype=np.int)                    #用于存储种群 shape=(200, 31)
for i in range(NP):#遍历每一个个体
    f[i,:]=np.random.choice(list(range(0, city_num)), size=city_num, replace=False)#群体初始化

len=np.zeros((NP,1))                  #存储路径长度
for i in range(NP):#遍历每一个个体
    len[i]=fitness_func(D, xi=f[i]) #计算初始群体每个个体的路程长度

###激励度按升序排序
Index=np.argsort(len,axis=0)
Index=Index[:,0]
Sortf=f[Index] # #排序后的初始群体 shape=(200, 31)




##############免疫循环############
trace=[] #记录迭代激励度最优值
for gen in tqdm(range(G)):#遍历每一次迭代
    af = variation(Sortf)  # 选择一半个体 进行克隆、变异、变异抑制 shape=(100, 31)
    aflen=np.zeros((af.shape[0],1))                  #存储af群体路径长度 shape=(100, 1)
    for j in range(af.shape[0]):#遍历af中的每一个个体
        aflen[j] = fitness_func(D, xi=af[j])  # 计算af群体每个个体的路程长度(亲和度)

    bf = refresh()  # 创建一半新生种群#bf.shape=(100, 31)
    bflen = np.zeros((bf.shape[0], 1))  # 存储bf群体路径长度 shape=(100, 1)
    for j in range(bf.shape[0]):#遍历af中的每一个个体
        bflen[j] = fitness_func(D, xi=bf[j])  # 计算af群体每个个体的路程长度(亲和度)

    # ##########种群刷新:免疫种群与新生种群合并##
    f1 = np.concatenate((af, bf), axis=0)  # 合并的种群 f1.shape=(50, 2) f1为子代
    f1len = np.concatenate((aflen, bflen), axis=0)  # 合并种群激励度值 shape=(200, 1)

    Index = np.argsort(f1len, axis=0)
    Index = Index[:, 0]
    Sortf = f1[Index]  # shape(50, 2)
    trace.append(fitness_func(D, xi=f1[0]))  # 记录最优个体的激励度值



############输出优化结果
Bestf=Sortf[0,:]                #最优变量
print('最优变量',Bestf)
print('最优值',trace[-1] )       #最优值
plt.plot(trace)
plt.title('迭代曲线')
plt.show()
plot_tsp(Bestf)

在这里插入图片描述

作者:电气 余登武

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

总裁余(余登武)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值