# How to predict the degree of the first series coefficient?

Given an expression f that is a function of x and a number x0, what is the least integer n that produces a non-zero coefficient in Series[f, {x, x0, n}]?

[1] For instance, here, is the answer is n = 1:

Series[Sqrt[x] (Exp[Sqrt[x]] - 1 - Sqrt[x]), {x, 0, 1}]
(*  SeriesData[x, 0, {Rational[1, 2]}, 3, 4, 2]  *)


[2] Here, it is n = 0:

Series[Sqrt[x]/(Exp[Sqrt[x]] - 1 - Sqrt[x]), {x, 0, 0}]
(*  SeriesData[x, 0, {2, Rational[-2, 3]}, -1, 1, 2]  *)


[3] Here, it is n = -1, lower than in the previous example, even though the order of vanishing is higher:

Series[x^Sqrt[2]/(Exp[Sqrt[x]] - 1 - Sqrt[x]), {x, 0, -1}]
(*  x^Sqrt[2] (SeriesData[x, 0, {2}, -2, -1, 2])  *)


[4] I'm particularly concerned about functions whose series are expensive to compute. I would like to avoid spending a lot of time computing Series[f, {x, 0, 0}] only to find that n has to be bigger than 0. Likewise, it seems inefficient to compute Series[f, {x, 0, 2}] if n = 0 would work. My intuition is that this latter case might in practice not be as bad as the first case of a failed Series, but I may be wrong. Here's a random example, but it doesn't show much difference between the two approaches (nor does it support my intuition):

ClearSystemCache[];
Series[Gamma[x^2] BesselJ[2, x]^2, {x, 0, 0}] // AbsoluteTiming
Series[Gamma[x^2] BesselJ[2, x]^2, {x, 0, 2}] // AbsoluteTiming

ClearSystemCache[];
Series[Gamma[x^2] BesselJ[2, x]^2, {x, 0, 4}] // AbsoluteTiming


Failing an efficient answer to the opening question, my principal objective at present is to find the first nonzero series coefficient. Example [3] is a type that occurs in practice. What is an efficient way to do determine the first nonzero series coefficient, if determining n exactly cannot be done quickly?

Note: It is possible that the function f has symbolic parameters. In my use-cases, I think numeric values may be substituted for them without annihilating the first term of the series. In general, of course this wouldn't be true.

