views:

1919

answers:

3

Hi guys,

I am looking for a generic python way to manipulate text into solvable equations.

For example:

there may be some constants to initialize

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

and a set of equations (written here for readability rather than the 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)

This leaves 5 unknowns, so presumably the system can be solved.

Q, dbo, dbr, tw1, tw2

Actual systems are non-linear and much more complicated.

I have already solved this easy example with scipy, Delphi, Sage... so I'm not looking for the solve part.

The equations are typed directly into a text editor and I want a Python program to give me an array of unknowns and an array of error functions.

y = mysolver.fsolve(f, x)

So, for the above example

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

I just don't know how to extract the unknowns and create the error functions.

I tried the compile.parse() function and it seems to give a structured breakdown.

Can anyone give some ideas on the best approach.

A: 

If you don't want to write a parser for your own expression language, you can indeed try to use the Python syntax. Don't use the compiler module; instead, use some kind of abstract syntax. Since 2.5, you can use the _ast module:

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 earlier versions, you would have to use parser.suite, which gives you a concrete-syntax tree that is more difficult to process.

Martin v. Löwis
I'm not sure I understand how I get from this to the vectors x=[] and f=[]I found a challenge here (parsing equation using re without using eval). Some of the code looks quite promising so I will experiment with that idea.
its this pagehttp://stackoverflow.com/questions/928563/code-golf-evaluating-mathematical-expressions
+1  A: 

Actually, I've implemented exactly the same thing in python. I'm also familiar with the Eureka and the other programs you mentioned. You can see my implementation at xyzsolve.appspot.com (Sorry for the shameless plug). The implementation is in all python. I'll list the iterations the code went through:

Iteration #0: Do a simple search a replace for each variable in the equation and replace the variable with its value. For example x * y would become 1.1 * 2.2 if the values of x and y are 1.1 and 2.2. After you get the transformed string, you can just use eval and put its value into the residual (or f vector, in your case). Scipy's fsolve/fmin function lets you pass additional arguments into your residual function, so make use of that. I.e. pass a dictionary that contains the index of each named variable. Your dict should contain something like {'x': 0, 'y':1} and then you can just do a search and replace for each equation. This works, but very slowly since you have to do a search-replace everytime the residual function is called.

Iteration #1: Do the same as iteration #0, except replace variables with the x array element directly, so 'y' would become 'x[1]'. In fact you can do all this to generate a function string; something that looks like "def f(x): return x[0]+x[1], x[0] - x[1]". Then you can use the exec function in python to create the function to pass to fsolve/fmin. No speed hit and you can stop at this point if your equations are in the form of valid python syntax. You can't do much more with this approach if you want to support more extensive equation input format.

Iteration #2: Implement a custom lexer and parser. This isn't as hard to do as it sounds. I used http://www.evanfosmark.com/2009/02/sexy-lexing-with-python/ for the lexer. I created a recursive descent parser (this isn't hard at all, 100 or so lines of code) to parse each equation. This gives you complete flexibilty with the equation format. I just keep track of the variables, constants that occur on each side of the equation in separate lists. As the parser parses the equation, it builds a equation string that looks like 'var_000 + var_001 * var_002' and so on. Finally I just replace the 'var_000' with the appropriate index from the x vector. So 'var_000' becomes 'x[0]' and so on. If you want you can build an AST and do many more sophisticated transformations but I stopped here.

Finally, you might also want to consider the type of input equations. There are quite a few innocuous non-linear equations that will not solve with fsolve (it uses MINPACK hybrdj). You probably also need a way to input initial guesses.

I'd be interested to hear if there are any other alternative ways of doing this.

kpatvt
A: 

Cpa=1,023 Cpw=4,193 dba=0 dbo=18,05 dbr=25 dbs=9,409 e1=0,58 e2=0,62 ma1=0,85 ma2=1,15 mw=0,8 Q=8,182 tw1=16,22 tw2=13,78

boussad