Kann ich wandelbare Algorithmen immer in Einzelzuweisungen umwandeln und trotzdem effizient sein?

8

Der Kontext

Der Kontext dieser Frage ist, dass ich mit Gen Expression Programming (GEP), einer Form von evolutionärer Algorithmus, mit Erlang . GEP verwendet ein string-basiertes DSL mit der Bezeichnung Karva-Notation . Die Karva-Notation lässt sich leicht in Ausdrucksstrukturen umwandeln, aber der Übersetzungsalgorithmus geht von einer Implementierung mit veränderbaren Objekten aus: unvollständig Sub-Ausdrücke werden zu einem frühen Zeitpunkt des Übersetzungsprozesses erstellt und ihre eigenen Unter-Ausdrücke werden später mit Werten gefüllt, die zum Zeitpunkt der Erstellung nicht bekannt waren.

Der Zweck der Karva-Notation besteht darin, dass sie garantiert, dass syntaktisch korrekte Ausdrücke ohne teure Codierungstechniken oder Korrekturen des genetischen Codes erzeugt werden. Das Problem ist, dass ich mit einer Single-Assignment-Programmiersprache wie Erlang den Ausdruck neu erstellen muss tree kontinuierlich, wenn jeder Sub-Ausdruck ausgefüllt wird. Dies braucht ein preiswertes - O (n)? - Aktualisiere die Operation und konvertiere sie in eine, die in exponentieller Zeit vervollständigt werden würde (sofern ich mich nicht irre). Wenn ich keinen effizienten funktionalen Algorithmus finde, um K-Ausdrücke in Ausdrucksbäume umzuwandeln, dann ist eine der überzeugenden Eigenschaften von GEP verloren.

Die Frage

Ich schätze, dass das K-Ausdruck-Übersetzungsproblem ziemlich unklar ist, also was ich will, ist Rat, wie man einen inhärent nicht-funktionalen Algorithmus (der mutierbare Datenstrukturen ausnutzt) in einen, der das nicht tut, umwandelt. Wie passen reine funktionale Programmiersprachen viele der Algorithmen und Datenstrukturen, die in den frühen Tagen der Informatik produziert wurden, die von der Wandlungsfähigkeit abhängen, um die Leistungsmerkmale zu erhalten, die sie brauchen?

    
Andrew Matthews 30.07.2011, 12:08
quelle

4 Antworten

8
___ answer6963984 ___

Es gibt keinen einzigen Weg dies zu tun, es muss wirklich von Fall zu Fall versucht werden. Ich versuche normalerweise, sie in einfachere Operationen zu zerlegen, zu falten und zu entfalten und dann von dort zu optimieren. Der Karva-Dekodierungsfall ist, wie andere bemerkt haben, ein Breitenbaum, und ich habe mit treeUnfoldM_BF begonnen. Vielleicht gibt es ähnliche Funktionen in Erlang.

Wenn die Dekodieroperation unangemessen teuer ist, könnten Sie die Dekodierung memotisieren und Subbäume teilen / wiederverwenden ... obwohl es wahrscheinlich nicht in einen generischen Tree-Unfold passt und Sie dazu spezielle Funktionen schreiben müssten. Wenn die Fitnessfunktion langsam genug ist, kann es gut sein, einen naiven Decoder wie den unten aufgeführten zu verwenden. Es wird den Baum jeden Aufruf vollständig wiederherstellen.

%Vor%     
___ qstntxt ___

Der Kontext

Der Kontext dieser Frage ist, dass ich mit Gen Expression Programming (GEP), einer Form von evolutionärer Algorithmus, mit Erlang . GEP verwendet ein string-basiertes DSL mit der Bezeichnung Karva-Notation . Die Karva-Notation lässt sich leicht in Ausdrucksstrukturen umwandeln, aber der Übersetzungsalgorithmus geht von einer Implementierung mit veränderbaren Objekten aus: unvollständig Sub-Ausdrücke werden zu einem frühen Zeitpunkt des Übersetzungsprozesses erstellt und ihre eigenen Unter-Ausdrücke werden später mit Werten gefüllt, die zum Zeitpunkt der Erstellung nicht bekannt waren.

Der Zweck der Karva-Notation besteht darin, dass sie garantiert, dass syntaktisch korrekte Ausdrücke ohne teure Codierungstechniken oder Korrekturen des genetischen Codes erzeugt werden. Das Problem ist, dass ich mit einer Single-Assignment-Programmiersprache wie Erlang den Ausdruck neu erstellen muss tree kontinuierlich, wenn jeder Sub-Ausdruck ausgefüllt wird. Dies braucht ein preiswertes - O (n)? - Aktualisiere die Operation und konvertiere sie in eine, die in exponentieller Zeit vervollständigt werden würde (sofern ich mich nicht irre). Wenn ich keinen effizienten funktionalen Algorithmus finde, um K-Ausdrücke in Ausdrucksbäume umzuwandeln, dann ist eine der überzeugenden Eigenschaften von GEP verloren.

