Traveling Salesman Problem

Optimization attempts

from numpy import transpose, array
from matplotlib.pyplot import scatter, subplots
from scipy.spatial import distance_matrix
from pandas import DataFrame

points = array([(0,0), (0,4), (3,0), (1,1), (5,5)])
labels = ['A', 'B', 'C', 'D', 'E']
x, y = transpose(points)

fig, ax = subplots()
ax.scatter(x, y)

for i, txt in enumerate(labels):
    ax.annotate(txt, (x[i], y[i]))

df = DataFrame(distance_matrix(points, points), columns=labels)
df
A B C D E
0 0.000000 4.000000 3.000000 1.414214 7.071068
1 4.000000 0.000000 5.000000 3.162278 5.099020
2 3.000000 5.000000 0.000000 2.236068 5.385165
3 1.414214 3.162278 2.236068 0.000000 5.656854
4 7.071068 5.099020 5.385165 5.656854 0.000000
import math
import itertools

def isRouteValid(routes):
    counts = {}
    for f, t, d in routes:
        f = int(f); t = int(t)
        if (f == t): return False
        counts[f] = 1 if counts.get(f, None) is None else counts[f] + 1
        counts[t] = 1 if counts.get(t, None) is None else counts[t] + 1
    for c in counts:
        if (counts[c] != 2): return False
    return True

def mapEnroute(dists, route):
    r = []
    for i in range(len(route)):
        r.append(dists[i][route[i]])
    return r

def nicePrint(pds, i):
    m = [pds[x][y] for x,y in enumerate(i)]
    label = lambda x: labels[int(x)]
    s = sum([d for f,t,d in m])
    return str(["{0} -> {1} {2:.2f}".format(label(f),label(t),d) for f,t,d in m]) + " {:.2f}".format(s)

def cost(distances, labels):
    dists = []
    for x, row in enumerate(distances):
        for y, cell in enumerate(row):
            dists.append([x, y, cell])
    pd = DataFrame(dists, columns=['f','t','d'])
    pds = [list(data.sort_values('d').values) for key,data in pd.groupby('t')]

    iters = list(itertools.product(*([list(range(len(labels)))]*len(labels))))
    iters.sort(key=lambda x: sum(x))
    for i in (iters):
        if(isRouteValid(mapEnroute(pds, i))):
            return nicePrint(pds, i)
    return 0

def bruteIt(distances, labels):
    dists = []
    for x, row in enumerate(distances):
        for y, cell in enumerate(row):
            dists.append([x, y, cell])
    pd = DataFrame(dists, columns=['f','t','d'])
    pds = [list(data.sort_values('d').values) for key,data in pd.groupby('t')]

    iters = list(itertools.permutations(list(range(len(labels)))))
    shortest_route = None
    shortest_dist = 999999999999999999
    for i in iters:
        if any([x==y for x,y in enumerate(i)]): continue
        distance = sum([distances[x,y] for x,y in enumerate(i)])
        if distance < shortest_dist:
            shortest_dist = distance
            shortest_route = i
    return shortest_dist, ["{}{} {:.2f}".format(labels[y],labels[x],distances[x,y]) for x,y in enumerate(shortest_route)], shortest_dist

from timeit import default_timer as timer
start = timer()
print(cost(df.values, labels))
end = timer()
print(end - start,"s")
start = timer()
print(bruteIt(df.values, labels))
end = timer()
print(end - start,"s")
['C -> A 3.00', 'D -> B 3.16', 'E -> C 5.39', 'A -> D 1.41', 'B -> E 5.10'] 18.06
0.06618459999981496 s
(16.84832056705845, ['DA 1.41', 'EB 5.10', 'AC 3.00', 'CD 2.24', 'BE 5.10'], 16.84832056705845)
0.011839300000019648 s

All code in GPL