Synonymketten - Effizienter Routing-Algorithmus für iOS / SQLite - IOS, Algorithmus, SQLite, Traveling-Salesman, Thesaurus

EIN Synonymkette ist eine Reihe eng verwandter Wörter, die sich über zwei Anker erstrecken. Zum Beispiel können die englischen Wörter "schwarz" und "weiß" verbunden sein als:

schwarz-dunkel-obskur-versteckt-versteckt-gemütlich-bequem-einfach-einfach-rein-Weiß

Oder, hier ist "wahr" und "falsch":

wahr-just = fair = schön = hübsch-kunstvoll-künstlich-scham-falsch

Ich arbeite an einer Thesaurus-iOS-App, und das würde ich tungerne auch Synonymketten anzeigen. Das Ziel besteht darin, eine Kette innerhalb eines gewichteten Graphs von Wortbeziehungen zurückzugeben. Meine Quelle ist ein sehr großer Thesaurus mit gewichteten Daten, wobei die Gewichte die Ähnlichkeit zwischen Wörtern messen. (z. B. "Outlaw" ist eng mit "Bandit" verwandt, aber entfernter mit "Rogue" verwandt.) Unsere tatsächlichen Werte reichen von 0,001 bis ~ 50, aber Sie können jeden Gewichtsbereich annehmen.

Welche Optimierungsstrategien empfehlen Sie?B. innerhalb von 5 Sekunden nach der Verarbeitung auf einem typischen iOS-Gerät? Nehmen wir an, der Thesaurus hat eine halbe Million Begriffe mit jeweils 20 Assoziationen. Ich bin mir sicher, dass es eine Menge früherer Untersuchungen zu solchen Problemen gibt, und ich würde gerne Hinweise darauf hören, was darauf angewendet werden könnte.

Mein aktueller Algorithmus beinhaltet rekursivAbsteigend ein paar Ebenen von den Start- und Endwörtern und dann nach abfangenden Wörtern suchen, aber das wird zu langsam mit Tausenden von SQLite (oder Realm) wählt.

Antworten:

2 für die Antwort № 1

Da du gesagt hast, deine Quelle sei ein großer ThesaurusBei gewichteten Daten nehme ich an, wenn Sie ein beliebiges Wort auswählen, haben Sie das Gewicht für seinen Nachfolger im Ähnlichkeitsgraphen. Ich werde immer die folgende Reihenfolge verwenden, wenn ich ein Beispiel gebe:

schwarz-dunkel-obskur-versteckt-versteckt-gemütlich-bequem-einfach-einfach-rein-weiß

Stellen wir uns die Wörter als einen Knotenpunkt vorGraph, jede Ähnlichkeitsbeziehung, die ein Wort mit einem anderen hat, ist ein Pfad auf diesem Graphen. Jeder Pfad wird mit Kosten gewichtet. Dies entspricht der Gewichtung der Quelldatei. Die beste Lösung, um einen Pfad von einem Wort zum anderen zu finden, ist die Verwendung des EIN* (Ein Stern) Pfad finden.

Ich verwende die minimalen "Kosten", um von a zu reisenWort zu seinem Nachfolger zu 1. Sie können es entsprechend anpassen. Zuerst benötigen Sie eine gute heuristische Funktion, da dies ein Greedy-Algorithmus ist. Diese heuristische Funktion wird die "gierige" Entfernung zwischen zwei Wörtern, beliebigen Wörtern, zurückgeben. Sie müssen die Tatsache respektieren, dass die "Entfernung", die es zurückgibt, niemals größer sein kann als der tatsächliche Abstand zwischen den beiden Wörtern. Da ich keine Beziehung zwischen irgendwelchen Wörtern für einen Thesaurus kenne, gibt meine heuristische Funktion immer die Mindestkosten zurück. Mit anderen Worten, es wird immer sagen, dass ein Wort das ähnlichste Wort zu jedem anderen ist. Zum Beispiel meine Heuristik Funktion sagt mir das "schwarz" ist das beste Synonym für "Weiß".

Sie müssen die heuristische Funktion einstellen, wenn Sie können, so wird es mit genaueren Abständen reagieren, wodurch der Algorithmus schneller läuft. Das ist der schwierige Teil, denke ich.

