我试图采用一个函数的导数,包括带有sympy的布尔变量。
我的预期结果:
两种不同的衍生物,取决于布尔值是True还是False(即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为True或False的x阈值为4.29 ...,因此是正数和实数。
输出:
TypeError: cannot determine truth value of Relation
我知道真值取决于x,这是一个符号。因此,不知道x无法确定bo。
但是我如何得到我的预期结果,其中bo是象征性的?
答案 0 :(得分:1)
首先,我建议您仔细考虑代码中发生的事情。您首先定义一些sympy函数,例如
fct1 = sy.Function("fct1")
所以在此之后,fct1
是一个未定义的sympy.Function
- 未定义,因为它既没有指定它的参数是什么,也没有指定函数的样子。
然而,您可以明确定义同名函数,如
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
但是请注意,此时,fct1
不再是sympy.Function
或者任何同情对象:覆盖旧的定义,现在它只是一个常规的python函数!
这也是你得到错误的原因:当你调用bo(x)
时,python试图评估
-0.004*x**2 + 0.25*x + 4 <= 5
并根据您对bo()
的定义返回一个值。但是python不知道上面的内容是否属实(或者如何进行比较),所以它会抱怨。
我建议改变2:
代替python函数,就像在代码中一样,你可以简单地使用sympy表达式,例如。
fct1 = -0.004*x**2 + 0.25*x + 4
为了获得条件的真值,我建议使用Heaviside function (wiki),对于负参数求值为0,对于正值求值为1。它在sympy中的实现是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中的(弱)不等式一致。在第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)
不幸的是,我现在手上没有工作情况1.1并且只能测试旧代码。
另一个关注的问题是分段功能:如果使用sympy的乳胶印刷,插入
,它们更具可读性sy.init_printing()
在代码的早期。
(免责声明:我绝不是专家,并且可能还有其他更好的解决方案。只是想提出建议!)