0
$\begingroup$

I have a problem with exponentials and the use of the commands N and Collect. I am trying to write a code that generates a very large list of polynomials on a variable x which are needed as input for an external program. In order to create the proper input for this program, I have to write the polynomials in a numerical format and not a symbolic one. A simple nesting of the commands

Collect[N[f[x],precision],x]

does (almost every time) what I want. The problem with my polynomials is that they come after the cancellation of some exponentials, of which the two commands above took care of so far. As a simple example,

In[]:= Collect[
 N[-4*E^(2*Pi*(4 + x))*(E^(-(Pi*x) - Pi*(8 + x))/2 - 
      8*E^(-(Pi*x) - Pi*(8 + x))*Pi) + 
   8*E^(-(Pi*x) + 2*Pi*(4 + x) - Pi*(8 + x))*Pi*x], x]
Out[]= 98.531 + 25.1327 x

However, the only instance when this happens to fail is when one of the polynomials is of degree 0, in which case the cancellation of the exponentials doesn't happen anymore:

In[]:= Collect[N[-4*E^(-(Pi*x) + 2*Pi*(4 + x) - Pi*(8 + x))], x]
Out[]= -4. 2.71828^(-3.14159 x + 6.28319 (4. + x) - 
  3.14159 (8. + x))

A trivial swap of N and Collect doesn't solve the issue. After changing the arguments of the exponentials, the problem seems to appear if I have some parenthesis () and some noninteger number in front of my variable x. I would like to make use of Simplify to solve the problem, but since the program is already demanding and the process has to be iterated tons of times, I need to find a faster way to fix this issue instead of using Simplify each time. The only other solution which seemed to work is nesting the commands N[ExpToTrig[N[Collect[... ,x]]]] (it's not enough to apply N[ ] once), but I am not sure of how much it is reliable on the long run and (if and) how much it is faster than Simplify. Is there some quick fix to the problem that I don't know of? Thanks in advance.

$\endgroup$

2 Answers 2

3
$\begingroup$
Clear["Global`*"]

collect[expr_, wp_ : MachinePrecision, var : _Symbol : x] :=
 expr // Simplify // Collect[#, var] & // N[#, wp] &

poly1 = -4*
    E^(2*Pi*(4 + x))*(E^(-(Pi*x) - Pi*(8 + x))/2 - 
      8*E^(-(Pi*x) - Pi*(8 + x))*Pi) + 
   8*E^(-(Pi*x) + 2*Pi*(4 + x) - Pi*(8 + x))*Pi*x;

poly1 // collect

(* 98.531 + 25.1327 x *)

poly1 // collect[#, 10] &

(* 98.53096491 + 25.13274123 x *)

poly2 = -4*E^(-(Pi*x) + 2*Pi*(4 + x) - Pi*(8 + x));

poly2 // collect

(* -4. *)

poly2 // collect[#, 8] &

(* -4.0000000 *)

EDIT: To avoid Simplify, use ExpandAll

collect2[expr_, wp_ : MachinePrecision, var : _Symbol : x] := 
 expr // ExpandAll // Collect[#, var] & // N[#, wp] &

poly1 // collect2

(* 98.531 + 25.1327 x *)

poly2 // collect2

(* -4. *)
$\endgroup$
5
  • $\begingroup$ Hi, thanks for your answer. Doesn't this always use Simplify on each expression you are giving as input? Because my question was whether this can be avoided or not. Applying Simplify to a full and large amount of polynomials only because of a problem with a very small subset of them is the real problem which I'm trying to evade $\endgroup$
    – Gnrdgr1594
    Apr 19, 2021 at 21:24
  • $\begingroup$ Yes it uses Simplify. I didn't get to the part of your question where it said you wanted something else. $\endgroup$
    – Bob Hanlon
    Apr 19, 2021 at 21:29
  • $\begingroup$ @Gnrdgr1594 On the two examples, I find nothing faster than poly // Simplify // N // Expand. (I'm a bit surprised, because Simplify can be slow, but not here.) $\endgroup$
    – Michael E2
    Apr 20, 2021 at 2:21
  • 1
    $\begingroup$ 3rd arg of Collect can be useful here, Collect[expr, var, fun] with fun equal to Simplify or ExpandAll $\endgroup$
    – I.M.
    Apr 20, 2021 at 2:30
  • $\begingroup$ @I.M. It's kinda slow, though. $\endgroup$
    – Michael E2
    Apr 20, 2021 at 4:20
1
$\begingroup$

@BobHanlon's Simplify solution is pretty fast, and the tweak below is a little faster. Simplify is not always fast, but without an example to show it is slower, it seems the way to go. A fairly quick way, though twice as slow as Simplify, is to evaluate the exponential at a numerical value of x. Given that the exponentials cancel out anyway, the coefficients are really constant functions of x.

poly1 = -4*
    E^(2*Pi*(4 + x))*(E^(-(Pi*x) - Pi*(8 + x))/2 - 
      8*E^(-(Pi*x) - Pi*(8 + x))*Pi) + 
   8*E^(-(Pi*x) + 2*Pi*(4 + x) - Pi*(8 + x))*Pi*x;

poly1 // Simplify // N // Expand // RepeatedTiming
poly1 /. E^y_ :> E^(y /. x -> 0.) // Expand // RepeatedTiming

poly1 // Simplify // Collect[#, x] & // N // RepeatedTiming   (* Bob's Simplify *)
poly1 // ExpandAll // Collect[#, x] & // N // RepeatedTiming  (* Bob's ExpandAll *)
Collect[poly1, x, Simplify] // N // RepeatedTiming            (* I.M.'s variants *)
Collect[poly1, x, ExpandAll] // N // RepeatedTiming 
(*
  {0.0000159242, 98.531 + 25.1327 x}
  {0.00003259,   98.531 + 25.1327 x}

  {0.0000242625, 98.531 + 25.1327 x}
  {0.00457064,   98.531 + 25.1327 x}
  {0.00163333,   98.531 + 25.1327 x}
  {0.00708584,   98.531 + 25.1327 x}
*)

The second example is a little small for a speed test, but it was included because the OP's first method didn't handle it. We can make a more complicated example by raising poly1 to a power. The Simplify method is still a little faster than the others. Although @BobHanlon's Simplify @* Collect slows down relatively, it's still faster than ExpandAll @* Collect.

poly2 = poly1^10;

poly2 // Simplify // N // Expand // RepeatedTiming // First
poly2 /. E^y_ :> E^(y /. x -> 0.) // Expand // RepeatedTiming // First

poly2 // Simplify // Collect[#, x] & // N // RepeatedTiming // First
poly2 // ExpandAll // Collect[#, x] & // N // RepeatedTiming // First
Collect[poly2, x, Simplify] // N // RepeatedTiming // First
Collect[poly2, x, ExpandAll] // N // RepeatedTiming // First
(*
  0.0000417911
  0.0000496085

  0.000470552
  0.00525135
  0.00515953
  0.13587
*)
$\endgroup$
1
  • $\begingroup$ I was updating the question right now and then I saw your new message. Thanks for your time. I did some runs with a subset of my data and I confirm that using Simplify and Collect is a bit faster than ExpandAll. However, I found a faster fix: using N[ ,precision] before Collect reduces by a factor of 3x the time needed (I guess because I'm truncating the numbers to play with Collect?), but will not get rid of the ugly exponentials. However, using the option Collect[N[expr,precision],x,ReplaceAll[#,x->0]&] does the job very efficiently. I will add a detailed answer in a bit. $\endgroup$
    – Gnrdgr1594
    Apr 20, 2021 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.