重新排列求解器的方程

时间:2009-07-23 04:22:39

标签: python equation solver

我正在寻找一种通用的python方法来将文本操作为可解方程式。

例如:

可能有一些常量要初始化

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

和一组方程式(这里为了可读性而不是求解器而写)

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)

这留下了5个未知数,所以系统可以解决。

Q, dbo, dbr, tw1, tw2

实际系统是非线性的,而且要复杂得多。

我已经用scipy,Delphi,Sage解决了这个简单的例子...所以我不是在寻找解决部分。

方程直接输入到文本编辑器中,我想要一个Python程序给我一个未知数组和一组错误函数。

y = mysolver.fsolve(f, x)

所以,对于上面的例子

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

我只是不知道如何提取未知数并创建错误函数。

我尝试了compile.parse()函数,它似乎给出了结构化细分。

任何人都可以就最佳方法提出一些想法。

2 个答案:

答案 0 :(得分:2)

实际上,我在python中实现了完全相同的东西。我也熟悉Eureka和你提到的其他程序。您可以在xyzsolve.appspot.com上看到我的实现(抱歉,这是无耻的插件)。实现在所有python中。我将列出代码经历的迭代:

迭代次数#0:对方程中的每个变量进行简单的搜索替换,并将变量替换为其值。例如,如果x和y的值是1.1和2.2,则x * y将变为1.1 * 2.2。获得转换后的字符串后,您可以使用eval并将其值放入残差(或者f矢量,在您的情况下)。 Scipy的fsolve / fmin函数允许您将其他参数传递给残差函数,因此请使用它。即传递包含每个命名变量索引的字典。你的dict应该包含类似{'x':0,'y':1}的东西,然后你可以只搜索并替换每个等式。这很有效,但非常慢,因为每次调用残差函数时都必须进行搜索替换。

迭代#1:与迭代#0相同,除了直接用x数组元素替换变量,因此'y'将变为'x [1]'。实际上你可以做所有这些来生成一个函数字符串;看起来像“def f(x):返回x [0] + x [1],x [0] - x [1]”的东西。然后你可以使用python中的exec函数来创建传递给fsolve / fmin的函数。没有速度命中,如果你的方程是有效的python语法形式,你可以在这一点停止。如果你想支持更广泛的方程式输入格式,你不能用这种方法做更多的事情。

迭代#2:实现自定义词法分析器和解析器。这并不像听起来那么难。我使用http://www.evanfosmark.com/2009/02/sexy-lexing-with-python/作为词法分析器。我创建了一个递归下降解析器(这根本不难,100行代码)来解析每个等式。这使您可以使用等式格式完全灵活。我只是跟踪变量,在单独的列表中的等式的每一侧出现的常数。当解析器解析等式时,它会构建一个看起来像'var_000 + var_001 * var_002'的等式字符串,依此类推。最后,我只用x向量中的适当索引替换'var_000'。所以'var_000'变成'x [0]'等等。如果你想要你可以建立一个AST并做更复杂的转换,但我在这里停了下来。

最后,您可能还想考虑输入方程的类型。有很多无害的非线性方程式无法用fsolve求解(它使用MINPACK hybrdj)。您可能还需要一种输入初始猜测的方法。

我很想知道是否有其他替代方法可以做到这一点。

答案 1 :(得分:1)

如果您不想为自己的表达式语言编写解析器,您确实可以尝试使用Python语法。不要使用编译器模块;相反,使用某种抽象语法。从2.5开始,您可以使用_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'

在早期版本中,您必须使用parser.suite,它为您提供了一个更难处理的具体语法树。