Die Manhattan-Distanz ist überschätzt und macht mich verrückt

Lesezeit: 5 Minuten

Benutzer-Avatar
Babak

Ich implementiere ein Sternalgorithmus mit Manhattan-Distanz die zu lösen 8-Puzzle (in C). Es scheint sehr gut zu funktionieren und besteht viele Unit-Tests, findet aber in einem Fall nicht den kürzesten Pfad (es findet 27 Schritte statt 25).

Wenn ich die heuristische Funktion auf ändere Hamming-Distanz es findet in 25 Schritten. Auch findet in 25 Schritten, wenn ich die Manhattan-Distanzfunktion mache, die Hälfte der eigentlichen Kosten zurück.

Deshalb glaube ich, dass das Problem irgendwo in der Manhattan-Entfernungsfunktion liegt und die Kosten überschätzt werden (daher unzulässig). Ich dachte, vielleicht läuft etwas anderes im C-Programm schief, also habe ich ein kleines Python-Skript geschrieben, um nur die Ausgabe der Manhattan-Distanzfunktion zu testen und zu verifizieren, und beide erzeugen genau das gleiche Ergebnis.

Ich bin wirklich verwirrt, weil die heuristische Funktion der einzige Fehlerpunkt zu sein scheint und gleichzeitig richtig zu sein scheint.

8-Puzzle-Startziel

Du kannst es versuchen dieser Löser und geben Sie die Kachelreihenfolge wie “2,6,1,0,7,8,3,5,4” ein. Wählen Sie den Algorithmus Manhattan-Distanz und es findet in 25 Schritten. Ändern Sie es jetzt in Manhattan-Distanz + linearer Konflikt und es findet 27 Schritte.

Aber meine Manhattan-Distanz (ohne linearen Konflikt) findet in 27 Schritten statt.

Hier ist mein allgemeiner Algorithmus:

manhattan_distance = 0
iterate over all tiles
if the tile is not the blank tile:
find the coordinates of this tile on the goal board
manhattan_distance += abs(x - goal_x) + abs(y - goal_y)

Ich denke, wenn mit einem wichtigen Teil etwas sehr falsch wäre, würde es nicht alle über 25 vorherigen Tests bestehen, also könnte dies eine Art Grenzfall sein.

Hier ist die kommentierte Manhattan-Distanzfunktion in C:

int ManhattanDistance(Puzzle p, State b){
   State goal = getFinalState(p);
   int size = getSize(b);
   int distance = 0;
   if (getSize(goal) == size){ // both states are the same size
      int i, j;
      for(i=0; i<size; i++){
         for(j=0; j<size; j++){ // iterate over all tiles
            int a = getStateValue(b, i, j); // what is the number on this tile?
            if (a != 'B'){ // if it's not the blank tile
               int final_cordinates[2];
               getTileCoords(goal, a, final_cordinates); // find the coordinates on the other board
               int final_i = final_cordinates[0];
               int final_j = final_cordinates[1];
               distance +=  abs(i - final_i) + abs(j - final_j);
            }
         }
      }
   }
   return distance;
}

Bitte hilf mir.

BEARBEITEN: Wie in den Kommentaren besprochen, kann der zum Öffnen von Knoten bereitgestellte Code gefunden werden hier

  • Ihre Manhattan-Distanzfunktion scheint mir in Ordnung zu sein.[well, at least from just reading it…] bist du sicher, dass es daran liegt? Vielleicht öffnet Ihre A * -Implementierung geschlossene Knoten nicht erneut, wenn sie einen kürzeren Pfad zu ihnen findet? das könnte erklären, warum dieser Fehler nicht immer auftritt.

    – amit

    24. Oktober 2011 um 13:13 Uhr

  • Beachten Sie auch, dass wenn size(goal) != size(b)geben Sie 0 zurück. Dies sollte sowieso nicht passieren, aber wenn Sie bereits nach dieser Situation suchen, möchten Sie vielleicht zurückgeben infinity stattdessen [since you cannot get to the target with non-matching board sizes]

    – amit

    24. Oktober 2011 um 13:21 Uhr


  • Es kann hilfreich sein, eine Ablaufverfolgung Ihrer Implementierung auf dieser bestimmten Instanz mit einer anderen Implementierung zu vergleichen (z code.google.com/p/a-star-algorithm-implementation). Zu sehen, wo sie divergieren, könnte Ihnen helfen, Ihren Fehler zu finden.

    – Nate Kohl

    24. Oktober 2011 um 13:37 Uhr

  • Ich stimme Amit zu, Ihre Funktion scheint mir in Ordnung zu sein. Das Problem liegt wahrscheinlich an einer anderen Stelle in Ihrem Code. Versuchen Sie, den kleinsten Fall zu finden, der Ihnen unerwartete Ergebnisse liefert, und debuggen Sie diesen (dh vergleichen Sie die erwarteten Zwischenergebnisse mit den tatsächlichen).

    – schick

    24. Oktober 2011 um 13:41 Uhr

  • @amit Ich habe diese if-Blöcke überprüft und das Programm erreicht diese nie, da die Kosten für den Umzug von einem Staat in einen anderen Staat immer 1 sind (im Gegensatz zu beispielsweise der Länge der Straßen zwischen Städten), sodass ein geschlossener Knoten nie wieder geöffnet werden muss denn je weiter Sie gehen, desto mehr steigen die Kosten bei jedem Schritt um 1, so dass es unmöglich ist, einen Knoten zu finden, den Sie zuvor gesehen haben und der weniger kostet als der aktuelle Zug.

    – Babak

    24. Oktober 2011 um 13:55 Uhr


Benutzer-Avatar
zustimmen

Das Problem scheint nicht in Ihrer heuristischen Funktion zu liegen, sondern im Algorithmus selbst. Aufgrund Ihrer Beschreibung des Problems und der Tatsache, dass es nur in einigen bestimmten Fällen auftritt, glaube ich, dass es mit dem erneuten Öffnen eines geschlossenen Scheitelpunkts zu tun hat, sobald Sie einen besseren Weg dorthin gefunden haben.

Beim Lesen des von Ihnen bereitgestellten Codes [in comments]ich glaube, ich habe verstanden, wo das Problem liegt, in Zeile 20:

if(getG(current) + 1 < getG(children[i])){

Das ist falsch! Sie prüfen, ob g(current) + 1 < g(children[i])möchten Sie eigentlich nach Folgendem suchen: f(current) + 1 + h(children[i]) < g(children[i])da Sie diesen Wert mit der heuristischen Funktion von überprüfen möchten children[i]und nicht von current!

Beachten Sie, dass es mit set identisch ist f(children[i]) = min{f(children[i]),f(current)+1}und dann hinzufügen h(children[i]) um das zu bekommen g Wert.

  • Danke, dass Sie diesen Code untersucht haben. Ich folge hier überhaupt nicht deiner Logik. f(aktuell) = g(aktuell) + h(aktuell) warum würden Sie sowohl h(aktuell) als auch h(Kinder) hinzufügen?[i]) zusammen und erwarten, dass es weniger als g(Kinder[i])? Wie Sie wissen, stellt jeder “h”-Wert die ungefähren Kosten von diesem Knoten bis zum Ziel dar. Schauen Sie sich auch den Algorithmus in an Wikipedia-Seite und dieser Teil gehört zu “tentative_g_score” in diesem Code, der gleich g_score ist[x] + dist_between(x,y) Ich verstehe nicht, was “h” hier macht?

    – Babak

    24. Oktober 2011 um 19:06 Uhr


1332980cookie-checkDie Manhattan-Distanz ist überschätzt und macht mich verrückt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy