Search code examples
pythonsympyintegral

Integral of piecewise function gives incorrect result


Using the recent version of sympy (0.7.6) I get the following bad result when determining the integral of a function with support [0,y):

from sympy import *
a,b,c,x,z = symbols("a,b,c,x,z",real = True)
y = Symbol("y",real=True,positive=True)
inner = Piecewise((0,(x>=y)|(x<0)|(b>c)),(a,True))
I = Integral(inner,(x,0,z))
Eq(I,I.doit())

This is incorrect as the actual result should have the last two cases swapped. This can be confirmed by checking the derivative:

Derivative(I.doit(),z).doit().simplify().subs(z,x)

which reduces to 0 everywhere.

Interestingly, when dropping the condition (b>c) by substituting inner = Piecewise((0,(x>=y)|(x<0)),(a,True)) I get a TypeError:

TypeError: cannot determine truth value of
-oo < y

Am I using the library incorrectly or is this actually a serious sympy bug?


Solution

  • Yes, sympy 0.7.6 is wrong in this case, and in some other such cases. Generally, I don't know any symbolic math package that I would trust to do calculus with piecewise defined functions.

    Note that although

    inner = Piecewise((0, (x>=y)|(x<0)), (a,True))
    

    throws a TypeError at integration time, a logically equivalent definition

    inner = Piecewise((a, (x<y)&(x>=0)), (0,True))
    

    leads to the correct result

    Piecewise((a*z, And(z < y, z >= 0)), (0, And(z <= 0, z >= -oo)), (a*y, True))
    

    By the way, the previous version, sympy 0.7.5, handles

    inner = Piecewise( (0, (x>=y)|(x<0)), (a,True) )
    

    without a TypeError, producing the correct result (in a different form):

    Piecewise((0, z <= 0), (a*y, z >= y), (a*z, True))
    

    Here is another, simpler example of buggy behavior:

    >>> Integral(Piecewise((1,(x<1)|(z<x)), (0,True)) ,(x,0,2)).doit()
    -Max(0, Min(2, Max(0, z))) + 3
    
    >>> Integral(Piecewise((1,(x<1)|(x>z)), (0,True)) ,(x,0,2)).doit()
    -Max(0, Min(2, Max(1, z))) + 3
    

    The first result is incorrect (it fails for z=0, for example). The second is correct. The only difference between two formulas is z<x vs x>z.