SymPy:区间数学
SymPy: Interval Math
简介
我们最近在做一个项目,一直在寻找一个合适的系统来计算一些值。 SymPy 被推荐为一个丰富的数学库。但是,我们的项目无法实现 "work"。
我们一直在努力解决的问题是,我们将使用的许多值都经过了多次舍入,并且很可能容易出现浮点数错误。为了在之前的项目中解决这个问题,我们使用 Interval Arithmetic 代替 JavaScript 来相当有效地使用。 Python 的 mpmath 看起来很相似,但 SymPy 不仅使用 mpmath,而且还提供了我们将来可能需要的其他潜在有用的功能。
问题
我们最近一直在研究的一个示例方程是 a = b * (1 + c * d * e)
,我们希望在所有其他变量已知的情况下求解 e
。但是,有些变量需要表示为一个值的范围,因为我们不知道确切的值,但范围很小。
代码
from sympy import *
from sympy.sets.setexpr import SetExpr
a, b, c, d, e = symbols('a b c d e')
b = 40
c = 1
d = 0.1
a = SetExpr(Interval(45.995, 46.005))
equ = Eq(b * (1 + c * d * e), a)
solveset(equ, e)
ValueError: The argument '45.995*I' is not comparable.
这只是最新的尝试,但我尝试过设置域、设置符号的不等式、使用 AccumBounds
和许多其他解决方案,但我不禁认为我们完全忽略了一些简单的事情.
解决方案
看来,使用一个间隔对于所选答案提供的代码是可行的,但它不会扩展到需要间隔或值范围的多个符号。看来我们将扩展 mpmath 库以支持额外的区间函数。
由于某种原因,绘图模块中的 SymPy 中有一个 intervalmath 模块。虽然它不是 Basic 的子类,但不能直接在表达式中使用。但是,我们可以使用 lambdify
将其替换为表达式 as
from sympy import *
from sympy.plotting.intervalmath import interval
b = 40
c = 1
d = 0.1
a, e = symbols('a, e', real=True)
equ = Eq(b * (1 + c * d * e), a)
sol_e, = solveset(equ, e)
f_e = lambdify(a, sol_e)
int_a = interval(45.995, 46.005)
int_e = f_e(a=int_a)
print(int_e)
这给
[1.498750, 1.501250]
我认为 intervalmath 模块的使用不多,所以它很可能无法完全解决您的实际问题。
使用集合可能是更好的方法,imageset
似乎可以做到这一点:
In [16]: set_e = imageset(Lambda(a, sol_e), Interval(45.995, 46.005))
In [17]: set_e
Out[17]: [1.49875, 1.50125]
虽然我不确定这与多个 symbol/interval 配合使用效果如何。
编辑:为了完整起见,我展示了如何使用具有多个间隔的 intervalmath
:
from sympy import *
from sympy.plotting.intervalmath import interval
b = 40
d = 0.1
a, c, e = symbols('a, c, e', real=True)
equ = Eq(b * (1 + c * d * e), a)
sol_e, = solveset(equ, e)
f_e = lambdify((a, c), sol_e)
int_a = interval(45.995, 46.005)
int_c = interval(0.95, 1.05)
int_e = f_e(a=int_a, c=int_c)
print(int_e)
这给
[1.427381, 1.580263]
简介
我们最近在做一个项目,一直在寻找一个合适的系统来计算一些值。 SymPy 被推荐为一个丰富的数学库。但是,我们的项目无法实现 "work"。
我们一直在努力解决的问题是,我们将使用的许多值都经过了多次舍入,并且很可能容易出现浮点数错误。为了在之前的项目中解决这个问题,我们使用 Interval Arithmetic 代替 JavaScript 来相当有效地使用。 Python 的 mpmath 看起来很相似,但 SymPy 不仅使用 mpmath,而且还提供了我们将来可能需要的其他潜在有用的功能。
问题
我们最近一直在研究的一个示例方程是 a = b * (1 + c * d * e)
,我们希望在所有其他变量已知的情况下求解 e
。但是,有些变量需要表示为一个值的范围,因为我们不知道确切的值,但范围很小。
代码
from sympy import *
from sympy.sets.setexpr import SetExpr
a, b, c, d, e = symbols('a b c d e')
b = 40
c = 1
d = 0.1
a = SetExpr(Interval(45.995, 46.005))
equ = Eq(b * (1 + c * d * e), a)
solveset(equ, e)
ValueError: The argument '45.995*I' is not comparable.
这只是最新的尝试,但我尝试过设置域、设置符号的不等式、使用 AccumBounds
和许多其他解决方案,但我不禁认为我们完全忽略了一些简单的事情.
解决方案
看来,使用一个间隔对于所选答案提供的代码是可行的,但它不会扩展到需要间隔或值范围的多个符号。看来我们将扩展 mpmath 库以支持额外的区间函数。
由于某种原因,绘图模块中的 SymPy 中有一个 intervalmath 模块。虽然它不是 Basic 的子类,但不能直接在表达式中使用。但是,我们可以使用 lambdify
将其替换为表达式 as
from sympy import *
from sympy.plotting.intervalmath import interval
b = 40
c = 1
d = 0.1
a, e = symbols('a, e', real=True)
equ = Eq(b * (1 + c * d * e), a)
sol_e, = solveset(equ, e)
f_e = lambdify(a, sol_e)
int_a = interval(45.995, 46.005)
int_e = f_e(a=int_a)
print(int_e)
这给
[1.498750, 1.501250]
我认为 intervalmath 模块的使用不多,所以它很可能无法完全解决您的实际问题。
使用集合可能是更好的方法,imageset
似乎可以做到这一点:
In [16]: set_e = imageset(Lambda(a, sol_e), Interval(45.995, 46.005))
In [17]: set_e
Out[17]: [1.49875, 1.50125]
虽然我不确定这与多个 symbol/interval 配合使用效果如何。
编辑:为了完整起见,我展示了如何使用具有多个间隔的 intervalmath
:
from sympy import *
from sympy.plotting.intervalmath import interval
b = 40
d = 0.1
a, c, e = symbols('a, c, e', real=True)
equ = Eq(b * (1 + c * d * e), a)
sol_e, = solveset(equ, e)
f_e = lambdify((a, c), sol_e)
int_a = interval(45.995, 46.005)
int_c = interval(0.95, 1.05)
int_e = f_e(a=int_a, c=int_c)
print(int_e)
这给
[1.427381, 1.580263]