Code-Manipulation über einen interaktiven Baum für Mathematica

8

Diese Frage veranlasste mich dazu überlege dir eine interaktive Methode zum Bearbeiten von Code. Ich frage mich, ob es angesichts der dynamischen Fähigkeiten von Mathematica möglich ist, so etwas zu implementieren.

Betrachten Sie einen Ausdruck:

%Vor%

Und sein TreeForm :

Ich möchte diesen Baum direkt bearbeiten und dann das Ergebnis in Mathematica-Code zurückübersetzen lassen. Man sollte zumindest in der Lage sein:

  • Umbenennen von Knoten, Ersetzen von Symbolen
  • lösche die Knoten und setze ihre Blätter auf den Knoten über
  • zurück
  • Knoten und Blätter neu anordnen (die Reihenfolge der Argumente)

Ich glaube, dass es Sprachen oder Umgebungen gibt, die auf diese Art von Manipulation spezialisiert sind, und ich finde das nicht attraktiv, aber ich bin daran interessiert, diese Art von interaktiver Baumbearbeitung für spezielle Zwecke zu haben.

    
Mr.Wizard 26.05.2011, 12:34
quelle

1 Antwort

13

Ich werde eine Teillösung anbieten, aber diejenige, mit der du anfangen kannst. Ich werde die veränderbare Baumdatenstruktur aus diesem Beitrag verwenden, da dies der Fall ist scheint wie Mutabilität für dieses Problem natürlich ist. Wiederholen Sie es aus Bequemlichkeit hier:

%Vor%

Hier ist der Code zum Erstellen eines veränderbaren Baums aus einem beliebigen Mathematica-Ausdruck und Lesen des Ausdrucks zurück aus dem Baum:

%Vor%

Sie können einfache Ausdrücke wie a+b testen. Ein paar Kommentare, wie das funktioniert: Um einen veränderbaren Ausdrucksbaum (aufgebaut aus node -s) aus einem Ausdruck zu erzeugen, rufen wir die Funktion makeExpressionTree auf, die zuerst den Baum erstellt (Aufruf an makeExpressionTreeAux ) und dann indexiert die Knoten (Aufruf an indexNodes ). Die Funktion makeExpressionTree ist rekursiv, sie durchläuft den Ausdrucksbaum rekursiv, während sie ihre Struktur in die Struktur des resultierenden veränderbaren Baums kopiert. Ein subtiler Punkt hier ist, warum wir Dinge wie val = Hold[Evaluate[Unique[]]] , nd.setValue[val]; , Evaluate[val[[1]]] = expr; und nicht nur nd.setValue[expr] brauchen. Dies geschieht mit InputField[Dynamic[some-var]] im Hinterkopf - dazu benötigen wir eine Variable, um den Wert zu speichern (vielleicht könnte man eine mehr benutzerdefinierte Dynamic schreiben, um dieses Problem zu vermeiden, wenn man mag). Nachdem der Baum erstellt wurde, enthält jeder Knoten also einen Wert, der Hold[someSymbol] ist, während someSymbol den Wert eines Atoms oder eines Kopfes für einen nicht-atomaren Unterteil enthält. Das Indexierungsverfahren ändert den Wert jedes Knotens von Hold[sym] in {index,Hold[symbol]} . Beachten Sie, dass es die Funktion traverse verwendet, die den generischen Tiefen-zuerst-Mutable-Tree-Traversal implementiert (ähnlich wie Map[f,expr, Infinity] , aber für veränderbare Bäume). Daher werden Indizes in der Tiefe in der ersten Reihenfolge inkrementiert. Schließlich durchläuft die Funktion expressionFromTree den Baum und erstellt den Ausdruck, den der Baum speichert.

Hier ist der Code zum Rendern der veränderbaren Struktur:

%Vor%

Dieser Teil funktioniert wie folgt: Die Funktion getGraphRules durchläuft den Baum und sammelt Parent-Child-Pares von Knotenindizes (in Form von Regeln). Das resultierende Regelwerk ist das, was die GraphPlot als erstes Argument erwartet . Die Funktion getNodeIndexRules durchläuft den Baum und erstellt die Hash-Tabelle, in der Schlüssel Knotenindizes und Werte die Knoten selbst sind. Die Funktion makeSymbolRule übernimmt den Knoten und gibt die verzögerte Regel der Form index:>node-var-symbol zurück. Es ist wichtig, dass die Regel verzögert wird, damit die Symbole nicht ausgewertet werden. Dies wird verwendet, um das Symbol aus dem Knotenbaum in InputField[Dynamic[]] einzufügen.

So können Sie es verwenden: Erstellen Sie zuerst einen Baum:

%Vor%

Rendere es dann:

%Vor%

Sie müssen die Daten in jedem Eingabefeld ändern können, obwohl einige Mausklicks nötig sind, um den Cursor dort erscheinen zu lassen. Zum Beispiel habe ich c auf c1 und b auf b1 geändert. Dann erhalten Sie den modifizierten Ausdruck:

%Vor%

Diese Lösung behandelt nur Modifikationen, aber nicht das Entfernen von Knoten usw. Sie kann jedoch ein Ausgangspunkt sein und auch auf diesen Bereich ausgedehnt werden.

BEARBEITEN

Hier ist eine viel kürzere Funktion, die auf den gleichen Ideen basiert, aber nicht die veränderbare Baumstruktur verwendet.

%Vor%

So verwenden Sie es:

%Vor%

Sie können getExpression[] jederzeit aufrufen, um den aktuellen Wert von Ausdruck zu sehen oder ihn einer beliebigen Variablen zuzuordnen, oder Sie können

verwenden %Vor%

Diese Methode liefert einen viel kürzeren Code, da die native Baumstruktur von Mathematica als Skelett für den Baum wiederverwendet wird, wo alle informativen Teile (Köpfe und Atome) durch Symbole ersetzt wurden. Dies ist immer noch ein veränderbarer Baum, solange wir Zugriff auf Originalsymbole und nicht nur auf ihre Werte haben, aber wir müssen nicht über Bausteine ​​für den Baum nachdenken - wir verwenden dafür die Ausdrucksstruktur. Dies ist nicht die vorherige längere Lösung zu verringern, konzeptionell denke ich, dass es klarer ist, und es ist wahrscheinlich immer noch besser für kompliziertere Aufgaben.

    
Leonid Shifrin 26.05.2011 14:39
quelle