Search code examples
pythonsympysymbolic-math

Why does SymPy's integrate sometimes produce antiderivative with very long numbers?


This is on SymPy 1.1.1 using Python 3.6.5.

In SymPy, I always had to use S('...') around the integrand to make it not return a result using floating point numbers, and sometimes to make it actually evaluate the integral. One side effect of this is that SymPy sometimes returns a result with very long whole numbers, e.g.,

z=symbols('z')
integrate(S('1/(cos(z)+sin(z)+2**(1/2))'),z)

returns

-221108036964586978124740847487718783991180811173992192658
5647118334188786/(-2669010107947987550795474273552499757111
367990811651140108173443831125763*tan(z/2) + 
18872751463854612207095892554955468385336360233408060517004
98501499110078*sqrt(2)*tan(z/2) - 7817349615625263300858850180
569529185777319674708450884076749
42332015685*sqrt(2) + 110554018482293489062370423743859391995
5904055869960963292823559167094393) + 
1563469923125052660171770036113905837155463934941690176815349
884664031370*sqrt(2)/(-2669010107947987550795474273552499757
111367990811651140108173443831125763*tan(z/2) + 
18872751463854612207095892554955468385336360233408060517004985
01499110078*sqrt(2)*tan(z/2) - 78173496156252633008588501805695
29185777319674708450884076749
42332015685*sqrt(2) + 11055401848229348906237042374385939199559
04055869960963292823559167094393)

I verified the result above and it is correct. Doing simplify() on the above did not help. I thought at first is that the result needs to be simplified, that is all.

If I do not use S'(....)' with sympy, it does not evaluate on this example.

>>> integrate(1/(cos(z)+sin(z)+2**(1/2)),z)
1.0*Integral(1/(1.0*sin(z) + 1.0*cos(z) + 1.4142135623731), z)

But compare to the small outputs from fricas 1.3.3

integrate(1/(cos(z)+sin(z)+2^(1/2)),z)
((-1)*2^(1/2)*sin(z)+((-1)*2^(1/2)*cos(z)+2))/(2*sin(z)+(-2)*cos(z))

Mathematica 11.3

ClearAll[z]
FullSimplify[Integrate[1/(Cos[z] + Sin[z] + 2^(1/2)), z]]
-(((1 + I) + (2*I + Sqrt[2])*E^(I*z))/((1 + I) + Sqrt[2]*E^(I*z)))

Maple 2018

int(1/(cos(z)+sin(z)+2^(1/2)),z);
-2/((2^(1/2)-1)*(tan((1/2)*z)+2^(1/2)+1))

Question: what is in SymPy's integration algorithm that sometimes makes it output such long numbers, while other CAS systems do not for the same integral? Is there a trick in SymPy to make it produce smaller leaf-size result compared to the other CAS systems?

Again, SymPy's results are correct. I am just asking why its result on this example have such long numbers. May be if one knows why, it will help better understand things.


Solution

  • I can guess that the answer comes from "heuristic Risch algorithm" which at some step matches coefficients of many pieces of the (taken apart) expression, and ends up with large coefficients that do the job. In practical terms, simplifying the expression before integration happens to help:

    >>> integrate(trigsimp(1/(cos(z)+sin(z)+sqrt(2))), z)
    -sqrt(2)/(tan(z/2 + pi/8) + 1)
    

    (One can use simplify here to the same effect, but if you know that trigonometric simplification is in order here, trigsimp is the way to go.) Once the expression is simplified to

    sqrt(2)/(2*(sin(z + pi/4) + 1))
    

    there is just one trigonometric function left, which is a lot easier than dealing with two.

    (Aside: using sqrt(2) in place of 2**(1/2) is a better way to avoid premature evaluation of 1/2 to a float than stringifying the entire formula.)