重新排列求解器的方程

发布于 2024-07-29 10:55:47 字数 915 浏览 3 评论 0原文

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

任何人都可以提供有关最佳方法的一些想法。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少女情怀诗 2024-08-05 10:55:47

事实上,我已经在 python 中实现了完全相同的东西。 我也熟悉尤里卡和你提到的其他程序。 你可以在 xyzsolve.appspot.com 上看到我的实现(抱歉这个无耻的插件)。 整个实现都是用Python实现的。 我将列出代码经历的迭代:

迭代 #0:对方程中的每个变量进行简单的搜索替换,并将该变量替换为其值。 例如,如果 x 和 y 的值为 1.1 和 2.2,则 x * y 将变为 1.1 * 2.2。 获得转换后的字符串后,您可以使用 eval 并将其值放入残差(或 f 向量,在您的情况下)。 Scipy 的 fsolve/fmin 函数允许您将附加参数传递到残差函数中,因此请充分利用它。 即传递一个包含每个命名变量索引的字典。 您的字典应包含类似 {'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”的方程字符串,依此类推。 最后,我将“var_000”替换为 x 向量中的适当索引。 所以'var_000'变成'x[0]'等等。 如果你愿意,你可以构建一个 AST 并进行许多更复杂的转换,但我就停在这里了。

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

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

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.

离鸿 2024-08-05 10:55:47

如果你不想为自己的表达式语言编写解析器,你确实可以尝试使用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,它为您提供了更难以处理的具体语法树。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文