1

我正在寻找一种通用的 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() 函数,它似乎给出了结构化的细分。

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

4

2 回答 2

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): return 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)。您可能还需要一种输入初始猜测的方法。

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

于 2009-07-25T06:17:07.700 回答
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,它为您提供了一个更难处理的具体语法树。

于 2009-07-23T04:41:15.557 回答