2009-07-23 12 views
1

Ich bin auf der Suche nach einem generischen Python Weg, um Text in lösbare Gleichungen zu manipulieren.Rearrange Gleichungen für Solver

Zum Beispiel:

kann es einige Konstanten sein

e1,e2=0.58,0.62 
ma1,ma2=0.85,1.15 
mw=0.8 
Cpa,Cpw=1.023,4.193 
dba,dbr=0.0,25.0 

und ein Satz von Gleichungen zu initialisieren (geschrieben hier zur besseren Lesbarkeit statt der Solver)

Q=e1*ma1*Cpa*(tw1-dba) 
Q=ma1*Cpa*(dbs-dba) 
Q=mw*Cpw*(tw1-tw2) 
Q=e2*ma2*Cpa*(dbr-tw2) 
Q=ma2*Cpa*(dbr-dbo) 

Dieses 5 Blätter Unbekannte, vermutlich kann das System also gelöst werden.

Q, dbo, dbr, tw1, tw2 

Aktuelle Systeme sind nicht linear und viel komplizierter.

Ich habe dieses einfache Beispiel bereits mit scipy, Delphi, Sage gelöst ... also suche ich nicht nach dem Lösungsteil.

Die Gleichungen werden direkt in einen Texteditor geschrieben und ich möchte, dass ein Python-Programm mir ein Array von Unbekannten und ein Array von Fehlerfunktionen gibt.

y = mysolver.fsolve(f, x) 

also für das obige Beispiel

x=[Q,dbo,dbr,tw1,tw2] 

f=[Q-e1*ma1*Cpa*(tw1-dba), Q-ma1*Cpa*(dbs-dba), Q-mw*Cpw*(tw1-tw2), 
    Q-e2*ma2*Cpa*(dbr-tw2), Q-ma2*Cpa*(dbr-dbo)] 

Ich weiß nur nicht, wie die Unbekannten zu extrahieren und die Fehlerfunktionen erstellen.

Ich habe versucht, die compile.parse() -Funktion und es scheint eine strukturierte Aufteilung geben.

Kann jemand einige Ideen über den besten Ansatz geben.

+0

Müssen Sie diese "Listen" -Syntax zulassen? (a, b = 1,2) Es könnte einfacher sein, wenn Sie nicht ... – Stobor

+0

Nein, ich habe es getan, um die konstante Zuweisung kompakter zu machen. Wie würde es helfen, Werte individuell zu vergeben? –

+0

Vor langer Zeit gab es ein Borland-Programm namens Eureka, das dieses Problem löst. Derselbe Code wurde später vom Autor als Merkur herausgegeben. Viele Jahre später kam ein Windows-Programm namens EES (Engineering Equation Solver) heraus, aber der Solver war nie so gut wie Eureka. Ich fand kürzlich einen Code von Clifford Wolf online http://svn.clifford.at/tools/trunk/electrotools/eqsolver.html aber es ist in JavaScript und ehrlich gesagt, ich folge nicht seiner Logik. Das ist ziemlich genau das, was ich will, aber in Python. –

Antwort

1

Wenn Sie keinen Parser für Ihre eigene Ausdruckssprache schreiben wollen, können Sie tatsächlich versuchen, die Python-Syntax zu verwenden. Verwenden Sie nicht das Compiler-Modul; Verwenden Sie stattdessen eine abstrakte Syntax. Seit 2.5 können Sie das _ast Modul verwenden:

py> import _ast                  
py> tree = compile("e1,e2=0.58,0.62", "<string>", "exec", _ast.PyCF_ONLY_AST) 
py> tree 
<_ast.Module object at 0xb7cd5fac>          
py> tree.body[0] 
<_ast.Assign object at 0xb7cd5fcc> 
py> tree.body[0].targets[0] 
<_ast.Tuple object at 0xb7cd5fec> 
py> tree.body[0].targets[0].elts 
[<_ast.Name object at 0xb7cd5e4c>, <_ast.Name object at 0xb7cd5f6c>] 
py> tree.body[0].targets[0].elts[0].id 
'e1' 
py> tree.body[0].targets[0].elts[1].id 
'e2' 

In früheren Versionen müßten Sie parser.suite verwenden, was gibt Ihnen einen konkreten-Syntaxbaum, die schwieriger zu verarbeiten ist.

+0

