3

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.

Rodrigo de Azevedo
  • 1,097
  • 9
  • 17
Nasser
  • 12,849
  • 6
  • 52
  • 104
  • I suspect, as in your other question, it has to do with assumptions. 1.1.1 seems to have loosened initial assumptions on symbols. – hpaulj Jun 18 '18 at 07:55
  • Aside: I know that having to work around eager Python evaluation of fractions is annoying, but stringifying the entire formula is a dangerous workaround, as you can see in my comment under hpaulj's answer. Just put `sqrt(2)` in place of `2**(1/2)`, and there is no need for `S('...')` anymore. (This does not answer the main question.) –  Jun 18 '18 at 09:16
  • What is the name of function `S`? – Rodrigo de Azevedo Jun 18 '18 at 10:08
  • 1
    @RodrigodeAzevedo Here it means the [built-in shorthand for sympify](https://stackoverflow.com/a/41867990) –  Jun 18 '18 at 10:11
  • @user6655984 what you suggest is not possible for what I am doing. I am using a test suite of over 70,000 integrals in it. All written this way, using ^ for exponents on many expressions. I can only change ^ to ** to make sympy happy. Other changes would requires advanced parser to convert the radicals to not use ** notation. Also, how would you write `2**(5/6)` without using `**` ? – Nasser Jun 18 '18 at 10:56
  • Okay, I wasn't aware of your use case. `2**(S(5)/6)` is how I'd write that exponent if typing it from scratch. –  Jun 18 '18 at 11:04

1 Answers1

3

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