Die Frage

Ich schätze, dass das K-Ausdruck-Übersetzungsproblem ziemlich unklar ist, also was ich will, ist Rat, wie man einen inhärent nicht-funktionalen Algorithmus (der mutierbare Datenstrukturen ausnutzt) in einen, der das nicht tut, umwandelt. Wie passen reine funktionale Programmiersprachen viele der Algorithmen und Datenstrukturen, die in den frühen Tagen der Informatik produziert wurden, die von der Wandlungsfähigkeit abhängen, um die Leistungsmerkmale zu erhalten, die sie brauchen?

    
___ answer6883613 ___

Ich denke, ich habe herausgefunden, wie Sie Ihr spezielles Problem mit den K-Bäumen lösen können (das allgemeine Problem ist zu schwer: P). Meine Lösung wird in einem schrecklichen hybriden Python-ähnlichen psudocode dargestellt (ich bin heute sehr langsam auf meinem FP) aber ändert keinen Knoten, nachdem du einen erstellt hast (der Trick besteht darin, den Baum zu erstellen) von unten nach oben)

Zuerst müssen wir herausfinden, welche Knoten zu welcher Ebene gehören:

%Vor%

Also in Data.Tree , das sollte Ihnen data Tree a = Node {rootLabel :: a, subForest :: Forest a} geben. Jetzt können Sie dies in einen Baum von unten umwandeln:

%Vor%

Ich bin mir ziemlich sicher, dass wir das jetzt sehr einfach in die Einzelaufgabe Erlang / Haskell umwandeln können.

    
___ answer6883410 ___

Es gibt eine Reihe von Lösungen, wenn ein veränderbarer Zustand in der funktionalen Programmierung erforderlich ist.

  1. Verwenden Sie einen anderen Algorithmus, der das gleiche Problem löst. Z.B. Quicksort wird allgemein als veränderbar angesehen und kann daher in einer funktionalen Umgebung weniger nützlich sein, aber Mergesort ist im Allgemeinen besser für eine funktionale Einstellung geeignet. Ich kann nicht sagen, ob diese Option in Ihrem Fall möglich oder sinnvoll ist.

  2. Sogar funktionale Programmiersprachen bieten normalerweise eine Möglichkeit, den Status zu ändern. ( Dieser Blog Beitrag scheint zu zeigen, wie man es in Erlang macht. ) Für einige Algorithmen und Datenstrukturen ist dies in der Tat die einzige verfügbare Option (es gibt aktive Forschung zu dem Thema, denke ich); Zum Beispiel werden Hash-Tabellen in funktionalen Programmiersprachen im Allgemeinen mit veränderbarem Zustand implementiert.

In Ihrem Fall bin ich mir nicht sicher, ob die Unveränderlichkeit wirklich zu einem Performance-Engpass führt. Sie haben recht, der (Sub-) Baum wird bei der Aktualisierung neu erstellt, aber die Erlang-Implementierung wird wahrscheinlich alle Teilbäume wiederverwenden, die sich nicht geändert haben, was zu O (log n) -Komplexität pro Update anstelle von O (1) mit veränderbarem Zustand führt . Außerdem werden die Knoten der Bäume nicht kopiert, sondern die Referenzen auf die Knoten, die relativ effizient sein sollten. Sie können über Baumaktualisierungen in einer funktionalen Einstellung in z.B. die Dissertation von Okasaki oder in seinem Buch "Purely Functional Data Structures" basierend auf der These. Ich würde versuchen, den Algorithmus mit einer unveränderlichen Datenstruktur zu implementieren und zu einem veränderbaren zu wechseln, wenn Sie ein Leistungsproblem haben.

Siehe auch einige relevante SO-Fragen hier und here .

    
___ tag123computerscience ___ Informatik (CS) ist die Wissenschaft hinter der Programmierung. Es ist das Studium der theoretischen Grundlagen von Information und Berechnung und praktischer Techniken für deren Implementierung und Anwendung in Computersystemen. ___ tag123algorithm ___ Ein Algorithmus ist eine Folge wohldefinierter Schritte, die eine abstrakte Lösung für ein Problem definieren. Verwenden Sie dieses Tag, wenn sich Ihr Problem auf den Algorithmusentwurf bezieht. ___ tag123funktionale Programmierung ___ Funktionale Programmierung ist ein Programmierparadigma, das auf der Erzeugung von Abstraktionen unter Verwendung von Funktionen basiert, die Nebeneffekte und Zustandsänderungen vermeidet. Reine funktionale Programmierung ist threadsicher. ___ tag123evolutionaryalgorithm ___ Evolutionäre Algorithmen (EAs) sind inspiriert vom biologischen Modell der Evolution und der natürlichen Selektion. In der natürlichen Welt hilft die Evolution den Arten, sich an ihre Umwelt anzupassen. Evolutionäre Algorithmen basieren auf einem vereinfachten Modell dieser biologischen Evolution. Um ein bestimmtes Problem zu lösen, schaffen wir eine Umgebung, in der sich mögliche Lösungen entwickeln können. Die Umwelt ist von den Parametern des Problems geprägt und fördert die Evolution des Guten ___ tag123mutable ___ Ein veränderbares Element kann nach der Erstellung geändert werden. ___ qstnhdr ___ Kann ich wandelbare Algorithmen immer in Einzelzuweisungen umwandeln und trotzdem effizient sein? ___
AndrewC 23.02.2014 02:20
quelle
3