Sie können den Pseudo-Code für den Algorithmus in dem von mir gesendeten Wikipedia-Artikel sehen. Aber hier ist es für eine schnellere Erklärung:

function A*(start,goal)
closedset := the empty set    -- The set of nodes already evaluated.
openset := {start}    -- The set of tentative nodes to be evaluated, initially containing the start node
came_from := the empty map    -- The map of navigated nodes.

g_score[start] := 0    -- Cost from start along best known path.
-- Estimated total cost from start to goal through y.
f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)

while openset is not empty
current := the node in openset having the lowest f_score[] value
if current = goal
return reconstruct_path(came_from, goal)

remove current from openset
add current to closedset
for each neighbor in neighbor_nodes(current)
if neighbor in closedset
continue
tentative_g_score := g_score[current] + dist_between(current,neighbor)

if neighbor not in openset or tentative_g_score < g_score[neighbor]
came_from[neighbor] := current
g_score[neighbor] := tentative_g_score
f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)
if neighbor not in openset
add neighbor to openset

return failure

function reconstruct_path(came_from,current)
total_path := [current]
while current in came_from:
current := came_from[current]
total_path.append(current)
return total_path

Nun, für den Algorithmus haben Sie 2 Arrays vonKnoten, die Sie besuchen (geöffnet) und diejenigen, die Sie bereits besucht haben (geschlossen). Sie haben auch zwei Reihen von Entfernungen für jeden Knoten, die Sie vervollständigen werden, während Sie durch den Graphen fahren.

Ein Array (g_score) wird Ihnen die tatsächlich niedrigste zurückgelegte Entfernung zwischen dem Startknoten und dem angegebenen Knoten mitteilen. Beispielsweise, g_score ["versteckt"] gibt die niedrigsten gewichteten Kosten für die Reise zurück "schwarz" zu "versteckt".

Das andere Array (f_score) wird Ihnen die angenommene Entfernung zwischen dem von Ihnen angegebenen Knoten und dem Ziel mitteilen, das Sie erreichen möchten. Zum Beispiel gibt f_score ["gemütlich"] die angenommenen gewichteten Kosten zurück, von denen aus gefahren werden soll "gemütlich" zu "Weiß" Verwenden der heuristischen Funktion. Denken Sie daran, dass diese Kosten immer weniger oder gleich den tatsächlichen Kosten sind, um zwischen Wörtern zu reisen, da unsere heuristische Funktion die oben genannte Regel einhalten muss.

Wenn der Algorithmus ausgeführt wird, reisen Sie vonVon Knoten zu Knoten, beginnend mit dem Startwort, speichern Sie alle Knoten, die Sie zurückgelegt haben, und die Kosten, die Sie für die Reise "verbraucht" haben. Sie werden den gefahrenen Weg ersetzen, wenn Sie bessere Kosten für die Fahrt auf dem Weg finden g_score Array. Du wirst das benutzen f_score um vorherzusagen, welcher Knoten am besten zuerst besucht wird, aus dem Array von "nicht besuchten" Knoten. Es ist am besten, wenn Sie Ihre speichern f_score Als ein minimaler Haufen.

Sie werden den Algorithmus beenden, wenn Sie den Knoten findendas ist das Ziel, das du willst. Dann rekonstruieren Sie den minimalen Pfad mit dem Array der besuchten Knoten, die Sie bei jeder Iteration gespeichert haben. Eine andere Möglichkeit, den Algorithmus zu stoppen, ist, wenn er alle Nachbarknoten besucht und das Ziel nicht gefunden hat. Wenn dies geschieht, kann man sagen, dass es keinen Weg vom Startknoten zum Ziel gibt.

Dieser Algorithmus wird am häufigsten bei Spielen verwendetder bessere Weg zwischen zwei Objekten in einer 3D-Welt. Um es zu verbessern, müssen Sie nur eine bessere heuristische Funktion erstellen, die es dem Algorithmus ermöglicht, die besseren Knoten zuerst zu finden und schneller zum Ziel zu bringen.

- 7f


Verwandte Fragen
Speisekarte