遺傳算法求解旅行商(TSP)問題 -- python


參考資料:

遺傳算法解決TSP旅行商問題(附:Python實現)

遺傳算法詳解(GA)(個人覺得很形象,很適合初學者)

from itertools import permutations
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from itertools import combinations, permutations 
#%matplotlib inline

def fitnessFunction(pop,num,city_num,x_position_add_end,y_position_add_end):
    '''適應度函數,計算每個排列的適應度,並保存到pop矩陣第二維的最后一項'''
    for x1 in range(num):
        square_sum = 0
        for x2 in range(city_num):
            square_sum += (x_position_add_end[int(pop[x1][x2])] - x_position_add_end[int(pop[x1][x2+1])])**2 + (y_position_add_end[int(pop[x1][x2])] - y_position_add_end[int(pop[x1][x2+1])])**2
        # print(round(1/np.sqrt(square_sum),7))
        pop[x1][-1] = round(1/np.sqrt(square_sum),7)

def choiceFuction(pop): 
    '''
    這里的做法:比如A當前種群中的最優解,B為經過交叉、變異后的最差解,把A作為最當前代中的最優解保存下來作為這一代的最優解,同時A也參與交叉
    和變異。經過交叉、變異后的最差解為B,那么我再用A替代B。
    :argument pop矩陣
    :return 本代適應度最低的個體的索引值和本代適應度最高的個體
    '''
    yield np.argmin(pop[:, -1])
    yield pop[np.argmax(pop[:, -1])]

def choice(pop,num,city_num,x_position_add_end,y_position_add_end,b):
    fitnessFunction(pop,num,city_num,x_position_add_end,y_position_add_end)
    c,d =choiceFuction(pop)
    # 上一代的最優值替代本代中的最差值
    pop[c] = b
    return pop


def drawPic(maxFitness,x_position,y_position,i):
    index = np.array(maxFitness[:-1],dtype=np.int32)
    x_position_add_end = np.append(x_position[index],x_position[[index[0]]])
    y_position_add_end = np.append(y_position[index],y_position[[index[0]]])
    fig = plt.figure()
    plt.plot(x_position_add_end,y_position_add_end,'-o')
    plt.xlabel('x',fontsize = 16)
    plt.ylabel('y',fontsize = 16)
    plt.title('{iter}'.format(iter=i))
    
def matuingFuction(pop,pc,city_num,pm,num):
    mating_matrix =np.array(1-(np.random.rand(num)>pc),dtype=np.bool)  # 交配矩陣,如果為true則進行交配
    a = list(pop[mating_matrix][:,:-1])# 進行交配的個體
    b = list(pop[np.array(1-mating_matrix,dtype=bool)][:,:-1]) # 未進行交配的個體,直接放到下一代
    b = [list(i) for i in b] # 對b進行類型轉換,避免下面numpy.array 沒有index屬性
#     print(a)
    if len(a)%2 !=0:
        b.append(a.pop())
#     print('ab的長度:',len(a),len(b))
    for i in range(int(len(a)/2)):
        # 隨機初始化兩個交配點,這里寫得不好,這邊的兩個點初始化都是一個在中間位置偏左,一個在中間位置偏右
        p1 = np.random.randint(1,int(city_num/2)+1)
        p2 = np.random.randint(int(city_num/2)+1,city_num)
        x1 = list(a.pop())
        x2 = list(a.pop())
        matuting(x1,x2,p1,p2)
        # 交配之后產生的個體進行一定概率上的變異
        variationFunction(x1,pm,city_num)
        variationFunction(x2,pm,city_num)
        b.append(x1)
        b.append(x2)
    zero = np.zeros((num,1))
#     print('b的形狀:',len(b))
    temp = np.column_stack((b, zero))
    return temp
        
    
def matuting(x1,x2,p1,p2):
        # 以下進行交配
        # 左邊交換位置
        temp = x1[:p1]
        x1[:p1] = x2[:p1]
        x2[:p1] = temp
        # 右邊交換位置
        temp = x1[p2:]
        x1[p2:] = x2[p2:]
        x2[p2:] = temp
        # 尋找重復的元素
        center1 = x1[p1:p2]
        center2 = x2[p1:p2]
        while True: # x1左邊
            for i in x1[:p1]:
                if i in center1:
                    # print(center1.index(i)) # 根據值找到索引
                    x1[x1[:p1].index(i)] = center2[center1.index(i)]
                    break
            if np.intersect1d(x1[:p1],center1).size == 0: # 如果不存在交集,則循環結束
                break
        while True: # x1右邊
            for i in x1[p2:]:
                if i in center1:
                    # print(center1.index(i)) # 根據值找到索引
                    x1[x1[p2:].index(i) + p2] = center2[center1.index(i)]
                    # print(x1)
                    break
            if np.intersect1d(x1[p2:],center1).size == 0: # 如果不存在交集,則循環結束
                break
        while True: # x2左邊
            for i in x2[:p1]:
                if i in center2:
#                     print(center2.index(i)) # 根據值找到索引
                    x2[x2[:p1].index(i)] = center1[center2.index(i)]
                    break
            if np.intersect1d(x2[:p1],center2).size == 0: # 如果不存在交集,則循環結束
                break
        while True: # x2右邊
            for i in x2[p2:]:
                if i in center2:
                    # print(center2.index(i)) # 根據值找到索引
                    x2[x2[p2:].index(i) + p2] = center1[center2.index(i)]
                    # print(x2)
                    break
            if np.intersect1d(x2[p2:],center2).size == 0: # 如果不存在交集,則循環結束
                break   
               
def variationFunction(list_a,pm,city_num):
    '''變異函數'''
    if np.random.rand() < pm:
        p1 = np.random.randint(1,int(city_num/2)+1)
        p2 = np.random.randint(int(city_num/2)+1,city_num)
#         print(p1,p2)
        temp = list_a[p1:p2]
        temp.reverse()
        list_a[p1:p2] = temp
#         print(list_a)
def main():
    # 初始化
    pop = [] # 存放訪問順序和每個個體適應度
    num = 250 # 初始化群體的數目
    city_num = 10 # 城市數目
    pc = 0.9 # 每個個體的交配概率
    pm = 0.2 # 每個個體的變異概率 
    x_position = np.random.randint(0,100,size=city_num)
    y_position = np.random.randint(0,100,size=city_num)
    x_position_add_end = np.append(x_position,x_position[0])
    y_position_add_end = np.append(y_position,y_position[0])
    for i in range(num):
        pop.append(np.random.permutation(np.arange(0,city_num))) # 假設有5個城市,初始群體的數目為60個
        # 初始化化一個60*1的拼接矩陣,值為0
    zero = np.zeros((num,1))
    pop = np.column_stack((pop, zero)) # 矩陣的拼接
    fitnessFunction(pop,num,city_num,x_position_add_end,y_position_add_end)
    for i in range(180):
        a,b = choiceFuction(pop) # a 為當代適應度最小的個體的索引,b為當代適應度最大的個體,這邊要保留的是b
#         print('索引值和適應度最大的個體:',a,b)
    #     pop[a]=b
        if (i+1)%10==0:
            drawPic(b,x_position,y_position,i+1) # 根據本代中的適應度最大的個體畫圖
        pop_temp = matuingFuction(pop,pc,city_num,pm,num) #交配變異
        pop = choice(pop_temp,num,city_num,x_position_add_end,y_position_add_end,b)
        

main()

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM