Das Problem des reisenden Verkäufers in Java

1. Einführung

In diesem Lernprogramm lernen Sie den Algorithmus für simuliertes Annealing kennen und zeigen die Beispielimplementierung basierend auf dem Traveling Salesman Problem (TSP).

2. Simuliertes Glühen

Der Simulated Annealing-Algorithmus ist eine Heuristik, um Probleme mit einem großen Suchraum zu lösen.

Die Inspiration und der Name kamen vom Glühen in der Metallurgie; Es ist eine Technik, bei der ein Material erhitzt und kontrolliert abgekühlt wird.

Im Allgemeinen verringert das simulierte Glühen die Wahrscheinlichkeit, dass schlechtere Lösungen angenommen werden, wenn der Lösungsraum erkundet wird, und senkt die Temperatur des Systems. Das folgende https://commons.wikimedia.org/wiki/File:Hill Climbing with Simulated Annealing.gif[animation]zeigt den Mechanismus der Suche nach der besten Lösung mit dem Simulated Annealing-Algorithmus:

Wie wir sehen können, verwendet der Algorithmus einen breiteren Lösungsbereich mit hoher Systemtemperatur und sucht nach einem globalen Optimum. Beim Absenken der Temperatur wird der Suchbereich kleiner, bis das globale Optimum gefunden wird.

Der Algorithmus hat einige Parameter, mit denen gearbeitet werden kann:

  • Anzahl der Iterationen - Stoppbedingung für Simulationen

  • Anfangstemperatur - die Startenergie des Systems

  • Kühlrate - der Prozentsatz, um den der Wert reduziert wird

Temperatur des Systems ** Mindesttemperatur - optionale Stoppbedingung

  • Simulationszeit - optionale Stoppbedingung

Die Werte dieser Parameter müssen sorgfältig ausgewählt werden, da sie die Leistung des Prozesses erheblich beeinflussen können.

3. Reisender Verkäufer Problem

Das Traveling Salesman Problem (TSP) ist das bekannteste Problem der Informatik-Optimierung in einer modernen Welt.

In einfachen Worten ist es ein Problem, eine optimale Route zwischen Knoten im Graphen zu finden. Die Gesamtfahrstrecke kann eines der Optimierungskriterien sein. Weitere Informationen zu TSP finden Sie unter https://simple.wikipedia.org/wiki/Travelling salesman problem[hier].

4. Java-Modell

Um das TSP-Problem zu lösen, benötigen wir zwei Modellklassen, nämlich City und Travel . Im ersten werden die Koordinaten der Knoten im Diagramm gespeichert:

@Data
public class City {

    private int x;
    private int y;

    public City() {
        this.x = (int) (Math.random() **  500);
        this.y = (int) (Math.random() **  500);
    }

    public double distanceToCity(City city) {
        int x = Math.abs(getX() - city.getX());
        int y = Math.abs(getY() - city.getY());
        return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    }

}

Der Konstruktor der City -Klasse ermöglicht es uns, zufällige Orte der Städte zu erstellen. Die distanceToCity (..) -Logik ist für Berechnungen bezüglich der Entfernung zwischen den Städten verantwortlich.

Der folgende Code ist für die Modellierung einer Verkaufsreisetour verantwortlich. Beginnen wir mit der Generierung der ersten Reihenfolge der Städte auf Reisen:

public void generateInitialTravel() {
    if (travel.isEmpty())
        new Travel(10);
    Collections.shuffle(travel);
}

Zusätzlich zur Generierung der Anfangsreihenfolge benötigen wir die Methoden, um die zwei zufälligen Städte in der Reisereihenfolge auszutauschen. Wir werden damit nach den besseren Lösungen innerhalb des Algorithmus für simuliertes Annealing suchen:

public void swapCities() {
    int a = generateRandomIndex();
    int b = generateRandomIndex();
    previousTravel = travel;
    City x = travel.get(a);
    City y = travel.get(b);
    travel.set(a, y);
    travel.set(b, x);
}

Außerdem benötigen wir eine Methode, um die Swap-Generierung im vorherigen Schritt rückgängig zu machen, falls die neue Lösung von unserem Algorithmus nicht akzeptiert wird:

public void revertSwap() {
    travel = previousTravel;
}

Die letzte Methode, die wir behandeln wollen, ist die Berechnung der gesamten Fahrstrecke, die als Optimierungskriterium verwendet wird:

public int getDistance() {
    int distance = 0;
    for (int index = 0; index < travel.size(); index++) {
        City starting = getCity(index);
        City destination;
        if (index + 1 < travel.size()) {
            destination = getCity(index + 1);
        } else {
            destination = getCity(0);
        }
            distance += starting.distanceToCity(destination);
    }
    return distance;
}

