Code source de code_beatrix.algorithm.tsp
# -*- coding: utf-8 -*-
"""
Function solving the TSP problem
:githublink:`%|py|6`
"""
import random
[docs]def distance_point(p1, p2):
"""
Returns the Euclidian distance between two points.
Retourne la distance euclidienne entre deux points.
:param p1: point 1
:param p2: point 2
:return: distance
:githublink:`%|py|18`
"""
d = 0
for a, b in zip(p1, p2):
d += (a - b) ** 2
return d ** 0.5
[docs]def distance_circuit(points):
"""
Computes the distance of this circuit.
Calcule la longueur d'un circuit.
:param points: list of points, the circuit assumes they are giving in that order
:return: distance
:githublink:`%|py|32`
"""
d = 0
for i in range(1, len(points)):
d += distance_point(points[i - 1], points[i])
return d + distance_point(points[0], points[-1])
[docs]def permutation(points, i, j):
"""
Switches two points and returns a new path.
Echange deux points et retourne le nouveau circuit.
:param points: circuit
:param i: first index
:param j: second index (< len(points))
:return: new circuit
:githublink:`%|py|48`
"""
points = points.copy()
points[i], points[j] = points[j], points[i]
return points
[docs]def reverse(points, i, j):
"""
Reverses a sub part of circuit.
Retourne une partie du circuit.
:param points: circuit
:param i: first index
:param j: second index (<= len(points))
:return: new circuit
:githublink:`%|py|63`
"""
points = points.copy()
if i > j:
i, j = j, i
c = points[i:j]
c.reverse()
points[i:j] = c
return points
[docs]def voyageur_commerce_simple(points):
"""
Solves the TSP using basic permutations,
points are 2D coordinates.
Résoud le problème du voyageur de commerce.
:param points: list of points
:githublink:`%|py|80`
"""
d0 = distance_circuit(points)
dnew = d0
n = len(points) - 1
first = True
while dnew < d0 or first:
first = False
d0 = dnew
# first pass : random
for i in range(len(points)):
h1 = random.randint(0, n)
h2 = random.randint(0, n)
p = permutation(points, h1, h2)
d = distance_circuit(p)
if d < dnew:
dnew = d
points = p
h1 = random.randint(0, n)
h2 = random.randint(h1 + 1, n + 1)
p = reverse(points, h1, h2)
d = distance_circuit(p)
if d < dnew:
dnew = d
points = p
# second pass : no reverse
for i in range(len(points)):
for j in range(i + 1, len(points) + 1):
p = reverse(points, i, j)
d = distance_circuit(p)
if d < dnew:
dnew = d
points = p
return points
[docs]def plot_circuit(points, ax=None, **kwargs):
"""
Plots the circuit on a graph.
Dessine la solution du voyageur de commerce.
:param points: points
:param ax: axe
:param kwargs: sent to ``plt.subplots``
:return: ax
:githublink:`%|py|128`
"""
if ax is None:
import matplotlib.pyplot as plt
_, ax = plt.subplots(**kwargs)
ax.plot([_[0] for _ in points], [_[1] for _ in points], "o")
p2 = points + [points[0]]
ax.plot([_[0] for _ in p2], [_[1] for _ in p2], "-")
return ax