旅行商问题
旅行商问题(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)
作者:电气 余登武
转载:https://blog.csdn.net/kobeyu652453/article/details/116694555
查看评论