TSP mit genetischen Algorithmen



1. Allgemeine Problemstruktur

Das Ziel des Softwareprojektes ist es, Lösungen für das Problem des Handlungsreisenden (engl. Traveling Salesman Problem = TSP) zu finden.

Zur Realisierung werden die sogenannten genetischen Algorithmen verwendet.

Als Implementierungsplattform dient die VDM Class Library der FH Wedel zur Erstellung des Datenmodells für den Algorithmus sowie Tcl/Tk zur Ausgabe der Lösung bzw. zum allgemeinen Benutzerdialog.


1.1 Das Traveling Salesman Problem

Bei dem Problem des Handlungsreisenden geht es darum, daß ein Reisender auf einer Rundreise eine bestimmte Anzahl von Städten besuchen muß, wobei jede Stadt nur einmal angefahren werden darf. Ziel ist wieder der Ausgangspunkt der Tour.

Es soll nun eine möglichst kurze (im Optimalfall die kürzeste) Reisestrecke gefunden werden, welche die oben genannten Kriterien erfüllt.

Gegebenenfalls wird auch eine Obergrenze für die Länge des Weges angegeben, die unterschritten werden soll.

Als Ausgangsbasis für die Berechnung der einzelnen Wege dient eine Entfernungsmatrix über alle Städte. Das Aussehen einer solchen Matrix ist im Prinzip jedem Straßenatlas zu entnehmen.

Die möglichen Lösungen steigen bei dem Problem des Handlungsreisenden mit größerem n (= die Anzahl der Städte) rapide an. Es existieren n! (Fakultät) Lösungswege für das TSP (bzw. (n-1)!, wenn der Ausgangsort mit in das n eingerechnet wird, da dieser ja nicht variabel ist). Strenggenommen sind es eigentlich n!/2 (bzw. (n-1)!/2) Lösungen, da die Strecke HH-Bremen-Berlin-HH natürlich bzgl. der Weglänge mit der Strecke HH-Berlin-Bremen-HH identisch ist. Dies' soll aber für die Lösungsfindung nicht weiter beachtet werden.


1.2 Genetische Algorithmen

Der genetische Algorithmus gehört zu den sogenannten heuristischen Verfahren in der Informatik, d.h. das Verfahren beruht auf Hypothesen bzw. Erfahrungen, die Güte des Algorithmus ist nicht beweisbar.

Anwendungsbereiche für derartige Methoden sind Probleme, bei denen das Errechnen der Lösungen exponentiell zur Länge der Eingabe wächst. Da es sich bei dem TSP um so einen Fall handelt, wurde hier auf diese Möglichkeit zurückgegriffen.

Als Vorbild für die genetischen Algorithmen diente die biologische Genetik bzw. insbesondere die Evolutionstheorie.

Die Lösungen für das Problem werden als Chromosomen aufgebaut, die wiederum aus einzelnen Genen zusammengesetzt sind. Jedes Chromosom erhält eine Bewertungsfunktion (auch Fitneß des Chromosoms genannt).

Die Gene repräsentieren die einzelnen Teile der Lösung.

Soll z.B. eine beliebige Funktion f(x,y,z)=... minimiert werden, so stellen die Gene die Werte für x, y und z dar, die Fitneß entspricht dem Funktionswert.

Die Anzahl der Gene in einem Chromosom hängt also von den Veränderlichen in der Funktion ab.

Es wird nun eine Population als eine Menge von Chromosomen aufgebaut (üblicherweise mindestens 50 Chromosomen, danach Vielfache von hundert).

Die Anfangspopulation wird mit zufälligen Werten initialisiert. Danach wird das beste Chromosom bzgl. der Fitneß aus der Population herausgesucht und als erste Lösung präsentiert.

Nun wird die Population mittels verschiedener Vererbungsmechanismen in eine neue Population überführt, das beste Chromosom wird wieder ermittelt, usw. .

Der nächste Vererbungsschritt kann entweder auf Anstoß erfolgen, oder es wird eine bestimmte Anzahl von Iterationsschritten vorgegeben.

Die in diesem Projekt verwendeten Vererbungsmechanismen sind:

Es gibt natürlich noch mehr als die oben genannten Mechanismen, auf die hier aber nicht weiter eingegangen werden soll.

Jede Vererbungsart wird mit einem bestimmten Anteil an der Gesamtpopulation durchgeführt, das zu verändernde Chromosom aus der Ausgangspopulation wird mittels eines Auswahlverfahren bestimmt.

Für weitergehende Information sei auf die fachspezifische Literatur verwiesen.

1.2.1 Reproduktion

Bei der Reproduktion wird ein Chromosom aus der alten Population zufällig ausgewählt und unverändert in die neue Population übernommen. Es wird also reproduziert.

1.2.2 Selektion

Auch bei der Selektion wird ein Chromosom unverändert in die neue Population eingefügt, die Auswahl folgt jedoch im Gegensatz zur Reproduktion anhand der Fitneß des Chromosoms, d.h. die besten überleben.

1.2.3 Mutation

Bei dem ausgewählten Chromosom wird per Zufall ein Gen bestimmt, welches mutiert wird. Diesem Gen wird also ein neuer Wert zugewiesen.

1.2.4 Cross-Over

Beim Cross-Over werden zwei Chromosomen hergenommen. Per Zufall wird ein Gen bestimmt. Ab diesem Gen erfolgt eine Kreuzung der Ausgangschromosomen, es entstehen also zwei neue Chromosomen, von denen in der Regel aber nur eins weiterverwendet wird.


1.3 TSP und Genetische Algorithmen

Das Problem des Handlungsreisenden soll nun mit genetischen Algorithmen realisiert werden. Wie schon dem Kapitel über genetische Algorithmen zu entnehmen ist, repräsentiert ein Chromosom eine mögliche Lösung (hier also einen Reiseweg).

Die einzelnen Gene stellen die anzufahrenden Städte dar. Daraus folgt, daß die Länge der Chromosomen mit (n-1) anzusetzen ist, da der Ausgangs- und Endpunkt der Reise ja feststeht.

Die Frage, die sich stellt, ist, wie die Städte innerhalb der Chromosomen dargestellt werden sollen. Eine Möglichkeit wäre es, den Genen jeweils eine Stadt zuzuweisen und dann den Wert in dem Gen (in diesem Fall zwischen 1 und n-1) als den entsprechenden Punkt auf dem Reiseweg zu betrachten bzw. alternativ den Genen den Punkt auf dem Reiseweg zuzuweisen (erstes Gen = erstes Ziel, usw.) und den Wert als die Stadt zu interpretieren.

Hierbei entsteht allerdings ein Problem. Jeder Wert darf in einem Chromosom nur einmal vorkommen, da sonst eine nicht zulässige Lösung entsteht. Bei den Vererbungen durch Reproduktion bzw. Selektion würde es hierzu gar nicht kommen, Mutation und Cross-Over könnten jedoch unzulässige Lösungen produzieren.

Eine Möglichkeit, dieses zu umgehen, besteht in den sogenannten PMX-Algorithmen, die eine Art Reorganisation der Chromosomen durchführen. Näheres hierzu ist der Literatur zu entnehmen.

Hier wurde allerdings ein anderer Weg beschritten. Die Gene repräsentieren nach wie vor die einzelnen Städte, d.h. Gen 1 ist Stadt A, Gen 2 ist Stadt B, usw. Die Werte in den Genen sind jetzt aber keine Integer-Werte zwischen 1 und n-1 mehr, sondern Realzahlen zwischen 0 und 1. Anhand dieser Realzahlen (bei denen aufgrund der Genauigkeit ein doppeltes Vorkommen des gleichen Wertes nahezu ausgeschlossen ist) wird innerhalb des Chromosoms eine Sortierreihenfolge ermittelt, d.h. das Gen mit der kleinsten Ziffer ist die erste Stadt auf der Route, usw.

Bsp.:

Wenn nun einem Gen z.B. durch Mutation einer neuer Wert zugewiesen wird, entsteht lediglich eine neue Reihenfolge innerhalb des Chromosoms, die Lösung ist jedoch zulässig.

1.3.1 Auswahlverfahren

Auch für die Auswahl des zu verändernden Chromosoms gibt es mehrere Möglichkeiten. Testläufe mit dem sogenannten Roulette-Auswahl-Verfahren, welches Chromosomen mit höherer Fitneß bevorzugt (jedoch die mit geringer Fitneß nicht völlig ausschließt), sind nicht zu unserer Zufriedenheit ausgefallen, wobei dies' im Zweifelsfall aber auch auf schlechte Programmierung zurückzuführen sein könnte, was wir jedoch nicht hoffen wollen. :-)

Auch das Verfahren, welches nur die x besten Chromosomen zur Vererbung benutzt, wurde hier nicht verwendet, da es zwar schnell halbwegs brauchbare Ergebnisse liefert, sich jedoch auf der anderen Seite gerne in lokalen Maxima verhakt.

Wir haben uns schließlich auf das Verfahren "Auswahl durch Zufallszahlen" geeinigt, welches per Zufall zwei Chromosomen aus der Population heraussucht, und dann das Chromosom mit der besseren Fitneß weiterbenutzt.

1.3.2 Parameter

Bei der Auswahl der Parameter (d.h. also die Einstellungen für Reproduktions-, Selektions-, Cross-Over- und Mutationsrate) wurde auf die Empfehlungen aus der Literatur zurückgegriffen.

Diese wurden zwar zu Testzwecken leicht variiert, jedoch landeten wir im Endeffekt wieder bei den Vorgaben aus dem Buch von Kinnebrock bzw. aus dem Informatik-Duden.

Im einzelnen sehen die Vorgaben wie folgt aus (Angaben in Prozent für die Erstellung der neuen Population):


1.4 VDM-Spezifikation

Das Datenmodell für das Problem des Handlungsreisenden mit genetischen Algorithmen wurde mit der VDM-Spezifikation (Vienna Development Method) entworfen. Zur weiteren Vertiefung bzgl. dieser Spezifikation sei auf die Vorlesung "Software-Entwicklungs-Methoden" an der FH Wedel verwiesen.

Mit diesem Datenmodell wurde dann die VDM Class Library gefüttert, eine Art Generator, der aus dem Modell C- bzw. C++-Datentypen (auf Wunsch mit automatischer Speicherverwaltung) entwirft.

Um den Source-Code des VDM-Datenmodells für das TSP zu sehen, klicken sie hier.


1.5 Tcl/Tk

Bei Tcl/Tk handelt es sich um eine von John Ousterhout (Universitaet von Kalifornien in Berkeley) entwickelte interpretierende Programmiersprache, die ähnlich wie die bash oder die Skriptsprache Perl funktioniert. Es handelt sich dabei um ein Softwarepaket, das aus 2 Komponenten besteht. Zum einen gibt es die 'tclsh', die die shell fuer tcl darstellt, zum anderen kann die 'wish' benutzt werden, um X-Windows-Applikationen zu schreiben.

Der grosse Vorteil dieses Sprachsystemes ist es, daß eben diese beiden Shells vom Benutzer verändert werden können. Tcl/Tk erlaubt es, neue Befehle, die als C-Funktionen im mitgelieferten AppInit-Programm implementiert werden, in die shells zu integrieren. Genau diese Technik wurde benutzt, um den genetischen Algorithmus an Tcl/Tk anzubinden.


2. Das C++-Programm

Die obigen Ideen zum Algorithmus für die Problemlösung wurden in einem C++-Programm unter Verwendung der von der VDM Class Library erzeugten Datentypen umgesetzt.


2.1 Funktionen

Im folgenden folgt eine Auflistung der Funktionen bzw. Prozeduren inklusive einer kurzen Aufgabendefinition.

Für genauere Information sei auf die Inline-Dokumentation des Source-Codes verwiesen.

2.1.1 InitChromsom

Initialisiert ein Chromosom mit zufälligen Werten.

Wird aufgerufen von InitPopulation.

2.1.2 InitPopulation

Initialisiert die Anfangspopulation.

Wird aufgerufen von der Programmsteuerung.

2.1.3 InitTable

Initialisiert die Entfernungsmatrix.

Wird aufgerufen von der Programmsteuerung.

2.1.4 CalcPath

Berechnet anhand der Gene eines Chromosoms die korrekte Reiseroute.

Wird aufgerufen von GetBest, Vererbung und der Programmsteuerung.

2.1.5 CalcLength

Berechnet (nach der Ermittlung der Reiseroute) die Länge des Reiseweges.

Wird aufgerufen von GetBest, Vererbung und der Programmsteuerung.

2.1.6 GetBest

Sucht das beste Chromosom bzgl. der Fitneß aus einer Population heraus.

Wird aufgerufen von Vererbung und der Programmsteuerung.

2.1.7 SelectChromo

Wählt ein Chromosom nach einem bestimmten Verfahren für den nächsten Vererbungsmechanismus aus.

Wird aufgerufen von Vererbung.

2.1.8 Vererbung

Führt einen Vererbungschritt durch und erzeugt so eine neue Population.

Wird aufgerufen von der Programmsteuerung.

2.1.9 LoesungToString

Konvertiert die durch GetBest gefundene Lösung in einen String zur Übergabe an Tcl/Tk.

Wird aufgerufen von der Programmsteuerung.

2.1.10 Programmsteuerung

Die Programmsteuerung wird von dem Tcl/Tk-Programmteil aufgerufen und führt dann eine von drei möglichen Aktionen aus.


2.2 Source-Code

Um den Source-Code des C++-Teils zu sehen, klicken sie genau hier.



3. Das Tcl/Tk-Programm

3.1 Die Tcl/Tk-Source

Mit Tcl/Tk wurde die grafische Ausgabe der berechneten Ergebnisse und der Benutzerdialog implementiert. Fuer Interessierte kann der Progammcode in dem File 'tsp' eingesehen werden, wobei nachvollzogen werden kann, welche Window-Objekte wir benutzt haben. Als Literatur für den tieferen Einstieg seien hier besonders die Bücher aus dem Addison-Wesley Verlag empfohlen.


3.2 Integration neuer Funktionen in Tcl/Tk

Da wir mit der Tk-Shell arbeiten mußten, haben wir folgerichtig auch diese um die neuen Befehle erweitert und uns dann eine neue eigene shell erzeugt, und zwar die 'tspwish'. Um sich diese neue shell erzeugen zu können, nimmt man die bei Tcl/Tk mitgelieferte Datei 'tkAppInit.c' und führt neue Befehle mit dem TclCreateCommand ein. Hier kann man bestimmen, wie die Namen der Funktion im C-Programm und in der eigenen Window-Shell heißen sollen. Die zugehörige Funktion kann dann im AppInit-Programm implementiert werden. Anschließend wird durch das Compilieren des AppInit-Programms und des dazugehoerigen Linkens mit den tcl/tk-Libraries die neue individuelle Window-Shell erzeugt.

Diese kann dann genauso wie die Standard-wish vom Benutzer als Shell-Interpreter eingesetzt werden. Sie hat den gleichen Funktionsumfang wie die alte Shell nur eben jetzt erweitert um die eigenen C-Routinen


4. Benutzung des TSP-Programmpaketes

4.1 Installation des TSP-Programmes

Das TSP-Programm ist unter UNIX/Linux-Systemen lauffähig. Zur Installation werden die folgenden Dateien und Programme benötigt:


Fuer den Installationsablauf wird nachstehende Reihenfolge empfohlen:
(1) mit 'cd' in das home-Verzeichnis wechseln
(2) mit 'mkdir work' Arbeitsverzeichnis erstellen
(3) die Datei 'tsp.tgz' in das neu erstellte work-Verzeichnis kopieren
(4) der Entpack- und Entarchivierungsvorgang wird mit dieser Befehlszeile durchgefuehrt: 'tar -xzf tsp.tgz -C ~/work'
(5) Nach der Ausfuehrung sollten die nachfolgenden Dateien vorhanden sein:

Die brd25-Dateien und brd6-Dateien sind Beispieldaten mit jeweils 25 bzw. 6 Staedten in Deutschland.

(6) Erstellung der Windowshell: 'make'
(7) Installation der Programme in /usr/local/bin mit 'make INSTALL'
(8) Danach erfolgt der Start des TSP-Programms mit 'tsp'.

Sollte es bei der Erstellung der Windowshell einen reference-Fehler geben, so kann das Makefile mit 'make WITHDLL' gestartet werden.

Wenn das Programm wieder deinstalliert werden soll, muß einfach nur 'tspuninstall' eingegeben werden.


4.2 Benutzerführung für das TSP-Programm

Das TSP-Programm wird mit 'tsp' gestartet. Dem Benutzer präsentiert sich dann die Oberfläche mit dem Eingabefeld für die Punkte und dem nebenstehenden Informations- und Steuerrahmen.

Die Befehlseingaben erfolgen über die Menupunkte 'Datei' , 'Bearbeiten', 'Berechnung' und 'Parameter'.

Der Unterpunkt 'Laden ...' ermöglicht dem Benutzer, abgespeicherte Daten für das TSP erneut in den Speicher zu laden. Auswählbare Dateien werden in einer Listbox angezeigt, wobei per Doppelklick auf den entsprechenden Namen dieser ausgewählt wird. Mit Einfachklick auf den OK-Button wird das Laden aktiviert.

Das 'Speichern ...' erlaubt es, TSP-Daten unter einem bisherigen Namen oder einem neuen Namen zu sichern. Per Doppelklick kann wieder ein vorhandener Name in der Listbox ausgewählt werden. Einen neuen Namen kann der Benutzer in der Eingabezeile eingeben und mit dem Button 'Neuer Name' bestätigen. Mit 'OK' kann das Speichern abgeschlossen werden.

Das Programm wird über den Menupünkt 'Ende' verlassen.

Über den Unterpunkt 'Punkte einzeichnen ...' lassen sich die einzelnen Punkte für das TSP in dem linken Eingabequadrat mit der Maus eingeben. Ein Punkt wird durch Drücken der linken Maustaste gesetzt. Der Benutzer kann, wenn er einen Punkt ungenau gesetzt hat, diesen wieder zurücknehmen. Mit dem Button 'Gitternetz' wird ein Hilfsraster eingeblendet. Bei Betätigung des 'Fertig'-Buttons wird automatisch aufgrund der Bildschirmkoordinaten eine Entfernungsmatrix berechnet. Der Berechnungsvorgang kann jetzt gestartet werden.

Der Unterpunkt 'Punkte eingeben ...' ist eine Möglichkeit, die Bewertungszahlen, Punktekoordinaten und Punktenamen differenzierter zu behandeln. In einem 4x4-Ausschnitt können die Bewertungszahlen (z.B. Entfernungen, Kosten, ...) eingegeben werden. Mit einem Doppelklick auf die Punktenummer kann man dessen Bildschirmkoordinaten und den Namen des Punktes verändern. Durch Betätigen des Buttons 'Neuer Punkt' wird die Eingabematrix um einen zusätzlichen Punkt vergrößert.

Optimierungen können im Automatik- und im Einzelschrittmodus durchgeführt werden. Bei der Wahl des Unterpunktes 'Automatisch ...' wird eine Anzahl von Generationen (einstellbar unter 'Parameter->Einstellungen') berechnet und anschließend das Ergebnis angezeigt.

Der Benutzer kann durch 'Einzelschritte ...' die Optimierung schrittweise am Bildschirm verfolgen.

Bei der grafischen Anzeige wurde die erste Verbindungslinie vom Startpunkt gruen und die Verbindungslinie zum Endpunkt (=Strartpunkt) rot dargestellt.

Hinter dem Button 'Rundreise' verbigt sich eine Listbox, in der von oben nach unten die angefahrenen Punkte aufgeführt sind.

'Naechster Nachbar ...' liefert einen vom System vorgeschlagenen Vergleichswert. Dieser ergibt sich, indem ausgehend vom Startpunkt der nach dem gewählten Bewertungskriterium günstigste Nachbarpunkt angesteuert wird.

Hier kann der Bnutzer die für die Vererbung notwendigen Parameter eingeben. Wichtig zu beachten ist dabei, daß die Populationsgröße gleich der Summe der Reproduktionsrate, Mutationsrate, CO-Rate und Selektionsrate ist. Ferner können die Anzahl der Generationsdurchläufe für den Automatikmodus, die Größe des Gitternetzes und die physikalische Maßeinheit bestimmt werden.



5. Literatur