Search code examples
pythonsympysymbolic-integration

Unexpected/confusing Piecewise expression when integrating (x + b)**t, for t=0 and t=1


We wish to know what the general solution is for $ \int (x + b)^t dx, \: b,t \in \mathbb R $

import sympy
from sympy.abc import x, b, t
sympy.integrate((x + b)**t, x)

which returns the following piecewise solution:

$$\begin{cases} \frac{\left(b + x\right)^{t + 1}}{t + 1} & \text{for}: t \neq -1 \\log{\left(b + x \right)} & \text{otherwise} \end{cases}$$

However, this is not correct for t = 0 and t = 1.

Shouldn't the piecewise solution look something like this(?):

$$\begin{cases} \log{\left(b + x \right)} & \text{for} \: t = -1 \\x & \text{for} \: t = 0 \\ \frac{x^2}{2} + bx & \text{for} \: t = 1 \\ \frac{\left(b + x\right)^{t + 1}}{t + 1} & \text{otherwise} \\ \end{cases}$$

I assume Sympy is correct and that there is something I don't understand about the situation, and I would like to know what that is. I can only assume there is an underlying or implicit assumption that t is not 0 or 1.

We try setting t = 0:

import sympy
from sympy.abc import x, b, t
general_solution = sympy.integrate((x + b)**t, x)
specific_solution = general_solution.subs(t, 0) 

Here the specific_solution returns: x + b (incorrect)

We can now try calculating the same thing directly:

import sympy
from sympy.abc import x, b, t
direct_solution = sympy.integrate((x + b)**0, x)

Here the direct_solution returns: x (correct)

The same holds for t = 1


Solution

  • The result from SymPy is correct. Indefinite integrals are only defined up to an arbitrary additive constant and so are not unique. The integrate function does not add + C but you need to understand that it is there implicitly. The antiderivative is correct if its derivative returns the original function:

    In [21]: from sympy.abc import x, b, t
    
    In [22]: f = (x + b)**t
    
    In [23]: F = integrate(f, x)
    
    In [24]: F
    Out[24]: 
    ⎧       t + 1            
    ⎪(b + x)                 
    ⎪────────────  for t ≠ -1
    ⎨   t + 1                
    ⎪                        
    ⎪ log(b + x)   otherwise 
    ⎩                        
    
    In [25]: F.subs(t, 1)
    Out[25]: 
           2
    (b + x) 
    ────────
       2    
    
    In [26]: F.subs(t, 1).diff(x)
    Out[26]: b + x
    
    In [27]: F.subs(t, 1).diff(x) == f.subs(t, 1)
    Out[27]: True
    
    In [28]: F.subs(t, 0)
    Out[28]: b + x
    
    In [29]: F.subs(t, 0).diff(x)
    Out[29]: 1
    
    In [30]: F.subs(t, 0).diff(x) == f.subs(t, 0)
    Out[30]: True
    

    The differences that you see here are just constants wrt the integration variable x and it is valid to add any constant when computing an antiderivative (because the derivative of the constant is zero):

    In [31]: f.subs(t, 0).integrate(x)
    Out[31]: x
    
    In [32]: F.subs(t, 0)
    Out[32]: b + x
    
    In [33]: f.subs(t, 1).integrate(x)
    Out[33]: 
           2
          x 
    b⋅x + ──
          2 
    
    In [34]: F.subs(t, 1)
    Out[34]: 
           2
    (b + x) 
    ────────
       2    
    
    In [35]: F.subs(t, 1).expand()
    Out[35]: 
     2          2
    b          x 
    ── + b⋅x + ──
    2          2 
    

    More generally symbolic expressions for antiderivatives are potentially defined only up to addition of a piecewise constant function but that subtlety is not relevant in this example.