Konzentrieren wir uns nun auf den Hauptteil, die Implementierung des Algorithmus für simuliertes Annealing.

5. Simulierte Glüh-Implementierung

In der folgenden Implementierung von Simulated Annealing lösen wir das TSP-Problem. Nur eine kurze Erinnerung: Ziel ist es, die kürzeste Entfernung zu allen Städten zu finden.

Um den Prozess zu starten, müssen wir drei Hauptparameter angeben, nämlich startingTemperature , numberOfIterations und coolingRate :

public double simulateAnnealing(double startingTemperature,
  int numberOfIterations, double coolingRate) {
    double t = startingTemperature;
    travel.generateInitialTravel();
    double bestDistance = travel.getDistance();

    Travel currentSolution = travel;
   //...
}

Vor dem Start der Simulation erstellen wir eine erste (zufällige) Reihenfolge der Städte und berechnen die Gesamtstrecke für die Fahrt. Da dies die erste berechnete Entfernung ist, speichern wir sie zusammen mit currentSolution in der Variablen bestDistance__.

Im nächsten Schritt starten wir eine Hauptsimulationsschleife:

for (int i = 0; i < numberOfIterations; i++) {
    if (t > 0.1) {
       //...
    } else {
        continue;
    }
}

Die Schleife hält die Anzahl der von uns angegebenen Iterationen. Darüber hinaus haben wir eine Bedingung hinzugefügt, um die Simulation zu stoppen, wenn die Temperatur niedriger oder gleich 0,1 ist. Dadurch sparen wir Zeit für Simulationen, da bei niedrigen Temperaturen die Optimierungsunterschiede fast nicht sichtbar sind.

Schauen wir uns die Hauptlogik des Simulated Annealing-Algorithmus an:

currentSolution.swapCities();
double currentDistance = currentSolution.getDistance();
if (currentDistance < bestDistance) {
    bestDistance = currentDistance;
} else if (Math.exp((bestDistance - currentDistance)/t) < Math.random()) {
    currentSolution.revertSwap();
}

In jedem Simulationsschritt tauschen wir zufällig zwei Städte in der Reisereihenfolge aus.

Außerdem berechnen wir den currentDistance . Wenn der neu berechnete currentDistance niedriger als bestDistance ist, speichern wir ihn als den besten.

Andernfalls prüfen wir, ob die Boltzmann-Funktion der Wahrscheinlichkeitsverteilung niedriger ist als der zufällig gewählte Wert in einem Bereich von 0-1. Wenn ja, machen wir den Tausch der Städte rückgängig. Wenn nicht, behalten wir die neue Ordnung der Städte bei, da sie uns dabei helfen können, die lokalen Minima zu vermeiden.

Schließlich reduzieren wir in jedem Schritt der Simulation die Temperatur um den angegebenen coolingRate:

t ** = coolingRate;

Nach der Simulation geben wir die beste Lösung zurück, die wir mit Simulated Annealing gefunden haben.

  • Bitte beachten Sie die wenigen Tipps zur Wahl der besten Simulationsparameter: **

  • Für kleine Lösungsräume ist es besser, den Start zu verringern

Temperatur und erhöhen Sie die Abkühlgeschwindigkeit, da es die reduziert Simulationszeit, ohne an Qualität zu verlieren ** Für größere Lösungsräume wählen Sie bitte den höheren Start

Temperatur und kleine Abkühlgeschwindigkeit, da es mehr lokale Minima gibt ** Stellen Sie immer genügend Zeit zur Verfügung, um von hoch nach niedrig zu simulieren

Temperatur des Systems

Vergessen Sie nicht, etwas Zeit mit dem Algorithmus zu verbringen, der mit der kleineren Probleminstanz optimiert wird, bevor Sie mit den Hauptsimulationen beginnen, da dies die Endergebnisse verbessern wird. Die Abstimmung des Algorithmus für simuliertes Annealing wurde zum Beispiel in diesem Artikel https://www.researchgate.net/publication/269268529 Simulated Annealing algorithm for optimization of elastic optical networks with unicast and anycast traffic gezeigt.

6. Fazit

In diesem kurzen Tutorial konnten wir etwas über den Simulated Annealing-Algorithmus lernen und das Problem des reisenden Verkäufers lösen .

Dies zeigt hoffentlich, wie praktisch dieser einfache Algorithmus ist, wenn er auf bestimmte Arten von Optimierungsproblemen angewendet wird.

Die vollständige Implementierung dieses Artikels finden Sie unter über GitHub .