蚁群算法解决TSP问题

流程图

在这里插入图片描述

数据集

att48.tsp【下载链接】

关键要素

  1. 信息素更新:蚁周系统

代码

import random
import numpy as np
import copy
import time
import pandas as pd
import math
import matplotlib.pyplot as plt

def deal_data(city):
    city = np.array(city[0][6:len(city) - 1])
    city_name = city.tolist()
    chu_li = []
    for i in range(0, len(city_name)):
        temp = city_name[i].split()
        del temp[0]
        for x in range(0, 2):
            temp[x] = eval(temp[x])
        chu_li.append(temp)
    return chu_li

def display(city_location,best_route,satisfactory_solution,means):
    X = []
    Y = []
    for i in best_route:
        plt.scatter(city_location[i][0], city_location[i][1],color='b')
        x = city_location[i][0]
        y = city_location[i][1]
        X.append(x)
        Y.append(y)
    X.append(city_location[best_route[0]][0])
    Y.append(city_location[best_route[0]][1])
    plt.plot(X,Y,'-o')
    plt.title("satisfactory solution of TS:%d"%(int(min(satisfactory_solution))))
    plt.show()
    #绘制迭代过程图
    A = [i for i in range(len(means))]#横坐标
    B = satisfactory_solution[:] #纵坐标
    C=means[:]
    plt.xlim(0,len(means))
    plt.xlabel('进化次数',fontproperties="SimSun")
    plt.ylabel('路径里程',fontproperties="SimSun")
    plt.title("solution of ACO changed with evolution")
    plt.plot(A,B,'b-')
    plt.plot(A,C,'r-')
    plt.legend(["best","average"])
    plt.show()
    return 

