遗传算法解决TSP问题(三种交叉)

代码参考博客:https://blog.csdn.net/springtostring/article/details/82429604 改进

算法参考:https://blog.csdn.net/u012750702/article/details/54563515

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import math
import random

matplotlib.rcParams['font.family'] = 'STSong'
inputfile = ['eil51.txt','eil76.txt','eil101.txt',
             'str70.txt','kroA100.txt','kroC100.txt',
             'kroD100.txt', 'lin105.txt','pcb442.txt','pr2392.txt']
outputfile = ['eil51.outcome.txt','eil76.outcome.txt','eil101.outcome.txt',
             'str70.outcome.txt','kroA100.outcome.txt','kroC100.outcome.txt',
             'kroD100.outcome.txt', 'lin105.outcome.txt','pcb442.outcome.txt','pr2392.outcome.txt']



# 改良次数
improve_count = 2000

# 进化次数
evolution_time=[5000,10000,20000]

# 种群数
counts = [10,20,50,2000]



# 设置强者的定义概率,即种群前30%为强者
retain_rate = 0.3

# 设置弱者的存活概率
random_select_rate = 0.5

# 变异率
mutation_rate = 0.05
class TspHandler:

    def __init__(self,infile,outfile,count):
        # 种群数
        self.count = count
        self.city_name = []
        self.city_condition = []
        self.Distance = []
        self.register=[]
        self.read_file(infile)
        i=0
        population = self.population
        while i < 20001:
            # 选择繁殖个体群
            parents = self.selection(population)
            # 交叉繁殖
            children = self.crossover1(parents)
            # 变异操作
            self.mutation(children)
            # 更新种群
            population = parents + children

            distance, result_path = self.get_result(population)
            self.register.append(distance)
            i+=1
            if ( i==20000):

                X = []
                Y = []
                for index in result_path:
                    X.append(self.city_condition[index-1][0] )
                    Y.append(self.city_condition[index-1][1])

                plt.plot(X, Y, '-o')
                plt.show()

                plt.plot(list(range(len(self.register))), self.register)
                plt.show()
                result_path = [self.origin] + result_path + [self.origin]
               # with open('./outcomes/' + outfile+'1', 'a', encoding='UTF-8') as f:
             #       print(count, i)
              #      print(distance)
              #      print(result_path)
              #      f.write('population:' + str(count) + '  ' + 'generations:' + str(i) + '\n')
               #     f.write('全程路程:' + str(distance) + '\n')
                #    f.write('路线:')
               #     f.write(str(result_path) + '\n')





    # 总距离
    def get_total_distance(self,x):
        distance = 0
        distance += self.Distance[self.origin-1][x[0]-1]
        d =len(x)
        for i in range(d):
            if i == d - 1:
                distance += self.Distance[self.origin-1][x[i]-1]
            else:
                distance += self.Distance[x[i]-1][x[i + 1]-1]
        return distance

    # 改良
    def improve(self,x):
        i = 0
        distance = self.get_total_distance(x)
        d = len(x)
        while i < improve_count:
            # randint [a,b]
            u = random.randint(0, d - 1)
            v = random.randint(0, d - 1)
            if u != v:
                new_x = x.copy()
                t = new_x[u]
                new_x[u] = new_x[v]
                new_x[v] = t
                new_distance = self.get_total_distance(new_x)
                if new_distance < distance:
                    distance = new_distance
                    x = new_x.copy()
            else:
                continue
            i += 1

    # 自然选择
    def selection(self,population):
        """
        选择
        先对适应度从大到小排序,选出存活的染色体
        再进行随机选择,选出适应度虽然小,但是幸存下来的个体
        """
        # 对总距离从小到大进行排序
        graded = [[self.get_total_distance(x), x] for x in population]
        graded = [x[1] for x in sorted(graded)]
        # 选出适应性强的染色体
        retain_length = int(len(graded) * retain_rate)
        parents = graded[:retain_length]
        # 选出适应性不强,但是幸存的染色体
        for chromosome in graded[retain_length:]:
            if random.random() < random_select_rate:
                parents.append(chromosome)
        return parents

    def crossover1(self,parents):

        d = len(parents)
        target_count = self.count - d
        children = []

        while len(children) < target_count:
            male_index = random.randint(0, d - 1)
            female_index = random.randint(0, d - 1)
            if male_index != female_index:

                male = parents[male_index]
                female = parents[female_index]
                d1 = len(male)
                star = random.randint(0, d1- 1)
                if female[star] != male[star]:
                    index = 1
                else:
                    index = 0
                gene1 = []
                gene2 = []
                gene1.append(male[star])
                gene2.append(female[star])
                while (index == 1):
                    for i in range(d1):
                        if len(gene2) == d1:
                            index = 0
                        if male[i] == female[star]:
                            star = i
                            gene1.append(male[star])
                            gene2.append(female[star])
                            if (gene1[0] == female[i]):
                                index = 0
                            break
                exchange_shine = []
                for i in range(len(gene1)):
                    exchange_shine.append([gene1[i], gene2[i]])

                children1 = male.copy()
                children2 = female.copy()
                d2 = len(exchange_shine)
                for i in range(d1):
                    for j in range(d2):
                        if (children1[i] == exchange_shine[j][0]):
                            children1[i] = exchange_shine[j][1]
                            break
                    for m in range(d2):
                        if (children2[i] == exchange_shine[m][1]):
                            children2[i] = exchange_shine[m][0]
                            break
                children.append(children1)
                if (len(children) < target_count):
                    children.append(children2)
        return children

    def crossover2(self,parents):
        d = len(parents)
        target_count = self.count - d

        children = []

        while len(children) < target_count:
            male_index = random.randint(0, d - 1)
            female_index = random.randint(0, d - 1)
            if male_index != female_index:
                male = parents[male_index]
                female = parents[female_index]

                left = random.randint(0, len(male) - 2)
                right = random.randint(left + 1, len(male) - 1)

                gene1 = male[left:right]
                gene2 = []
                children1 = male.copy()
                children2 = female.copy()

                index = 0
                d1 = len(female)
                for i in range(d1):
                    if female[i] in gene1:
                        gene2.append(female[i])
                        children2[i] = gene1[index]
                        index += 1
                children1[left:right] = gene2
                children.append(children1)
                children.append(children2)
        return children

    # 交叉繁殖
    def crossover3(self,parents):
        # 生成子代的个数,以此保证种群稳定
        target_count = self.count - len(parents)
        # 孩子列表
        children = []
        while len(children) < target_count:
            male_index = random.randint(0, len(parents) - 1)
            female_index = random.randint(0, len(parents) - 1)
            if male_index != female_index:
                male = parents[male_index]
                female = parents[female_index]

                left = random.randint(0, len(male) - 2)
                right = random.randint(left + 1, len(male) - 1)

                # 交叉片段
                gene1 = male[left:right]
                gene2 = female[left:right]

                child1_c = male[right:] + male[:right]
                child2_c = female[right:] + female[:right]
                child1 = child1_c.copy()
                child2 = child2_c.copy()

                for o in gene2:
                    child1_c.remove(o)

                for o in gene1:
                    child2_c.remove(o)

                child1[left:right] = gene2
                child2[left:right] = gene1

                d =len(child1)

                child1[right:] = child1_c[0:d - right]
                child1[:left] = child1_c[d - right:]

                child2[right:] = child2_c[0:d - right]
                child2[:left] = child2_c[d - right:]

                children.append(child1)
                children.append(child2)

        return children

    # 变异
    def mutation(slef,children):
        for i in range(len(children)):
            if random.random() < mutation_rate:
                child = children[i]
                d =len(child)
                u = random.randint(1, d - 4)
                v = random.randint(u + 1, d - 3)
                w = random.randint(v + 1, d - 2)
                child = children[i]
                child = child[0:u] + child[v:w] + child[u:v] + child[w:]
                children[i] = child
        return children

    # 得到最佳纯输出结果
    def get_result(self,population):
        graded = [[self.get_total_distance(x), x] for x in population]
        graded = sorted(graded)
        return graded[0][0], graded[0][1]


    def read_file(self,file_path):
        with open(file_path, 'r', encoding='UTF-8') as f:
            city_condition = []
            lines = f.readlines()
            for line in lines:
                line = line.split('\n')[0]
                line = line.split(' ')
                self.city_name.append(line[0])
                city_condition.append([float(line[1]), float(line[2])])
        self.city_condition = np.array(city_condition)
        # 展示地图
        # plt.scatter(city_condition[:,0],city_condition[:,1])
        # plt.show()
        # 距离矩阵
        city_count = len(self.city_name)
        self.Distance = np.zeros([city_count, city_count])

        for i in range(city_count):
            for j in range(city_count):
                self.Distance[i][j] = math.sqrt(
                    (city_condition[i][0] - city_condition[j][0]) ** 2 + (
                                city_condition[i][1] - city_condition[j][1]) ** 2)
        self.population = []
        # 设置起点
        self.origin = 15
        index = [i for i in range(city_count)]
        index.remove(15)
        # 使用改良圈算法初始化种群
        for i in range(self.count):
            # 随机生成个体
            x = index.copy()
            random.shuffle(x)
            self.improve(x)
            self.population.append(x)


if __name__ == '__main__':
    for infile,outfile in zip(inputfile,outputfile):
        for  count in counts:
            a = TspHandler(infile,outfile,count)



你可能感兴趣的:(算法,TSP)