2009-07-23 11 views
1

Je suis à la recherche d'un moyen python générique pour manipuler le texte en équations résolubles.Réorganiser les équations pour le solveur

Par exemple:

il peut y avoir quelques constantes pour initialiser

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 

et un ensemble d'équations (écrit ici pour la lisibilité plutôt que le solveur)

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) 

Cela laisse 5 inconnus, donc probablement le système peut être résolu.

Q, dbo, dbr, tw1, tw2 

Les systèmes réels sont non linéaires et beaucoup plus compliqués.

J'ai déjà résolu cet exemple facile avec scipy, Delphi, Sage ... donc je ne cherche pas la partie de résolution. Les équations sont tapées directement dans un éditeur de texte et je veux qu'un programme Python me donne un tableau d'inconnues et un tableau de fonctions d'erreur.

y = mysolver.fsolve(f, x) 

Ainsi, pour l'exemple ci-dessus

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)] 

Je ne sais pas comment extraire les inconnues et créer les fonctions d'erreur.

J'ai essayé la fonction compile.parse() et il semble donner une décomposition structurée. Quelqu'un peut-il donner quelques idées sur la meilleure approche?

+0

Avez-vous besoin d'autoriser cette syntaxe "list"? (a, b = 1,2) Il pourrait être plus facile d'approcher si vous ne le faites pas ... – Stobor

+0

Non, je l'ai juste fait pour rendre l'assignation constante plus compacte. Comment cela aiderait-il à attribuer des valeurs individuellement? –

+0

Il y a longtemps, il y avait un programme Borland appelé Eureka qui résout ce problème. Le même code a été publié plus tard par l'auteur sous le nom de Mercure. De nombreuses années plus tard, un programme Windows appelé EES (Engineering Equation Solver) est sorti mais le solveur n'a jamais été aussi bon qu'Eureka. J'ai récemment trouvé du code en ligne par Clifford Wolf http://svn.clifford.at/tools/trunk/electrotools/eqsolver.html mais c'est en JavaScript et franchement je ne suis pas sa logique. C'est à peu près ce que je veux, mais en Python. –

Répondre

1

Si vous ne voulez pas écrire un analyseur pour votre propre langage d'expression, vous pouvez en effet essayer d'utiliser la syntaxe Python. N'utilisez pas le module de compilation; Au lieu de cela, utilisez une sorte de syntaxe abstraite. Depuis 2.5, vous pouvez utiliser le module _ast:

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' 

Dans les versions précédentes, vous devez utiliser parser.suite, ce qui vous donne un arbre syntaxe de béton qui est plus difficile à traiter.

+0

Je ne suis pas sûr de comprendre comment j'arrive de ceci aux vecteurs x = [] et f = [] J'ai trouvé un défi ici (équation d'analyse en utilisant re sans utiliser eval). Une partie du code semble assez prometteuse, donc je vais expérimenter avec cette idée. –

+0

c'est sa page http://stackoverflow.com/questions/928563/code-golf-evaluating-mathematical-expressions –

2

En fait, j'ai implémenté exactement la même chose en python. Je connais aussi l'Eureka et les autres programmes que vous avez mentionnés. Vous pouvez voir ma mise en œuvre à xyzsolve.appspot.com (Désolé pour la prise éhontée). L'implémentation est dans tout python. Je vais lister les itérations que le code a traversées:

Itération # 0: Effectuez une recherche simple pour remplacer chaque variable de l'équation et remplacez la variable par sa valeur. Par exemple x * y deviendrait 1.1 * 2.2 si les valeurs de x et y sont 1.1 et 2.2. Après avoir obtenu la chaîne transformée, vous pouvez simplement utiliser eval et mettre sa valeur dans le résidu (ou f vector, dans votre cas). La fonction fsolve/fmin de Scipy vous permet de passer des arguments supplémentaires dans votre fonction résiduelle, alors utilisez-la. C'est à dire. passer un dictionnaire qui contient l'index de chaque variable nommée. Votre dict devrait contenir quelque chose comme {'x': 0, 'y': 1} et vous pouvez simplement faire une recherche et remplacer pour chaque équation. Cela fonctionne, mais très lentement puisque vous devez faire une recherche-remplacer chaque fois que la fonction résiduelle est appelée.

Itération 1: Faire la même chose que l'itération # 0, sauf remplacer les variables par l'élément x array directement, ainsi 'y' deviendrait 'x [1]'.En fait, vous pouvez tout faire pour générer une chaîne de fonctions; quelque chose qui ressemble à "def f (x): renvoie x [0] + x [1], x [0] - x [1]". Ensuite, vous pouvez utiliser la fonction exec dans python pour créer la fonction à passer à fsolve/fmin. Aucune vitesse atteinte et vous pouvez vous arrêter à ce point si vos équations sont sous la forme d'une syntaxe python valide. Vous ne pouvez pas faire beaucoup plus avec cette approche si vous voulez supporter un format d'entrée d'équation plus étendu.

Itération 2: Implémentez un lexeur et un analyseur personnalisés. Ce n'est pas aussi difficile à faire que ça en a l'air. J'ai utilisé http://www.evanfosmark.com/2009/02/sexy-lexing-with-python/ pour le lexer. J'ai créé un analyseur de descente récursif (ce n'est pas difficile du tout, une centaine de lignes de code) pour analyser chaque équation. Cela vous donne une flexibilité complète avec le format d'équation. Je garde juste la trace des variables, les constantes qui se produisent de chaque côté de l'équation dans des listes séparées. Lorsque l'analyseur analyse l'équation, il construit une chaîne d'équation qui ressemble à 'var_000 + var_001 * var_002' et ainsi de suite. Finalement, je remplace simplement le 'var_000' par l'index approprié du vecteur x. Donc 'var_000' devient 'x [0]' et ainsi de suite. Si vous voulez vous pouvez construire un AST et faire beaucoup de transformations plus sophistiquées mais je me suis arrêté ici. Enfin, vous pouvez également prendre en compte le type d'équations d'entrée. Il y a quelques équations non-linéaires inoffensives qui ne résoudront pas avec fsolve (il utilise MINPACK hybrdj). Vous avez probablement aussi besoin d'un moyen d'entrer des suppositions initiales.

Je serais intéressé d'entendre s'il existe d'autres moyens de le faire.

Questions connexes