import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random as rd
from math import sqrt, exp
import os
"旅行商问题 ( TSP , Traveling Salesman Problem )"
'''
编写模拟退火算法解旅行商问题
实现TSP的模拟退火算法函数，输入是矩阵表示的图，输出是路径
可视化显示中间变化过程
要有详细的注释
使用python语言
'''

# input

def loadin_data():
    local_path = os.path.dirname(__file__)
    with open(local_path + '/../testdata/1.txt', 'r') as f:
        data = f.read()
        data = data.split()
        length = len(data)
        x = []
        y = []
        for i in range(length//2):
            x.append(int(data[2*i]))
            y.append(int(data[2*i+1]))
        f.close()
        # print(data)
        return x, y


def distance(path, i, j):
    a = path[0][i]-path[0][j]
    b = path[1][i]-path[1][j]
    return sqrt(a**2+b**2)


def exchange(path, a, b):
    path[0][a], path[0][b] = path[0][b], path[0][a]
    path[1][a], path[1][b] = path[1][b], path[1][a]


def sum_distance(path):
    sum = 0
    for i in range(len(path[0])-1):
        sum += distance(path, i, i + 1)
        # print(path)
    sum += distance(path, len(path[0]) - 1, 0)
    return sum


x, y = loadin_data()
path = [x, y]
plt.figure(figsize=(10,5))
ax1 = plt.axes([0.05, 0.05, 0.4, 0.9])
ax2 = plt.axes([0.55, 0.05, 0.4, 0.9])

T = 100
alpha = 0.95
iters = 1000
current = sum_distance(path)
print(current, '\n')
next = 0
count = 0
xl = []
yl = []
plt.pause(2)
plt.cla()
plt.ion()  # 打开交互模式
while(True):
    if(T < 0.05):
        break
    oldcurrent = current
    for i in range(iters):
        a, b = rd.sample(range(0, len(path[0])), 2)
        newpath = [[], []]
        for x, y in zip(path[0], path[1]):
            newpath[0].append(x)
            newpath[1].append(y)
        # print(newpath)
        exchange(newpath, a, b)
        # print(newpath)
        next = sum_distance(newpath)
        # print(path)
        # print(newpath)
        # print(next - current)
        if(next < current):
            current = next
            path = newpath.copy()
        elif (rd.random() < exp(-(next - current)/T)):
            current = next
            path = newpath.copy()
    plt.cla()  # 清除画板
    ax2.plot(path[0], path[1], 'b.-')
    ax2.plot([path[0][0], path[0][-1]], [path[1][0], path[1][-1]], 'b.-')
    ax2.plot(path[0], path[1], 'ro')
    plt.pause(0.05)
    if(oldcurrent != current):
        # print(count)
        count += 1
        xl.append(count)
        yl.append(current)
        ax1.plot(xl, yl)
        oldcurrent = current

    T = alpha * T
    print(T)
for x, y in zip(path[0], path[1]):
    print("(", x, y, ")-->", end='')
print(current)
plt.ioff()
plt.show()