Es gibt keinen einzigen Weg dies zu tun, es muss wirklich von Fall zu Fall versucht werden. Ich versuche normalerweise, sie in einfachere Operationen zu zerlegen, zu falten und zu entfalten und dann von dort zu optimieren. Der Karva-Dekodierungsfall ist, wie andere bemerkt haben, ein Breitenbaum, und ich habe mit treeUnfoldM_BF begonnen. Vielleicht gibt es ähnliche Funktionen in Erlang.

Wenn die Dekodieroperation unangemessen teuer ist, könnten Sie die Dekodierung memotisieren und Subbäume teilen / wiederverwenden ... obwohl es wahrscheinlich nicht in einen generischen Tree-Unfold passt und Sie dazu spezielle Funktionen schreiben müssten. Wenn die Fitnessfunktion langsam genug ist, kann es gut sein, einen naiven Decoder wie den unten aufgeführten zu verwenden. Es wird den Baum jeden Aufruf vollständig wiederherstellen.

%Vor%     
Nathan Howell 06.08.2011 00:31
quelle
2

Es gibt eine Reihe von Lösungen, wenn ein veränderbarer Zustand in der funktionalen Programmierung erforderlich ist.

  1. Verwenden Sie einen anderen Algorithmus, der das gleiche Problem löst. Z.B. Quicksort wird allgemein als veränderbar angesehen und kann daher in einer funktionalen Umgebung weniger nützlich sein, aber Mergesort ist im Allgemeinen besser für eine funktionale Einstellung geeignet. Ich kann nicht sagen, ob diese Option in Ihrem Fall möglich oder sinnvoll ist.

  2. Sogar funktionale Programmiersprachen bieten normalerweise eine Möglichkeit, den Status zu ändern. ( Dieser Blog Beitrag scheint zu zeigen, wie man es in Erlang macht. ) Für einige Algorithmen und Datenstrukturen ist dies in der Tat die einzige verfügbare Option (es gibt aktive Forschung zu dem Thema, denke ich); Zum Beispiel werden Hash-Tabellen in funktionalen Programmiersprachen im Allgemeinen mit veränderbarem Zustand implementiert.

In Ihrem Fall bin ich mir nicht sicher, ob die Unveränderlichkeit wirklich zu einem Performance-Engpass führt. Sie haben recht, der (Sub-) Baum wird bei der Aktualisierung neu erstellt, aber die Erlang-Implementierung wird wahrscheinlich alle Teilbäume wiederverwenden, die sich nicht geändert haben, was zu O (log n) -Komplexität pro Update anstelle von O (1) mit veränderbarem Zustand führt . Außerdem werden die Knoten der Bäume nicht kopiert, sondern die Referenzen auf die Knoten, die relativ effizient sein sollten. Sie können über Baumaktualisierungen in einer funktionalen Einstellung in z.B. die Dissertation von Okasaki oder in seinem Buch "Purely Functional Data Structures" basierend auf der These. Ich würde versuchen, den Algorithmus mit einer unveränderlichen Datenstruktur zu implementieren und zu einem veränderbaren zu wechseln, wenn Sie ein Leistungsproblem haben.

Siehe auch einige relevante SO-Fragen hier und here .

    
Antti 30.07.2011 13:30
quelle
2

Ich denke, ich habe herausgefunden, wie Sie Ihr spezielles Problem mit den K-Bäumen lösen können (das allgemeine Problem ist zu schwer: P). Meine Lösung wird in einem schrecklichen hybriden Python-ähnlichen psudocode dargestellt (ich bin heute sehr langsam auf meinem FP) aber ändert keinen Knoten, nachdem du einen erstellt hast (der Trick besteht darin, den Baum zu erstellen) von unten nach oben)

Zuerst müssen wir herausfinden, welche Knoten zu welcher Ebene gehören:

%Vor%

Also in +/*abcd , das sollte Ihnen [+, /*, abcd] geben. Jetzt können Sie dies in einen Baum von unten umwandeln:

%Vor%

Ich bin mir ziemlich sicher, dass wir das jetzt sehr einfach in die Einzelaufgabe Erlang / Haskell umwandeln können.

    
hugomg 30.07.2011 14:04
quelle