Wir beschÀftigen uns mit dem Wellenfunktionskollapsalgorithmus


Seit dem Aufkommen von DeBroglie und Tessera wurde ich oft gebeten, zu erklÀren, wie sie funktionieren. Generieren mag wie Magie aussehen, aber die Regeln dahinter sind eigentlich einfach.

Was ist der WFC-Algorithmus (Wave Function Collapse)? Es wurde von Maxim Gumin entwickelt , um "gekachelte" Bilder basierend auf einer einfachen Konfiguration oder Bildbeispielen zu erstellen. Der Algorithmus kann viel: Schauen Sie sich die Beispiele von Maxim und Twitter #wavefunctioncollapse an und sehen Sie sich dieses Video an . Die Vielfalt ist unglaublich.


Maxim in README hat die Arbeit von WFC kurz erlĂ€utert, aber es scheint mir, dass dieses Problem von Grund auf eine detailliertere Offenlegung erfordert. Da sich der Algorithmus auf das Programmieren in EinschrĂ€nkungen bezieht, widmet sich der grĂ¶ĂŸte Teil des Artikels der ErlĂ€uterung des Konzepts des Programmierens in EinschrĂ€nkungen, und am Ende kehren wir zu WFC zurĂŒck .

EingeschrÀnkte Programmierung ist eine Möglichkeit, Computer anzuweisen. Im Gegensatz zur imperativen Programmierung, wenn Sie eine Liste expliziter Funktionen angeben, oder der funktionalen Programmierung, wenn Sie mathematische Funktionen angeben, geben Sie dem Computer hier eine strenge Beschreibung des Problems und verwenden die integrierten Algorithmen, um eine Lösung zu finden.

Hinweis:Dieses Handbuch beschreibt verschiedene Konzepte, nicht Methoden und Code. Wenn Sie mehr an der Implementierung interessiert sind, können Sie meine WFC-OpenSource-Bibliothek ( Github , Dokumentation ) verwenden. Obwohl es besser ist, mit der Implementierung von Maxim zu lernen . Wenn Sie Unity verwenden, können Sie Tessera kaufen . Dies ist mein Tool zum Anwenden von WFC in dieser Engine.

Mini Sudoku


Zur Veranschaulichung nahm ich ein Mini- Sudoku . Dies ist ein Puzzle, das wie ein 4 × 4-Raster mit Zahlen in einigen Zellen aussieht.


Ziel ist es, jede leere Zelle gemĂ€ĂŸ den Regeln mit einer Zahl von 1 bis 4 zu fĂŒllen:

  • Jede Zahl von 1 bis 4 muss in jeder Zeile in einer einzigen Kopie vorhanden sein.
  • Jede Zahl von 1 bis 4 muss in jeder Spalte in einer einzigen Kopie vorhanden sein.
  • Jede Zahl von 1 bis 4 muss in einer einzelnen Kopie in jedem 2 × 2-Eckquadrat vorhanden sein.

Nach diesen Regeln lautet die Lösung wie folgt:


Möglicherweise haben Sie dieses RĂ€tsel leicht gelöst. Wir sind jedoch daran interessiert, wie ein Computer dies tun kann. Das Problem kann in zwei Teile unterteilt werden: eine Beschreibung der Bedingungen fĂŒr den Computer und anschließend eine Lösung mithilfe des Algorithmus.

Beschreibung der Bedingungen


In der Regel wird hierfĂŒr eine Programmiersprache mit EinschrĂ€nkungen verwendet. Es gibt mehrere solcher Sprachen, und ihre Wirkprinzipien sind Ă€hnlich.

Zuerst definieren wir die Variablen . Hier sind sie nicht die gleichen wie bei der herkömmlichen Programmierung. Im Kontext eines Problemlösers ist eine Variable ein unbekannter Wert, der gelöst werden muss, um ein Problem zu lösen. In unserem Sudoku-Beispiel erstellen wir Variablen fĂŒr alle leeren Zellen. Zur Vereinfachung können Sie auch Variablen fĂŒr gefĂŒllte Zellen erstellen.

Dann definieren wir fĂŒr jede Variable eine DomĂ€ne : eine Reihe möglicher Werte. In unserem Sudoku ist die DomĂ€ne fĂŒr jede leere Zelle {1, 2, 3, 4}. Und fĂŒr eine Zelle, in die 1 bereits eingegeben wurde, ist die DomĂ€ne {1}.

Schließlich legen wir die EinschrĂ€nkungen fest: Regeln, die unsere Variablen binden. In den meisten Programmiersprachen gibt es bereits eine Funktion mit EinschrĂ€nkungen all_distinct(..), die eindeutige Werte ĂŒbergeben muss. So können Sudoku-Regeln in 12 EinschrĂ€nkungen ĂŒbersetzt werden all_distinct- eine fĂŒr jede Zeile und Spalte sowie fĂŒr 2 × 2 Eckquadrate. Wir benötigen nur eine Art von EinschrĂ€nkung, um dieses Problem zu lösen. Problemlöser zur ErfĂŒllung der EinschrĂ€nkungen werden jedoch normalerweise mit einer großen Bibliothek verschiedener Arten von EinschrĂ€nkungen geliefert, um Ihr Problem zu beschreiben.

Hinweis : In der Praxis unterstĂŒtzen Programmiersprachen Arrays in EinschrĂ€nkungen, sodass es genauere Möglichkeiten gibt, diese Aufgabe zu formulieren. Es gibt viele Artikel im Internet ĂŒber das Lösen von Sudoku.

Algorithmen zur Lösung von Problemen mit der EinschrÀnkungszufriedenheit


Es gibt verschiedene Lösungstechniken. Aber ich werde die einfachste von ihnen in Betracht ziehen, um Ihnen das Prinzip ihrer Arbeit zu demonstrieren. DomĂ€nen fĂŒr jede Zelle werden hier angezeigt:


Dies sind alles mögliche Werte in variablen DomÀnen.

Nehmen Sie nun die erste EinschrÀnkung. Es erfordert, dass alle Werte in der oberen Zeile eindeutig sind. In einer Zelle ist der Wert 4 bereits eingeschrieben, daher kann dieser Wert in anderen Zellen der Reihe nicht sein . Wir entfernen es aus den DomÀnen dieser Zellen.


Wiederholen Sie diesen Vorgang mit allen 12 EinschrÀnkungen. Dies wird als Weitergabe von EinschrÀnkungen bezeichnet , da Informationen durch EinschrÀnkungen von einer Variablen auf eine andere verteilt werden.


Und schauen Sie, wir haben Variablen, in deren DomĂ€nen noch ein Wert ĂŒbrig ist. Dies sollten die richtigen Lösungen fĂŒr diese Variablen sein.


Es scheint, dass wir noch mehr von der Verteilung der BeschrÀnkungen profitieren können: Die neuen roten Einheiten zeigen an, dass wir mit einer einzelnen DomÀne noch mehr Variablen haben werden, und dies wird auch zur Verteilung beitragen. Wiederholen Sie den Vorgang, bis das RÀtsel gelöst ist.


Wir erschweren die Aufgabe


Leider können nicht alle logischen RĂ€tsel so schnell gelöst werden. Hier ist ein großes Sudoku, es funktioniert genauso, außer dass wir jetzt 9 verschiedene Werte, 9 Zeilen, 9 Spalten und 9 3 × 3 Quadrate haben.


Wenn wir versuchen, die oben genannte Technik anzuwenden, bleiben wir stecken:


Jetzt sind alle EinschrÀnkungen gleich, aber es gibt immer noch undefinierte Variablen.

Eine Person wird dies entscheiden, aber ein Computeralgorithmus wird dies nicht können. Die HandbĂŒcher fĂŒr Menschen sagen, dass wir jetzt nach immer komplizierteren logischen Schlussfolgerungen suchen mĂŒssen. DafĂŒr benötigen wir jedoch keinen Computeralgorithmus, da dies schwierig ist. Wir benötigen jedoch einen universellen Algorithmus, der mit allen EinschrĂ€nkungen und nicht nur nach Sudoku-Regeln arbeiten kann.

Daher machen Computer das DĂŒmmste: Sie nehmen an . Zuerst zeichnen wir den aktuellen Status des Puzzles auf. Dann wĂ€hlen wir eine beliebige Variable aus und setzen sie auf einen der möglichen Werte. Angenommen, wir weisen der zentralen Zelle den Wert 1 zu.

Jetzt können wir die EinschrĂ€nkungen etwas weiter verbreiten. Folgendes habe ich fĂŒr die mittlere Spalte erhalten:


Die blauen Werte sind die Schlussfolgerungen, die wir nach der Annahme gezogen haben. Wie Sie sehen können, ist etwas passiert. Wir schreiben noch ein paar Variablen auf, schauen uns aber die mittlere obere Zelle an. Es ist leer: In seiner DomĂ€ne gibt es keine möglichen Werte, die die EinschrĂ€nkungen erfĂŒllen (es kann keine 5 geben, da dieser Wert bereits im selben 3 × 3-Quadrat vorhanden ist und alle anderen Zahlen bereits in dieser Spalte enthalten sind).

Wenn wir eine Variable mit einer leeren DomĂ€ne erhalten, bedeutet dies, dass wir ihr keinen Wert zuweisen können. Das heißt, das RĂ€tsel kann nicht gelöst werden. Es stellt sich heraus, dass unsere Annahme falsch war .

Angesichts eines solchen Widerspruchs fĂŒhren wir den RĂŒckgabesuchprozess durch(RĂŒckverfolgung). Zuerst stellen wir den Zustand wieder her, der vor unserer Annahme war. Dann entfernen wir den Wert, den wir als Annahme verwendet haben, aus der DomĂ€ne - es kann nicht mehr die richtige Antwort sein.


Es wurde viel Arbeit geleistet, aber sie sind vorwÀrts gegangen. Selbst nach dem Ausschluss von 1 aus der zentralen Zelle befinden wir uns jedoch immer noch in einem toten Punkt. Es ist Zeit, immer wieder und immer wieder davon auszugehen.

Hier gibt es nicht viele algorithmische Aktionen. Jedes Mal, wenn wir keine BeschrĂ€nkungen verteilen können, gehen wir davon aus und fahren fort. Und da Sie mehrmals stecken bleiben können, bevor Sie auf einen Widerspruch stoßen, werden Sie mehrere gespeicherte ZustĂ€nde und Annahmen ansammeln.

Bei jeder Iteration mit einer RĂŒckgabe reduzieren Sie die DomĂ€ne um mindestens eine Variable, sodass der Algorithmus trotz zahlreicher Rollbacks die Arbeit schließlich abschließt.

Dieses Thema ist viel umfangreicher als ich beschreibe. In der Praxis können Optimierungen wie die Auswahl von Annahmen, das VerstĂ€ndnis, wann verteilt werden muss und wann komplexere logische Schlussfolgerungen gezogen werden mĂŒssen, einen großen Einfluss auf die ProgrammausfĂŒhrung haben. Und da Probleme mit EinschrĂ€nkungen in der Regel exponentiell zunehmen, können Sie morgen oder nach 5000 Jahren eine Antwort erhalten.

Wir kehren zum Zusammenbruch der Wellenfunktion zurĂŒck


Der Zusammenbruch der Wellenfunktion ist eine schwierige Aufgabe mit einer EinschrĂ€nkung: Es gibt Tausende von möglichen Lösungen. Wenn wir zufĂ€llig Annahmen treffen , erhalten wir anstelle eines Lösers einen Generator . Gleichzeitig wird es weiterhin alle gegebenen EinschrĂ€nkungen erfĂŒllen, das heißt, es wird viel leichter zu handhaben sein als die meisten anderen Verfahrensgeneratoren.

Die Aufgabe des WFC-Algorithmus besteht darin, Zellen mit Kacheln zu fĂŒllen, damit die Bilder auf den Kacheln miteinander kombiniert werden. Innerhalb der oben verwendeten Terminologie ist jede Kachel ein Wert, jede Zelle ist eine Variable und die Regeln fĂŒr das Platzieren von Kacheln sind EinschrĂ€nkungen.

Maxim, der Autor von WFC, stellte fest, dass Sie bei einer angemessenen Auswahl an Kacheln und einer geeigneten Randomisierung selten Backtracking verwenden mĂŒssen, sodass dieses Verfahren nicht implementiert werden kann. Somit ist das Wesen von WFC wie folgt:

  • FĂŒr jede Zelle wird ein boolesches Array erstellt, das die DomĂ€ne dieser Variablen darstellt. DomĂ€nen enthalten einen Datensatz pro Kachel, und alle werden mit einem Wert initialisiert true. Eine Kachel betritt eine DomĂ€ne, wenn ihr Wert gleich ist true.
  • Gleichzeitig gibt es Zellen, in denen DomĂ€nen mehrere Elemente enthalten:
    • Auswahl einer Zufallszelle nach der heuristischen Methode der "geringsten Entropie".
    • WĂ€hlen Sie eine zufĂ€llige Kachel aus der ZelldomĂ€ne aus und entfernen Sie alle anderen Kacheln von dort.
    • Das Aktualisieren der DomĂ€nen anderer Zellen basierend auf diesen neuen Informationen ist die Ausbreitung der Zellrestriktion. Dies muss wiederholt erfolgen, da Änderungen in den Zellen weitere Konsequenzen haben können.

Hinweis : Meine Bedingungen unterscheiden sich von den Bedingungen von Maxim. Er nennt das Array von DomĂ€nen eine Welle, und die Auswahl einer zufĂ€lligen Kachel ist eine Beobachtung. Das heißt, es wird eine Analogie zur Quantenmechanik gezogen. Aber der Vergleich ist oberflĂ€chlich, deshalb werden wir ihn ignorieren.

Es gibt viele ErgÀnzungen zu den oben genannten Prinzipien, die dem Algorithmus Anmut und Leistung verleihen. Aber schauen wir uns zuerst die beschriebenen Schritte an.

Beispiel


Angenommen, wir mĂŒssen ein 3 x 3-Raster mit vier Arten von Kacheln fĂŒllen:


Die EinschrĂ€nkungen sind: Die Farben benachbarter Kacheln mĂŒssen ĂŒbereinstimmen.

Wie im Sudoku-Beispiel werde ich den Inhalt von DomĂ€nen mit monochromen Bildern veranschaulichen. Wenn nur noch ein Element in der DomĂ€ne vorhanden ist, vergrĂ¶ĂŸere ich es und zeige es in Farbe.

Erstens können in jeder Zelle Kacheln jeglicher Art lokalisiert werden:


FĂŒhren Sie die Haupt-WFC-Schleife aus. WĂ€hlen Sie zufĂ€llig eine Zelle aus, z. B. oben links. WĂ€hlen Sie nun eine Kachel in der DomĂ€ne aus und löschen Sie alle anderen.


Verteilen Sie die EinschrĂ€nkungen. Die einzige Regel gilt fĂŒr benachbarte Kacheln, daher mĂŒssen zwei Zellen aktualisiert werden:


Können wir andere Kacheln angesichts der schrumpfenden DomĂ€nen aktualisieren? Ja! Obwohl wir uns bei der Auswahl der ersten Kachel nicht sicher sind, sehen wir, dass die verbleibenden Optionen nach rechts fĂŒhren. Das heißt, einige Arten von Kacheln können nicht in die obere rechte Ecke gelegt werden. Gleiches gilt fĂŒr die untere linke Ecke.


Wir können die EinschrÀnkungen nicht mehr verteilen, daher wiederholen wir den Hauptzyklus: Zellauswahl, Kachelauswahl und Verteilung. Diesmal nehmen wir die obere mittlere Zelle:


Ein weiterer Zyklus: Nehmen Sie die linke mittlere Zelle. Nach der Proliferation von Restriktionen fĂŒr die zentrale Zelle bleibt ein möglicher Wert ĂŒbrig.


Im Allgemeinen verstehen Sie die Idee. Sie können den Rest der Zellen selbst ausfĂŒllen.

Wenn Sie mit einem komplexeren interaktiven Beispiel experimentieren möchten , empfehle ich dieses .

Kleinste Entropie


Bei der Auswahl der nĂ€chsten auszufĂŒllenden Zelle sind einige Optionen vorzuziehen. Wenn Sie zufĂ€llig aus einer beliebigen Stelle im Raster auswĂ€hlen, kann eine Situation auftreten, in der gleichzeitig verschiedene Bereiche des Rasters gefĂŒllt sind. Dies kann zu Problemen fĂŒhren: AbhĂ€ngig von den verfĂŒgbaren Kacheln können die gefĂŒllten Bereiche nicht verbunden werden. Es ist daher besser, Zellen auszuwĂ€hlen, bei denen es in Zukunft weniger wahrscheinlich ist, dass sie zu solchen Problemen fĂŒhren. Mit anderen Worten, Sie mĂŒssen Zellen mit der geringsten Anzahl möglicher Werte in der DomĂ€ne (jedoch nicht weniger als zwei Werte) verwenden:

  1. Höchstwahrscheinlich befinden sie sich neben den bereits gefĂŒllten Zellen.
  2. Wenn wir sie fĂŒr die Zukunft belassen, können Schwierigkeiten auftreten, da die verfĂŒgbaren Werte bereits gering sind.

Der kleinste DomĂ€nenansatz funktioniert gut, wenn alle Kacheln gleich wahrscheinlich sind. Wenn Sie jedoch aus einer gewichteten Zufallsverteilung auswĂ€hlen , mĂŒssen Sie etwas anderes berĂŒcksichtigen. Maxima empfiehlt "minimale Entropie", dh wĂ€hlen Sie eine Zelle, die minimiert:

entropy=—∑pilog(pi)


Dies ist eine Zusammenfassung der Kacheln in der DomĂ€ne, in der pi- Wahrscheinlichkeit fĂŒr diese Kachel.

Effizientes Rechnen


Obwohl ich nicht auf Details eingehen möchte, gibt es zwei Optimierungen, mit denen ich die Geschwindigkeit so stark erhöhen kann, dass sie nicht ignoriert werden können.

Da sich unsere einzige Regel auf benachbarte Kacheln bezieht, können wir nur die EinschrĂ€nkungen ĂŒberprĂŒfen, die zu Ergebnissen fĂŒhren können, die sich von den vorherigen unterscheiden. Das heißt, wenn eine Zelle aktualisiert wird, fĂŒgen wir sie der Warteschlange der Zellen hinzu, die auf eine Entscheidung warten. Dann entfernen wir eine Zelle aus der Warteschlange und ĂŒberprĂŒfen jedes Mal die benachbarten Zellen. Wenn solche ÜberprĂŒfungen zur Erneuerung anderer Zellen fĂŒhren, fallen sie ebenfalls in die Warteschlange. Wenn Sie diesen Vorgang wiederholen, bis die Warteschlange leer ist, stellen Sie sicher, dass alle EinschrĂ€nkungen ĂŒberprĂŒft werden. Wir ĂŒberprĂŒfen sie jedoch erst, wenn sich die DomĂ€ne mindestens einer Zelle Ă€ndert, die diesen EinschrĂ€nkungen zugeordnet ist.

Um die AdjazenzbeschrĂ€nkung zu ĂŒberprĂŒfen, mĂŒssen wir außerdem die Frage beantworten: "Welche Kacheln sind angesichts der Kacheln in der DomĂ€ne von Zelle A in der DomĂ€ne von Zelle B möglich, wenn die Zellen benachbart sind?"

Manchmal wird diese Frage als "UnterstĂŒtzung" von Zelle A bezeichnet. FĂŒr eine bestimmte Kachel "b" in DomĂ€ne B ist es einfach, die Zyklen fĂŒr Kacheln in DomĂ€ne A zu berechnen. Wenn A mindestens eine Kachel hat, die neben "b" platziert werden kann, dann "b" immer noch geeignet, zumindest fĂŒr das betreffende Fliesenpaar. Wenn es in A keine solche Kachel gibt, können Sie die Kachel "b" nicht aus DomĂ€ne B ablegen, und wir können sie verwerfen.

Schleifen machen es einfach, dies in Code zu implementieren, arbeiten jedoch extrem langsam. Und wenn wir Informationen in einer zusĂ€tzlichen Datenstruktur speichern, können wir die Frage bei Bedarf schnell beantworten. Die neuen Daten sind ein großes Array mit EintrĂ€gen fĂŒr jede Seite jeder Zelle und jeder Kachel. In unserem Beispiel gibt es 9 Zellen mit jeweils 4 Seiten und 4 Arten von Kacheln. Wir brauchen also 9 * 4 * 4 DatensĂ€tze. Wir speichern UnterstĂŒtzungszĂ€hler im Array: FĂŒr jede Zelle / Kachel / Seite zĂ€hlen wir die Anzahl der Kacheln in der benachbarten ZellendomĂ€ne, die neben der betreffenden Kachel platziert werden können. Wenn der ZĂ€hler auf Null fĂ€llt, kann dieses PlĂ€ttchen nicht gelegt werden, da niemand daneben stehen kann.

Algorithmuserweiterungen


Da WFC auf einem allgemeineren VerstĂ€ndnis von eingeschrĂ€nkten Problemen basiert, gibt es viele Möglichkeiten, den Algorithmus durch Ändern der verwendeten EinschrĂ€nkungen zu erweitern.

Eine der offensichtlichen Änderungen ist, dass uns niemand zwingt, quadratische Zellen zu verwenden. WFC eignet sich hervorragend fĂŒr hexagonale Zellen in drei Dimensionen oder noch ungewöhnlicheren OberflĂ€chen .




Sie können zusĂ€tzliche EinschrĂ€nkungen einfĂŒhren: Korrigieren Sie bestimmte Kacheln oder erstellen Sie „Module“ aus mehreren Zellen.

Die EinfĂŒhrung zusĂ€tzlicher BeschrĂ€nkungen kann aus praktischer Sicht eine sehr wichtige Rolle spielen. Da WFC nur benachbarte Kacheln begrenzt, werden selten große Strukturen erzeugt, die ein hohes Maß an HomogenitĂ€t bieten und ungewöhnlich aussehen. Dieser Algorithmus funktioniert am besten bei der Auswahl von Kacheln. Um jedoch mit einigen großen Strukturen zu arbeiten, ist es besser, eine andere Technik zu verwenden oder andere EinschrĂ€nkungen einzufĂŒhren.

In einem anderen Artikel habe ich darĂŒber gesprochen, wie Sie mit WFC die besten Ergebnisse erzielen können.

Überlappende WFC


Eine der interessanten Erweiterungen des Algorithmus ist der "ĂŒberlappende" WFC. In den obigen Beispielen bezog sich die HauptbeschrĂ€nkung auf Paare benachbarter Kacheln. Dies reicht aus, um die Verbindung von Linien sicherzustellen und einfache Strukturen wie Höhlen, RĂ€ume usw. zu schaffen. Gleichzeitig gehen jedoch viele Informationen verloren. Wenn wir zum Beispiel brauchen, dass rote Kacheln immer neben blauen liegen, aber nie neben ihnen waren, wird es schwierig sein, dies allein in Bezug auf die NĂ€he auszudrĂŒcken.

Maxim schlug das Konzept der Überlappung von WFC vor: Wir ersetzen die Adjazenzbedingung durch eine neue EinschrĂ€nkung, die mehrere Kacheln gleichzeitig betrifft. Zum Beispiel, so dass am Ausgang jede Gruppe von 3 × 3-Zellen einer 3 × 3-Gruppe aus einer Gitterprobe entspricht. Die in der Probe vorhandenen Muster werden am Ausgang immer wieder in verschiedenen Variationen wiederholt:


Diese EinschrĂ€nkung ist viel empfindlicher als "einfache" AdjazenzbeschrĂ€nkungen. Und da es von einer bestimmten Stichprobe abhĂ€ngt, eignet es sich sehr gut zur Lösung kĂŒnstlerischer Aufgaben. Bisher bin ich auf nichts so Interessantes gestoßen. Vielleicht liegt der Grund darin, dass ein solcher Algorithmus schwieriger zu implementieren ist oder langsamer arbeitet oder manchmal die ursprĂŒngliche Probe zu gut reproduziert, was dazu fĂŒhrt, dass eine Art von NatĂŒrlichkeit und NatĂŒrlichkeit verloren geht.

Was weiter?


Das Lösen von Problemen mit EinschrĂ€nkungen ist ein großes und sich aktiv entwickelndes Gebiet der Informatik, und ich habe es nur angesprochen. WFC ist - genau wie jeder andere Algorithmus zur prozeduralen Generierung zur Lösung eingeschrĂ€nkter Probleme - noch neu. Ich empfehle, r / procedureuralgeneration , #wavefunctioncollapse , @exutumno und @osksta zu lesen , um sich ein Bild von den jĂŒngsten AnwendungsfĂ€llen zu machen.

Sie können auch meinen Artikel ĂŒber WFC lesen , mit meiner OpenSource-Bibliothek oder dem Unity-Tool experimentieren . Vergessen Sie nicht meine anderen Artikel zur Verfahrensgenerierung .

All Articles