im quite the noob when it comes to coding. I am currently trying to code a solution for a traveling salesman problem. I already found functioning code for a set of random values (as seen below or in https://nbviewer.jupyter.org/url/norvig.com/ipython/TSP.ipynb#Random-Sets-of-Cities). Now i want to use data in a .csv file that i have created, containing data of cities in a coordinate system (x and y values). However i cannot figure out what exactly i have to change in the code.
I tried changing the definition of the Cities() function into return frozenset(City() for row in csv.reader(staedtekoordinaten.csv, delimiter=";")
but this does not work either.
It is probably quite the stupid question, but i would highly appreciate if someone could help me... Thanks in advance!
import matplotlib.pyplot as plt
import random
import time
import itertools
import urllib
import csv
import functools
from statistics import mean, stdev
def alle_touren_tsp(cities):
# Erstelle eine Auflistung aller möglichen auszuführenden Touren. Aus dieser Liste
# kann später eine Auswahl per "min" Funktion getroffen werden, die die kürzeste Route darstellt.
return minimale_tour(alle_touren(cities))
def minimale_tour(tours):
# Definiere Funktion zur Auswahl der kürzesten Tour.
return min(tours, key=laenge_tour) # aus der Sammlung "touren" minimiere ELement "distanz_tour"
#Verbesserung - Redundante Touren werden vermieden (reduziert Rechenaufwand)
def alle_touren(cities):
# Gibt List mit Touren aus mit Permutation von Städten, alle permutationen starten jedoch mit
# derselben Stadt (verhindert Redundanzen)
start = first(cities)
return [[start] + Tour(rest)
for rest in itertools.permutations(cities - {start})]
def first(collection):
#Iteration über die collection, Ausgabe des jeweils ersten Elements
return next(iter(collection))
Tour = list # Tours are implemented as lists of cities
def laenge_tour(tour):
# Gesamtsumme einer Tour.
# Addiert die gelaufenen Teildistanzen zwischen zwei Datenpunkten (= locations)
return sum(distance(tour[i], tour[i - 1]) # für i=0 wird i-1 der letzte Datenpunkt
for i in range(len(tour)))
# Für alle Elemente in tour (Anzahl = len(tour)) wird die Distanz von der vorherigen Location (i-1)
# zur aktuellen (i) summiert)
# Lösung mit Subclass von Complex - Jeder Datenpunkt (also jeder Ort) wird mit zwei Koordinaten gespeichert,
# der Einfachheit halber im komplexen Zahlenraum (dort hat jeder Punkt generell zwei Koordinaten)
class Datenpunkt(complex):
x = property(lambda p: p.real)
y = property(lambda p: p.imag)
City = Datenpunkt
def distance(A, B):
# Definiert die Distanz "zu laufende Länge" zwischen den Punkten A und B => Euklidische Distanz
return abs(A - B)
# Testdatenpunkt: Randomized Cities mit Seed 42
def Cities(n, width=900, height=600, seed=42):
# Set aus n Datenpunkten mit randomized Koordinaten, dargestellt in width x height (900x600 weil Python-Standard)
random.seed(seed * n)
return frozenset(City(random.randrange(width), random.randrange(height))
# frozenset, damit kein Algorithmus einfach Datenpunkte löscht
# (i. S. v. der kürzeste Weg wäre, erst gar keinen Weg zu laufen)
for c in range(n))
alle_touren_tsp(Cities(8))
def plot_tour(tour):
# "Plot the cities as circles and the tour as lines between them."
plot_lines(list(tour) + [tour[0]])
def plot_lines(points, style='bo-'):
# "Plot lines to connect a series of points."
plt.plot([p.x for p in points], [p.y for p in points], style)
plt.axis('scaled');
plt.axis('off')
plot_tour(alle_touren_tsp(Cities(8)))
def plot_tsp(algorithm, cities):
# "Apply a TSP algorithm to cities, plot the resulting tour, and print information."
# Find the solution and time how long it takes
t0 = time.process_time()
tour = algorithm(cities)
t1 = time.process_time()
assert valid_tour(tour, cities)
plot_tour(tour);
plt.show()
print("{} city tour with length {:.1f} in {:.3f} secs for {}"
.format(len(tour), laenge_tour(tour), t1 - t0, algorithm.__name__))
def valid_tour(tour, cities):
# "Is tour a valid tour for these cities?"
return set(tour) == set(cities) and len(tour) == len(cities)
plot_tsp(alle_touren_tsp, Cities(8))
As for the new code (if I understood the remarks correctly:
import csv
# Lösung mit Subclass von Complex - Jeder Datenpunkt (also jeder Ort) wird mit zwei Koordinaten gespeichert,
# der Einfachheit halber im komplexen Zahlenraum (dort hat jeder Punkt generell zwei Koordinaten)
class Datenpunkt(complex):
x = property(lambda p: p.real)
y = property(lambda p: p.imag)
class City(Datenpunkt):
# this is a subclass of `complex` which sets itself up in `__new__`
def __new__(cls, x, y, name):
self = super().__new__(cls, float(x), float(y))
self.name = name
return self
def __str__(self):
return "{} {}".format(super().__str__(), self.name)
def __repr__(self):
return str(self)
@classmethod
def from_csv(cls, row):
"""Create class from CSV row. Row is assumed to be a collection with
index 0 and 1 being the coordinates of interest."""
return cls(*row[0:3])
def Cities(filename):
with open(filename, newline='') as fp:
return frozenset(City.from_csv(row) for row in csv.reader(fp, delimiter=";"))
print(Cities("testfile.csv"))
This gives the errors: Traceback (most recent call last):
File "filepath/Test.py", line 35, in <module>
print(Cities("testfile.csv"))
File "filepath/Test.py", line 34, in Cities
return frozenset(City.from_csv(row) for row in csv.reader(fp,
delimiter=";"))
File "filepath/Test.py", line 34, in <genexpr>
return frozenset(City.from_csv(row) for row in csv.reader(fp,
delimiter=";"))
File "filepath/Test.py", line 29, in from_csv
return cls(*row[0:3])
File "filepath/Test.py", line 15, in __new__
self = super().__new__(cls, float(x), float(y))
ValueError: could not convert string to float: 'x'
Process finished with exit code 1
The printed lines according to your idea are:
b'\xef\xbb\xbfx;y;name\r\n'b'0;0;Duisburg\r\n'
b'455,56;120,87;Berlin\r\n'
b'218,86;235,59;Hamburg\r\n'
b'345,6;-366,75;Muenchen\r\n'
b'13,97;-55,24;Koeln\r\n'
b'135,12;-147,2;Frankfurt\r\n'
b'190,25;-13,17;Kassel\r\n'
b'297,02;-51,3;Erfurt\r\n