class ACO:
    def __init__(self, m, alpha, beta, num_task, rho, Q, iter,dis):
        self.m = m  # 蚂蚁数量
        self.alpha = alpha  # 信息素重要程度因子
        self.beta = beta  # 期望值重要程度因子
        self.num_task = num_task  # 城市数量
        self.pheromonetable = np.ones((self.num_task, self.num_task))  # 初始化信息素矩阵,全为1
        self.candidate = np.zeros((m, num_task)).astype(int)  # 候选集列表,为蚂蚁数量*任务数量
        self.rho = rho  # 挥发速度
        self.Q = Q  # 信息素常数
        self.iter = iter  # 最大迭代次数
        self.dis=dis
        
    def initialization(self):  # 初始化蚂蚁位置
        # 注:信息素初始化已在蚁群算法构造函数中完成
        # 在此填入蚂蚁位置初始化代码
        init_position = []
        for i in range(self.m):
            init_position.append(random.randint(0,self.num_task-1))
        return init_position  # 一个列表,代表每个蚂蚁的初始位置,[2,4,5,7],分别表示第一个蚂蚁先执行任务2,第二个蚂蚁先执行任务4
    
    def calculate(self,paths):
        diss=[]
        for i in range(len(paths)):
            dis_sum=0
            for j in range(self.num_task-1):
                dis_sum+=self.dis[paths[i][j]][paths[i][j+1]]
            dis_sum+=self.dis[paths[i][-1]][paths[i][0]]
            diss.append(dis_sum)
        return diss
    
    def construct_solution(self, position):  # 构造路径,传入每只蚂蚁的初始位置
        profit_list = []  # 每迭代一次m个蚂蚁遍历的所有解的收益
        seq_list = []
        plan=[]
        for i in range(self.m):  # 每只蚂蚁
            #在此填入蚂蚁路径构造代码,路径以列表形式存在self.candidate[i]中,如,self.candidate[i] = [0,1,2,3,4,5,6,7]
            #注1:全部任务的收益之和,使用 datainstantiation.profit 获取
            #注2:单个任务的收益值,如任务j,使用 datainstantiation.tasklists[j][3] 获取
            task_index1 = position[i]                                # 每只蚂蚁访问的第一个城市下标
            task_path = [task_index1]                                    # 记录每只蚂蚁访问过的城市
            tabu = [task_index1]                                           # 记录每只蚂蚁访问过的城市下标,禁忌城市下标列表
            non_tabu = list(set(range(self.num_task)) - set(tabu))
            for j in range(self.num_task-1):                             # 对余下的任务进行访问
                up_proba = np.zeros(self.num_task-len(tabu))             # 初始化状态迁移概率的分子
                for k in range(self.num_task-len(tabu)):
                    font= np.power(self.pheromonetable[task_index1][non_tabu[k]], self.alpha) #信息素重要度
                    behind=np.power(1/self.dis[task_index1][non_tabu[k]], self.beta) #任务重要度
                    up_proba[k] =font*behind
                proba = up_proba/sum(up_proba)                             # 每条可能子路径上的状态迁移概率
                while True:                                                # 提取出下一个任务的下标
                    random_num = np.random.rand()
                    index_need = np.where(proba > random_num)[0]
                    if len(index_need) > 0:
                        task_index2 = non_tabu[index_need[0]]
                        break
                task_path.append(task_index2)
                tabu.append(task_index2)
                non_tabu = list(set(range(self.num_task)) - set(tabu))
                task_index1 = task_index2
            self.candidate[i]=task_path[:]
            
            for j in range(1):#迭代
                #寻找上一个最优路径对应的所有领域解
                path_new=[self.candidate[i]]
                for p in range(1,self.num_task-1):
                    for q in range(i+1,self.num_task-1):
                        path=self.candidate[i].copy()
                        path[p:q+1]=list(reversed(path[p:q+1]))
                        path_new.append(path)
                dis_new=self.calculate(path_new)
                dis_best=min(dis_new)#最短距离
                path_best=path_new[dis_new.index(dis_best)]#对应的最短路径方案
                self.candidate[i]=path_best[:]
            
            
            '''
            ###计算收益(距离)
            profit=0
            for j in range(self.num_task-1):
                profit+=self.dis[self.candidate[i][j]][self.candidate[i][j+1]]
            profit+=self.dis[self.candidate[i][-1]][self.candidate[i][0]]
            '''
            profit_list.append(dis_best)
            
        return profit_list

    def update(self, profit_list,best_route,best):  # 更新信息素

        changepheromonetable = np.zeros((self.num_task, self.num_task)) #存储每条路径上的信息素增量
        #在此填入信息素更新的代码
        #注1:profit_list存储的是每一只蚂蚁路径构造的解的收益值,即Gk,蚂蚁k的解收益值为profit_list[k]
        #注2:全部任务的收益之和,使用 datainstantiation.profit 获取
        for j in range(len(best_route)-1):
            changepheromonetable[best_route[j]][best_route[j+1]]+=1000*1/best
        changepheromonetable[best_route[-1]][best_route[0]]+=1000*1/best
        
        for i in range(self.m):
            delta=profit_list[i]*self.Q/sum(profit_list)
            for j in range(len(self.candidate[i])-1):
                changepheromonetable[self.candidate[i][j]][self.candidate[i][j+1]]+=delta
            changepheromonetable[self.candidate[i][-1]][self.candidate[i][0]]+=delta
        self.pheromonetable = (1 - self.rho) * self.pheromonetable + changepheromonetable
    def main_process(self):
        profit_iter = []  #存储每一代的最佳收益
        profit_iter_mean=[]
        for i in range(self.iter):
            position = copy.deepcopy(self.initialization())
            profit_list = self.construct_solution(position)
            profit_iter_mean.append(sum(profit_list)/self.m)
            profit_iter.append(min(profit_list))  # 获得每一代的最优值
            if min(profit_list)<=min(profit_iter):
                best_route=self.candidate[profit_list.index(min(profit_list))].copy()
            self.update(profit_list,best_route,min(profit_iter))
            # 更新最优
        return profit_iter_mean,profit_iter,min(profit_iter),best_route


data = pd.read_csv('att48.tsp', encoding='utf-8-sig', header=None)
city_location=deal_data(data) 
city_count=len(city_location)
dis =[[0]*city_count for i in range(city_count)] #距离矩阵
for i in range(city_count):
    for j in range(city_count):
        if i != j:
            dis[i][j] = math.sqrt((city_location[i][0]-city_location[j][0])**2 + (city_location[i][1]-city_location[j][1])**2)
        else:
            dis[i][j] = 0


a=ACO(20,2,4,city_count,0.5,10,100,dis)
#注:若修改任务数量,则datainstantiation.py中读取代码的任务数量也要一同修改
starttime = time.time()
profit_iter_mean,profit_iter,best,best_route=a.main_process()
print(round(time.time()-starttime,2))
print("所求最优解为:%d" % int(best))
display(city_location,best_route,profit_iter,profit_iter_mean)

部分结果展示


数据集运行时间(s)最短距离官方距离
att481493397633533
路线图迭代下降图

小结

从结果可以看出,求解质量很不好。后续有时间的话,我会对其进行改进如精英蚂蚁、最大最小蚂蚁系统、蚁群系统等等,同时也可与局部搜索算法配合使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值