具有布尔

时间:2017-07-16 16:29:19

标签: boolean sympy derivative

我试图采用一个函数的导数,包括带有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是象征性的?

1 个答案:

答案 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:

  1. 代替python函数,就像在代码中一样,你可以简单地使用sympy表达式,例如。

    fct1 = -0.004*x**2 + 0.25*x + 4

  2. 为了获得条件的真值,我建议使用Heaviside function (wiki),对于负参数求值为0,对于正值求值为1。它在sympy中的实现是sympy.Heaviside。 您的代码可能如下所示:

  3. 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()
    

    在代码的早期。

    (免责声明:我绝不是专家,并且可能还有其他更好的解决方案。只是想提出建议!)