from sympy import *
var("f, c, x, y")
eq = Eq(y, 1 / f * log(1+c*x) / x)
sol = solve(eq, x)
print(sol[0])
# out: -LambertW(-f*y*exp(-f*y/c)/c)/(f*y) - 1/c
如您所见,这是Lambert W function,它有两个分支:
由SymPy返回的解决方案由上面的分支(图中的蓝线)表示.对于本例,较低的(橙色)分支是正确的分支.
因此,让我们修改该解决方案:
mod_sol = sol[0].replace(lambda t: isinstance(t, LambertW), lambda t: LambertW(*t.args, -1))
print(mod_sol)
# out: -LambertW(-f*y*exp(-f*y/c)/c, -1)/(f*y) - 1/c
现在我们可以对其进行判断,得出x
:
import math
c_val = 10
f_val = math.log(1+c_val) - c_val/(1+c_val)
print(mod_sol.subs({f: f_val, c: c_val, y: 1.5}).n())
# out: 1.120173048954
EDIT to satisfy comment:个
我知道代码sol[0].replace(lambda t: isinstance(t, LambertW), lambda t: LambertW(*t.args, -1))
的最终目标是什么,但我很难理解代码是如何实现这一目标的.
replace
是一种"高级"方法,允许执行模式匹配操作.在本例中,我将以下参数传递给replace
:
Lambda函数形式的查询:lambda t: isinstance(t, LambertW)
.SymPy将把这个查询应用到符号表达式中包含的每个对象;t
参数表示当前正在查看的对象.如果找到匹配,则查询返回True
,否则返回False
.例如,SymPy从sol[0]
开始(请查看上面的内容以了解此表达式是如何组成的):
- 从一开始,
t
就是sol[0]
.sol[0]
是兰伯特W函数吗?不是,因为sol[0]
是两项的相加,其中一项包含Lambert W函数.那么,让我们继续前进.
- 那么,
t
就是-1/c
:它是Lambert W函数吗?显然不是,让我们继续前进.
t
就是-LambertW(-f*y*exp(-f*y/c)/c)/(f*y)
.它是Lambert W函数吗?不,它是乘法,其中一项是Lambert W函数.那么,让我们继续前进.
- 最终,
t
会变成LambertW(-f*y*exp(-f*y/c)/c)
.这是Lambert W函数吗?是的,所以查询函数返回True
.
返回替换对象的函数:lambda t: LambertW(*t.args, -1))
.如果查询函数返回某个对象的True
,则SymPy将获取该对象并将其传递给替换函数.具体地说,我在这里创建了一个新的Lambert W函数,它的参数与原始术语t
相同,但我要求它考虑具有-1
的较低分支.
将来,如果我遇到LambertW函数,我如何知道哪个分支给出了正确的解决方案?
这是我第一次接触到Lambert W函数.我看了维基百科,看到了这两个分支,我明白其中一定有一个极限价值.所以我画了sol[0]
和mod_sol
(见下图).正如您所看到的,直到y ~ 6.5
,较低的分支提供了正确的结果,之后必须考虑较高的分支.