• Can you give a closed list of all the allowed functions that you intend to consider? Say, only elementary functions + some Gamma, Bessel, and the like?. If so, it might be possible to pre-cacluate a catalog and then use it as the basis for guessing the minimal order Commented Oct 18, 2015 at 17:09
• @yohbs From a point of view localized to my anticipated needs, combinations of elementary functions, or just those that admit series expansions, would cover most or all cases. OTOH, having a general approach is both interesting to me and would allow for extension to cases that might prove interesting. Commented Oct 18, 2015 at 20:06
• For f1 the expression in the case [1], {Series[f1, {x, 0, 1}], Series[Series[f1, {x, 0, 1}] // Normal, {x, 0, 1}]} yields {SeriesData[x, 0, { Rational[1, 2]}, 3, 4, 2], SeriesData[x, 0, {}, 3, 3, 2]}. In other words, expressions with the same leading terms in their power series can yield different Series when taken to the same order. Commented Oct 19, 2015 at 4:52
• Should one assume that the function values are much cheaper to calculate than the series coeffs? Commented Oct 19, 2015 at 14:49
• @belisariusisforth That is my thinking. Doesn't mean it's right. But what I have in mind are all algebraic expressions in terms of standard functions. BTW, I now think I can do it with at most two calls to Series; not optimal, and I was hoping for an elegant solution. Commented Oct 19, 2015 at 17:37

The following approach seems to work most of the time for expressions with series that can be described by a single SeriesData, not multiplied by other function. This excludes case [3] in the question, to which I shall return. Note that I arrived at the approach by trial and error, and with limited trials I may have missed a lot of errors.

Define

ncal1[f_, x0_, dx_] := N[Log[2, (f /. x -> x0 + 2 dx)/(f /. x -> x0 + dx)]]
ncal[f_, x0_, dx_] := Module[{ntem = ncal1[f, x0, dx]},
Ceiling[Chop[ntem - Round[ntem], 10^2 dx] + Round[ntem]]]


dx should satisfy the Goldilocks criterion (not too large and not too small). Applying these functions to the four expressions in the question, named in the obvious way,

ncal1[#, 0, 10^-6] & /@ {f1, f2, f3, f4}
ncal[#, 0, 10^-6] & /@ {f1, f2, f3, f4}
(* {1.5002, -0.500199, 0.414014, 2.} *)
(* {2, 0, 1, 2} *)


The second and fourth answers from ncal agree with the corresponding values in the question. The f1 case is anomalous, as I mentioned in an earlier comment.

Series[f1, {x, 0, 3}]
(* SeriesData[x, 0, {1/2, 1/6, 1/24, 1/120, 1/720}, 3, 8, 2] *)
exp = % // Normal
(* x^(3/2)/2 + x^2/6 + x^(5/2)/24 + x^3/120 + x^(7/2)/720 *)
Series[exp, {x, 0, 3}]
(* SeriesData[x, 0, {1/2, 1/6, 1/24, 1/120}, 3, 7, 2] *)


For some reason, the series for f1 has one higher order term than the series of the series for f1. Hence, n = 2 is required for the power series of f1, but n = 1 is sufficient for f1 itself. Making Power Series Expansions discusses such behavior in a general way.

Here are more, admittedly simple, cases, for all of which the approach works.

{f5 = x^(-1/2) (x + x^2); nt = ncal[f5, 0, 10^-4], Series[f5, {x, 0, nt}] // Normal}
(* {1, Sqrt[x]} *)
{f6 = (1 + x + x^2); nt = ncal[f6, 0, 10^-4], Series[f6, {x, 0, nt}] // Normal}
(* {0, 1} *)
{f7 = (1/x + 1 + x + x^2); nt = ncal[f7, 0, 10^-4], Series[f7, {x, 0, nt}] // Normal}
(* {-1, 1/x *)
{f8 = Sum[x^i, {i, 3/2, 3, 1/2}]; nt = ncal[f8, 0, 10^-4], Series[f8, {x, 0, nt}] // Normal
(* {2, x^(3/2) + x^2} *)
{f9 = Sum[x^i, {i, 1/2, 2, 1/2}] + Sum[x^i, {i, 1/3, 2, 1/3}];
nt = ncal[f9, 0, 10^-4], Series[f9, {x, 0, nt}] // Normal}
(* {1, x^(1/3) + Sqrt[x] + x^(2/3) + 2 x *)
{f10 = Exp[Sqrt[x]] - 1; nt = ncal[f10, 0, 10^-4], Series[f10, {x, 0, nt}] // Normal}
(* {1, Sqrt[x] + x/2 *)
{f11 = Sin[x^(2/7)]; nt = ncal[f11, 0, 10^-4], Series[f11, {x, 0, nt}] // Normal}
(* {1, x^(2/7) - x^(6/7)/6} *)


At first glance, obtaining more than one term in some of these expressions may seem inconsistent with the goal of the question. However, this is the way Series works. Reducing n from 1 to 0 in the last case, for instance, yields

Series[Sin[x^(2/7)], {x, 0, 0}] // Normal
(* 0 *)


Now, consider an ostensibly very similar problem.

Series[Sin[x^Sqrt[2]], {x, 0, 2}]
(* Sin[x^Sqrt[2]] *)


Although Series can handle functions of rationale powers of x, it cannot handle functions of irrational powers. This seems like an unnecessary restriction.

As already noted, the approach in this answer does not work for case [3] and similar expressions containing irrational powers. However, it can be applied in this particular instance to

f3/Series[f3, {x, 0, -10}][[1]]
(* 1/(-1 + E^Sqrt[x] - Sqrt[x]) *)
{nt = ncal[%, 0, 10^-4], Series[%, {x, 0, nt}] // Normal}
(* {-1, 2/x} *)
%[[2]] Series[f3, {x, 0, -10}][[1]]
(* 2 x^(-1 + Sqrt[2]) *)


I imagine that the OP has in mind much more complex instances of case [3], however.

If computing multiple terms with fractional exponents, as in cases 8 through 11, is undesirable, the following work-around can be used. As an example, for f9,

lcd = LCM @@ Denominator@Cases[#, Power[x, Rational[zn_, zd_]] -> zn/zd, {0, Infinity}]
&[ft]
(nt = ncal[#, 0, 10^-4]; (Series[#, {x, 0, nt}] // Normal) /. x -> x^(1/lcd))
&[ft /. x -> x^lcd]
(* x^(1/3) *)


This same procedure can be applied to f1, yielding x^(3/2)/2 as in the question. Alternatively, if the answer is desired in SeriesData form,

lcd = LCM @@ Denominator@Cases[#, Power[x, Rational[zn_, zd_]] -> zn/zd, {0, Infinity}]
&[ft]
(nt = ncal[#, 0, 10^-4]; t = Series[#, {x, 0, nt}];
ReplacePart[t, -1 -> lcd t[[-1]]]) &[f1 /. x -> x^lcd]
(* SeriesData[x, 0, {1/2}, 3, 4, 2] *)


Incidentally, just as Series does not accept variables raised to irrational powers, it also does not accept variables raised to approximate-number powers.

Series[Sin[x^N[Sqrt[2], 6]], {x, 0, 4}]
(* Sin[x^1.41421] *)

• Thanks (+1). I didn't get pinged when you undeleted & updated. The numerical method seems quite good when those irrational powers are absent. For things like f3, I suppose the trick is to estimate the -10. I don't know if the number and order of the factors is reliable, but maybe f3/(Series[f3, {x, 0, -10}] /. _SeriesData -> 1) is safer. Commented Oct 20, 2015 at 17:11
• The -10 is simply a large negative number. Anything large enough will do, I believe. I have some additional ideas, which I shall add tonight, when I have time. My original response did not really answer your question, as I realized moments after I submitted it and then reread the question. Commented Oct 20, 2015 at 17:47