带有布尔值的 sympy 导数
sympy derivative with boolean
我正在尝试使用 sympy 对包含布尔变量的函数求导。
我的预期结果:
两个不同的导数,取决于布尔值是真还是假(即 1 或 0)。
示例:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
bo = sy.Function("bo")
fct1 = sy.Function("fct1")
fct2 = sy.Function("fct2")
FOC2 = sy.Function("FOC2")
y = 5
a = 2
b = 4
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
# the following gives the smaller positive intercept with the x-axis)
# this intercept is the threshold value for the boolean function, bo
min(sy.solve(fct1(x)-y, x))
def bo(x):
if fct1(x) <= y:
return 1
else:
return 0
def fct2(c, x):
return a + b*c + bo(x)*c
def FOC2(c, x):
return sy.diff(fct2(c, x), c)
print(FOC2(c, x))
评论后的最小函数显示 bo 为真或假的 x 阈值为 4.29...,因此是正数和真实数。
输出:
TypeError: cannot determine truth value of Relation
我明白真值取决于x,它是一个符号。因此,不知道 x 就无法确定 bo。
但是我怎样才能得到我的预期结果,其中 bo 是象征性的?
首先,我建议您仔细考虑上面粘贴的代码中发生的事情。您首先定义一些 sympy 函数,例如
fct1 = sy.Function("fct1")
所以在这之后,fct1
是一个未定义的 sympy.Function
- 未定义的意思是它既没有指定它的参数是什么,也没有指定函数的样子。
但是,您可以显式定义同名函数,如
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
但是请注意,此时 fct1
不再是 sympy.Function
或任何 sympy 对象:您覆盖旧定义,它现在只是一个常规 python函数!
这也是您收到错误的原因:当您调用 bo(x)
时,python 尝试计算
-0.004*x**2 + 0.25*x + 4 <= 5
和 return 根据您对 bo()
的定义的值。但是python不知道上面的是不是真的(或者怎么比较),所以报错。
我建议进行 2 处更改:
而不是 python 函数,如代码中所示,您可以简单地使用 sympy 表达式,例如
fct1 = -0.004*x**2 + 0.25*x + 4
为了得到你的条件的真值,我建议使用Heaviside function (wiki), which evaluates to 0 for a negative argument, and to 1 for positive. Its implementation in sympy is sympy.Heaviside
。
您的代码可能如下所示:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
y = 5
a = 2
b = 4
fct1 = -0.004*x**2 + 0.25*x + 4
bo = sy.Heaviside(y - fct1)
fct2 = a + b*c + bo * c
FOC2 = sy.diff(fct2, c)
print(FOC2)
两条评论在线
bo = sy.Heaviside(y - fct1)
(1) 当前实现默认不计算 sympy.Heaviside(0)
;这是因为周围有不同的定义(有些定义为 1,有些定义为 1/2)。您希望它为 1,以符合 OP 中的(弱)不等式。在 sympy 1.1 中,这可以通过向 Heaviside
传递一个附加参数来实现,即任何你想要 Heaviside(0)
评估为:
bo = sy.Heaviside(y - fct1, 1)
旧版本的 sympy 不支持此功能。
(2) 您将获得您的 FOC2,同样涉及 Heaviside
项。我喜欢这个的一点是,你可以继续使用这个表达式,比如你是否想求二阶导数等等。如果为了可读性,您更喜欢分段表达式 - 没问题。只需将相应的行替换为
bo = sy.Heaviside(y - fct1)._eval_rewrite_as_Piecewise(y-fct1)
这将自动转换为分段函数。 (请注意,在旧版本下,这会自动隐式使用 Heaviside(0) = 0.5 - 最好同时使用 (1) 和 (2):
bo = sy.Heaviside(y - fct1, 1)._eval_rewrite_as_Piecewise(y-fct1)
不幸的是,我现在手头没有可用的 sympy 1.1,只能测试旧代码。
关于 sympy 的分段函数的另一个注意事项:如果使用 sympy 的乳胶打印,通过插入
它们更具可读性
sy.init_printing()
在代码的早期。
(免责声明:我绝不是 sympy 方面的专家,可能还有其他更好的解决方案。只是想提出一个建议!)
我正在尝试使用 sympy 对包含布尔变量的函数求导。
我的预期结果:
两个不同的导数,取决于布尔值是真还是假(即 1 或 0)。
示例:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
bo = sy.Function("bo")
fct1 = sy.Function("fct1")
fct2 = sy.Function("fct2")
FOC2 = sy.Function("FOC2")
y = 5
a = 2
b = 4
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
# the following gives the smaller positive intercept with the x-axis)
# this intercept is the threshold value for the boolean function, bo
min(sy.solve(fct1(x)-y, x))
def bo(x):
if fct1(x) <= y:
return 1
else:
return 0
def fct2(c, x):
return a + b*c + bo(x)*c
def FOC2(c, x):
return sy.diff(fct2(c, x), c)
print(FOC2(c, x))
评论后的最小函数显示 bo 为真或假的 x 阈值为 4.29...,因此是正数和真实数。
输出:
TypeError: cannot determine truth value of Relation
我明白真值取决于x,它是一个符号。因此,不知道 x 就无法确定 bo。
但是我怎样才能得到我的预期结果,其中 bo 是象征性的?
首先,我建议您仔细考虑上面粘贴的代码中发生的事情。您首先定义一些 sympy 函数,例如
fct1 = sy.Function("fct1")
所以在这之后,fct1
是一个未定义的 sympy.Function
- 未定义的意思是它既没有指定它的参数是什么,也没有指定函数的样子。
但是,您可以显式定义同名函数,如
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
但是请注意,此时 fct1
不再是 sympy.Function
或任何 sympy 对象:您覆盖旧定义,它现在只是一个常规 python函数!
这也是您收到错误的原因:当您调用 bo(x)
时,python 尝试计算
-0.004*x**2 + 0.25*x + 4 <= 5
和 return 根据您对 bo()
的定义的值。但是python不知道上面的是不是真的(或者怎么比较),所以报错。
我建议进行 2 处更改:
而不是 python 函数,如代码中所示,您可以简单地使用 sympy 表达式,例如
fct1 = -0.004*x**2 + 0.25*x + 4
为了得到你的条件的真值,我建议使用Heaviside function (wiki), which evaluates to 0 for a negative argument, and to 1 for positive. Its implementation in sympy is
sympy.Heaviside
。 您的代码可能如下所示:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
y = 5
a = 2
b = 4
fct1 = -0.004*x**2 + 0.25*x + 4
bo = sy.Heaviside(y - fct1)
fct2 = a + b*c + bo * c
FOC2 = sy.diff(fct2, c)
print(FOC2)
两条评论在线
bo = sy.Heaviside(y - fct1)
(1) 当前实现默认不计算 sympy.Heaviside(0)
;这是因为周围有不同的定义(有些定义为 1,有些定义为 1/2)。您希望它为 1,以符合 OP 中的(弱)不等式。在 sympy 1.1 中,这可以通过向 Heaviside
传递一个附加参数来实现,即任何你想要 Heaviside(0)
评估为:
bo = sy.Heaviside(y - fct1, 1)
旧版本的 sympy 不支持此功能。
(2) 您将获得您的 FOC2,同样涉及 Heaviside
项。我喜欢这个的一点是,你可以继续使用这个表达式,比如你是否想求二阶导数等等。如果为了可读性,您更喜欢分段表达式 - 没问题。只需将相应的行替换为
bo = sy.Heaviside(y - fct1)._eval_rewrite_as_Piecewise(y-fct1)
这将自动转换为分段函数。 (请注意,在旧版本下,这会自动隐式使用 Heaviside(0) = 0.5 - 最好同时使用 (1) 和 (2):
bo = sy.Heaviside(y - fct1, 1)._eval_rewrite_as_Piecewise(y-fct1)
不幸的是,我现在手头没有可用的 sympy 1.1,只能测试旧代码。
关于 sympy 的分段函数的另一个注意事项:如果使用 sympy 的乳胶打印,通过插入
它们更具可读性sy.init_printing()
在代码的早期。
(免责声明:我绝不是 sympy 方面的专家,可能还有其他更好的解决方案。只是想提出一个建议!)