1. 程式人生 > 其它 >遺傳演算法解決TSP問題

遺傳演算法解決TSP問題

旅行商問題,即TSP問題(Traveling Salesman Problem)又譯為旅行推銷員問題、貨郎擔問題,是數學領域中著名問題之一。
假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最後要回到原來出發的城市。
路徑的選擇目標是要求得的路徑路程為所有路徑之中的最小值。

選用python和matplotlib.pyplot圖形化

import math
import copy
import random
import numpy as np
import matplotlib.pyplot as plt
from numpy.lib.function_base import average

class TSP():
    citys_position=[]               #城市座標
    population=[]                   #種群陣列
    fitness=[]                      #適應度陣列
    citys_size=10                   #城市個數
    population_size=100             #種群大小
    rate_crossover=0.1             #交叉率
    rate_mutation=0.01              #變異率
    iteration_num=200              #最大迭代次數
    best_dist=0x3f3f3f3f3f          #記錄最優距離
    dist_list=[]                    #記錄當前距離
    best_dist_list=[]               #記錄最優距離    
    best_individual=[]              #記錄目前最優旅行方案 
    
    #載入城市座標
    def load_citys_position(self):
        self.citys_position=[
            [18,54],[87,76],[74,78],[71,71],[25,38],
            [58,35],[4,50],[13,40],[18,40],[24,42],
            # [71,44],[64,60],[68,58],[83,69],[58,69],
            # [54,62],[51,67],[37,84],[41,94],[2,99]
        ]

    #載入初始種群
    def load_population(self):
        for i in range(self.population_size):
            temp=[]
            while len(temp)<self.citys_size:
                ite = random.randint(0,self.citys_size-1)
                if ite not in temp:
                    temp.append(ite)
            self.population.append([])
            for j in temp:
                self.population[i].append(j)
        # print(self.population)

    #初始化
    def __init__(self):
        self.load_citys_position()
        self.load_population()
        self.get_fitness()
        self.choice()

    #城市距離-染色體權值
    def city_dist(self,i,j):
        x=self.citys_position[i]
        y=self.citys_position[j]
        return math.sqrt(pow(x[0]-y[0],2)+pow(x[1]-y[1],2))

    #種群距離集
    def population_dist(self):
        now_dist_list=[]
        for i in range(len(self.population)):
            now_dist=0
            for j in range(1,len(self.population[i])):
                    now_dist+=self.city_dist(self.population[i][j],self.population[i][j-1])
            now_dist_list.append(now_dist)
        return now_dist_list

    #適應度函式
    def get_fitness(self):
        self.dist_list=self.population_dist()
        now_best_dist=min(self.dist_list)
        now_best_dist_index=self.dist_list.index(now_best_dist)
        now_fitness=[]
        
        if now_best_dist<self.best_dist:
            self.best_dist_list.append(now_best_dist)
            self.best_dist=now_best_dist
            self.best_individual=self.population[now_best_dist_index]
        else :
            self.best_dist_list.append(self.best_dist)
        for i in range(len(self.dist_list)):
            now_fitness.append(self.best_dist/self.dist_list[i])
        self.fitness=now_fitness
        # print("self.best_dist:",self.best_dist," now_dist_list:",now_dist_list)
        # print("self.fitness:",self.fitness)
                    
    #變異
    def mutation(self):
        for i in range(len(self.population)):
            now_rate=random.random()
            if(now_rate<self.rate_mutation):
                #隨機出兩個點進行片段翻轉
                index1=random.randint(0,len(self.population[i])-1)
                index2=random.randint(0,len(self.population[i])-1)
                if index1>index2:
                    temp=index1
                    index1=index2
                    index2=temp
                self.population[i][index1:index2]=list(reversed(self.population[i][index1:index2]))

    #交叉互換
    def crossover(self):
        last_index=-1;
        for i in range(len(self.population)):
            now_rate=random.random();
            if(now_rate<self.rate_crossover):
                if(last_index==-1):
                    last_index=i
                else : #順序交叉,保留前一個染色體的中間段,交換兩端
                    index1=random.randint(0,len(self.population[last_index])-1)
                    index2=random.randint(0,len(self.population[last_index])-1)
                    if index1>index2:
                        temp=index1
                        index1=index2
                        index2=temp
                    temp_list=[]    #取出中間段
                    for j in range(index1,index2+1):
                        temp_list.append(self.population[last_index][j])
                    next_gen=[]  #儲存交叉互換後的基因
                    index_temp=0
                    for j in range(len(self.population[i])):                            
                        if self.population[i][j] not in temp_list:
                            next_gen.append(self.population[i][j])
                        else :
                            next_gen.append(temp_list[index_temp])
                            index_temp+=1
                    self.population[last_index]=next_gen  #賦新基因
                    last_index=i;
     #選擇函式
    def choice(self):
        #最優解覆蓋
        for i in range(len(self.fitness)):
            if self.fitness[i]<0.5:
                # print("self.fitness[i]:",self.fitness[i]," self.dist_list[i]:",self.dist_list[i]," best_dist:",self.best_dist)
                # print("self.population[i]:",self.population[i],"self.best_individual:",self.best_individual)
                # print(" ")
                self.population[i]=self.best_individual
                self.fitness[i]=1
                   
    #進化,主函式
    def evolution(self):
        now_iteration_num=0 
        while now_iteration_num<self.iteration_num:
            now_iteration_num+=1
            self.crossover()
            self.mutation()
            self.get_fitness()
            self.choice()
            

    #視覺化資料
    def plot_show(self):
        print("self.best_dist",end=":")
        print(self.best_dist)
        print("self.best_individual",end=":")
        print(self.best_individual)
        x1=[]
        y1=[]
        x2=[]
        y2=[]
        for i in range(len(self.citys_position)):
            x1.append(self.citys_position[i][0])
            y1.append(self.citys_position[i][1])
        for i in range(len(self.best_individual)):
            x2.append(self.citys_position[self.best_individual[i]][0])
            y2.append(self.citys_position[self.best_individual[i]][1])
        print("x1:",end="")
        print(x1)
        print("y1:",end="")
        print(y1)
        print("x2:",end="")
        print(x2)
        print("y2:",end="")
        print(y2)
        plt.title("citys_position")
        plt.scatter(x1,y1,color='r',marker='o' ); #畫點
        plt.figure();
        plt.title("best_route")
        plt.plot(x2,y2,color='r',marker='o' ); #畫點
        for i in range(len(x2)):
            plt.text(x2[i],y2[i],i+1)
        plt.figure();
        plt.title("best_dist_change")
        plt.plot(self.best_dist_list,color='r')
        plt.show()
def main():
    tsp=TSP()
    tsp.evolution()
    tsp.plot_show()

if __name__ == '__main__':
    main()