Eine Gleichung mit benutzerdefinierten Funktionen in Python analysieren

8

Ich habe eine Zeichenfolge, die eine mathematische Gleichung ist, aber mit einigen benutzerdefinierten Funktionen. Ich muss alle diese Funktionen finden und durch Code ersetzen.

Zum Beispiel habe ich eine Zeichenfolge:

%Vor%

Ich möchte Code, der (zB) f2(x,y) durch x+y^2 und f1(x,y) durch sin(x+y)

ersetzt

Es wäre ideal, wenn verschachtelte Funktionen wie im Beispiel unterstützt würden. Es wäre jedoch immer noch nützlich, wenn die Verschachtelung nicht unterstützt wird.

Wie ich aus ähnlichen Themen verstehe, kann dies mit einem Compiler-Modul wie compiler.parse(eq) geschehen. Kann mir jemand erklären, wie ich mit AST-Objekt arbeiten kann, das von compiler.parse(eq) erstellt wurde, um meinen String zurück zu rekonstruieren und alle gefundenen Funktionen zu ersetzen?

Ich muss nur die Substitution durchführen und dann wird die Zeichenfolge in einem anderen Programm verwendet. Bewertung nicht erforderlich.

    
Alex 15.01.2015, 10:04
quelle

6 Antworten

7

ein minimales Arbeitsbeispiel ( +,-,*,/,** binary und unäre Operationen und Funktionsaufruf implementiert) Die Priorität der Operation wird mit Klammern

festgelegt

ein bisschen mehr als die Funktionalität für das gegebene Beispiel ist

gemacht %Vor%

Verwendung:

%Vor%

Ergebnis

%Vor%

WARNUNG Der Code arbeitet mit python2.7 und es ist nicht möglich mit anderen Versionen von Python zu arbeiten. Die Python 3-Version funktioniert nicht

    
Xavier Combelle 31.01.2015, 12:30
quelle
3

Die vollständige Ersetzung ist ziemlich schwierig. Hier ist mein Versuch, es zu tun. Hier können wir erfolgreich Ausdrücke einbinden, aber nicht in allen Szenarien. Dieser Code funktioniert nur mit AST, erstellt von ast module. Und verwendet codegen , um es zurück zum Code zu stringieren. Das Stringing von ast und modifizierendem ast im Allgemeinen wird in anderen SO Q / A behandelt: "Analysiere eine .py-Datei, lese den AST, modifiziere ihn und schreibe den modifizierten Quellcode zurück" .

Zuerst definieren wir wenige Helfer:

%Vor%

Danach definieren wir eine Substitutionsfunktion mit NodeTransformer . Zum Beispiel:

%Vor%

Die simultane Substitution mehrerer Variablen ist erforderlich, um unangenehme Situationen richtig zu vermeiden. Zum Beispiel ersetzen Sie sowohl a als auch b für a + b in a + b . Das Ergebnis sollte (a + b) + (a + b) sein, aber wenn wir zuerst a für a + b ersetzen, erhalten wir (a + b) + b und dann b , wir erhalten (a + (a + b)) + b , was das falsche Ergebnis ist! Also simultan ist wichtig:

%Vor%

Dann schreiben wir ähnlich NodeTransformer , um Aufrufe zu finden, wo wir Inline-Funktionsdefinitionen :

können %Vor%

Das substituteCalls ist rekursiv, sodass wir auch rekursive Inline-Funktionen verwenden können. Außerdem gibt es eine explizite Grenze, da einige Definitionen unendlich rekursiv sein können (als fact unten). Es gibt ein bisschen hässlich aussehende kopieren, aber es ist erforderlich, verschiedene Unterbäume zu trennen.

Und der Beispielcode:

%Vor%

Was ausdruckt:

%Vor%

Leider codegen version in pypi ist fehlerhaft. Ausdrücke werden nicht richtig in Klammern gesetzt, selbst AST sagt, sie sollten es tun. Ich habe jbremer / codegen ( pip install git+git://github.com/jbremer/codegen ) verwendet. Es fügt auch unnötige Klammern hinzu, aber es ist besser als gar keine. Danke an @XavierCombelle für den Tipp.

Die Substitution wird komplizierter, wenn Sie anonyme Funktionen haben, d. h. lambda . Dann müssen Sie Variablen umbenennen. Sie könnten versuchen, nach Lambda-Kalkül mit Substitution oder Implementierung zu suchen. Dennoch hatte ich Pech, irgendwelche Artikel zu finden, die Python für diese Aufgabe verwenden.

    
phadej 02.02.2015 14:13
quelle
2

kennen Sie die Variablen im Voraus?

Ich empfehle die Verwendung von sympy!

nehmen Sie zum Beispiel Folgendes:

%Vor%

'z' ist jetzt ein symbolischer Ausdruck, der die mathematische Formel darstellt. Sie können es ausdrucken. Sie können dann subs verwenden, um symbolische Ausdrücke oder Funktionen zu ersetzen. Sie können entweder sine symbolisch wieder darstellen (wie f1 und f2 ) oder Sie können möglicherweise die sin() in sympy.mpmath

verwenden

Je nach Ihren Bedürfnissen ist dieser Ansatz großartig, da Sie diesen Ausdruck eventuell berechnen, bewerten oder vereinfachen können.

hoffe das hilft!

    
adrianX 29.01.2015 06:37
quelle
1

(Verwendung von sympy als adrianX wurde vorgeschlagen, mit zusätzlichem Code.)

Der folgende Code konvertiert eine gegebene Zeichenfolge in eine neue Zeichenfolge, nachdem bestimmte Funktionen kombiniert wurden. Es ist hastig und schlecht dokumentiert, aber es funktioniert .

WARNUNG!

Enthält exec eval , bösartiger Code könnte wahrscheinlich eine Auswirkung haben, wenn die Eingabe von externen Benutzern bereitgestellt wird.

UPDATE:

  • Den gesamten Code neu geschrieben. Funktioniert in Python 2.7.
  • Funktionsargumente können durch Komma oder Leerzeichen oder beides getrennt werden.
  • Alle Beispiele in Frage und Kommentare funktionieren.
%Vor%     
Fermi paradox 02.02.2015 09:36
quelle
0

Was ist Ihr langfristiges Ziel? Soll die Funktion bewertet oder einfach substituiert werden? Im ersten Fall können Sie dies einfach ausprobieren (beachten Sie, dass f1 und f2 auch dynamisch definiert werden können):

%Vor%

Wenn Sie die Funktionen ersetzen und die modifizierte Version zurückbekommen wollen, müssen Sie tatsächlich auf einen AST-Parser zurückgreifen. Seien Sie jedoch vorsichtig bei der Verwendung von eval , da dies eine Sicherheitslücke für bösartigen Benutzereingabecode öffnet.

    
Matt 15.01.2015 10:24
quelle
0

Ich denke, Sie möchten etwas wie PyBison verwenden, das ein Parser-Generator ist.

Sehen Sie sich ein Beispiel an, das den hier benötigten Basiscode enthält:

Ссылка

Sie müssen einen Tokentyp für Funktionen und eine Regel für Funktionen hinzufügen und dann, was mit dieser Funktion passiert, wenn sie gefunden wird.

Wenn Sie weitere Informationen zum Parsen usw. benötigen, versuchen Sie einige grundlegende Tutorials zu Lex und (Yacc oder Bison) zu lesen.

    
peschü 15.01.2015 12:30
quelle