Ich bin mir nicht sicher, ich verstehe, wie ich von diesem zu den Vektoren x = [] und f = [] Ich fand eine Herausforderung hier (Parsing-Gleichung mit Re ohne Eval verwenden). Ein Teil des Codes sieht ziemlich vielversprechend aus, also werde ich mit dieser Idee experimentieren. –

+0

ist diese Seite http://stackoverflow.com/questions/928563/code-golf-evaluating-mathematical-expressions –

2

Eigentlich habe ich genau das gleiche in Python implementiert. Ich kenne auch Eureka und die anderen Programme, die Sie erwähnt haben. Sie können meine Implementierung auf xyzsolve.appspot.com sehen (Entschuldigung für den schamlosen Stecker). Die Implementierung ist in allen Python. Ich listet die Iterationen auf, die der Code durchlaufen hat:

Iteration # 0: Suchen Sie einfach einen Ersatz für jede Variable in der Gleichung und ersetzen Sie die Variable durch ihren Wert. Zum Beispiel würde x * y 1,1 * 2,2 werden, wenn die Werte von x und y 1,1 und 2,2 sind. Nachdem Sie die transformierte Zeichenfolge erhalten haben, können Sie einfach eval verwenden und ihren Wert in das Residuum (oder f-Vektor, in Ihrem Fall) eingeben. Scipy's fsolve/fmin-Funktion lässt Sie zusätzliche Argumente in Ihre Residuum-Funktion übergeben, also nutzen Sie diese. I.e. Übergeben Sie ein Wörterbuch, das den Index jeder benannten Variablen enthält. Ihr Diktat sollte etwas wie {'x': 0, 'y': 1} enthalten und dann können Sie einfach nach jeder Gleichung suchen und sie ersetzen. Dies funktioniert, aber sehr langsam, da Sie eine Suche durchführen müssen - ersetzen Sie jedes Mal, wenn die Restfunktion aufgerufen wird.

Iteration 1: Machen Sie dasselbe wie Iteration 0, außer dass Variablen direkt durch das x-Array-Element ersetzt werden, so dass "y" zu "x [1]" wird.Tatsächlich können Sie all dies tun, um eine Funktionszeichenfolge zu erzeugen; etwas, das aussieht wie "def f (x): zurück x [0] + x [1], x [0] - x [1]". Dann können Sie die exec-Funktion in Python verwenden, um die Funktion zu erstellen, die an fsolve/fmin übergeben wird. Keine Geschwindigkeit erreicht und Sie können an dieser Stelle aufhören, wenn Ihre Gleichungen in Form einer gültigen Python-Syntax vorliegen. Sie können mit diesem Ansatz nicht viel mehr tun, wenn Sie ein umfangreicheres Formeleingabeformat unterstützen möchten.

Iteration # 2: Implementieren Sie einen benutzerdefinierten Lexer und Parser. Das ist nicht so schwer zu tun, wie es sich anhört. Ich benutzte http://www.evanfosmark.com/2009/02/sexy-lexing-with-python/ für den Lexer. Ich habe einen rekursiven Descent-Parser erstellt (das ist überhaupt nicht schwer, etwa 100 Zeilen Code), um jede Gleichung zu analysieren. Dies gibt Ihnen volle Flexibilität mit dem Gleichungsformat. Ich behalte nur die Variablen, Konstanten, die auf jeder Seite der Gleichung in separaten Listen auftreten. Wenn der Parser die Gleichung analysiert, erstellt er eine Gleichungszeichenfolge, die aussieht wie 'var_000 + var_001 * var_002' und so weiter. Schließlich ersetze ich einfach 'var_000' durch den entsprechenden Index aus dem x-Vektor. Also wird 'var_000' zu 'x [0]' und so weiter. Wenn Sie möchten, können Sie einen AST erstellen und viele anspruchsvollere Transformationen durchführen, aber ich habe hier aufgehört.

Schließlich möchten Sie vielleicht auch den Typ der Eingangsgleichungen betrachten. Es gibt ziemlich viele harmlose nichtlineare Gleichungen, die sich nicht mit fsolve lösen (es benutzt MINPACK hybrdj). Sie benötigen wahrscheinlich auch eine Möglichkeit, erste Schätzungen einzugeben.

Ich wäre interessiert zu hören, ob es andere alternative Möglichkeiten gibt, dies zu tun.