Python 重新排列解算器的方程

Python 重新排列解算器的方程,python,equation,solver,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 和一组方程式(为便于阅读而非求解而写) 这就留下了5个未知数,所以这个系统大概可以解决 Q, dbo, dbr, tw1, tw2 实际系统是非线性的,而且要复杂得多 我已经用scipy、Delphi、Sage解决了这个简单的例子。。。所以我不

我正在寻找一种通用的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
和一组方程式(为便于阅读而非求解而写)

这就留下了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)]
我只是不知道如何提取未知数并创建错误函数

y = mysolver.fsolve(f, x)
我尝试了compile.parse()函数,它似乎给出了一个结构化的分解


任何人都可以给出一些最佳方法的想法。

如果您不想为自己的表达式语言编写解析器,您确实可以尝试使用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'
py>import\u ast
py>tree=compile(“e1,e2=0.58,0.62”,“”,“exec”,_ast.PyCF_ONLY_ast)
py>树
py>树体[0]
py>tree.body[0]。目标[0]
py>tree.body[0]。目标[0]。elts
[, ]
py>tree.body[0]。目标[0]。elts[0]。id
“e1”
py>tree.body[0]。目标[0]。elts[1]。id
‘e2’

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

实际上,我在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(x):返回x[0]+x[1],x[0]-x[1]”的内容。然后可以使用python中的exec函数创建传递给fsolve/fmin的函数。没有速度冲击,如果您的方程式采用有效的python语法形式,您可以在此时停止。如果您想支持更广泛的方程式输入格式,那么使用这种方法无法做更多的事情

迭代#2:实现自定义词法分析器和解析器。这并不像听起来那么难。我用过lexer。我创建了一个递归下降解析器(这一点都不难,大约100行代码)来解析每个方程。这使您能够完全灵活地使用公式格式。我只是在单独的列表中记录变量和方程两边的常数。当解析器解析方程时,它会构建一个类似于“var_000+var_001*var_002”的方程字符串,以此类推。最后,我用x向量中的适当索引替换“var_000”。所以“var_000”变成了“x[0]”等等。如果您愿意,您可以构建一个AST并进行更多复杂的转换,但我就到此为止了

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


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

您必须允许使用“列表”语法吗?(a,b=1,2)如果你不这样做,可能更容易接近……不,我只是为了使常数赋值更紧凑。单独赋值会有什么帮助呢?很久以前,有一个叫做Eureka的Borland项目解决了这个问题。作者后来发布了与Mercury相同的代码。许多年后,一个名为EES(工程方程求解器)的Windows程序问世,但求解器从来没有Eureka那么好。我最近在网上找到了Clifford Wolf的一些代码,但它是用JavaScript编写的,坦率地说,我不遵循他的逻辑。这正是我想要的,但在Python中,我不知道我是如何从这里得到向量x=[]和f=[]的,我在这里发现了一个挑战(使用re解析方程而不使用eval)。有些代码看起来很有前途,所以我将尝试一下这个想法