3

When simplifying an expression by hand, a trick that is often used is to remove terms that are lower powers of the independent variable, for instance, as $x \rightarrow \infty$,

$x^2 + x$

becomes simply

$x^2$

I am trying to replicate this functionality in Mathematica. Limit seems like an obvious choice, but

Limit[x^2 + x, x -> ∞]

simply returns $∞$ (not terribly helpful). Another option is Series, but it seems that one has to pass the highest power in the expression to get the desired result, with

Normal@Series[x^2 + x, {x, ∞, -2}]

returning the expected $x^2$. However, this does not work in general for more complicated expressions, when the highest power may not be so obvious. Consider the following example:

$\frac{x^2+x}{x+1}$

Mathematica code

(x^2+x)/(x+1)

We expect that the limiting form of this expression as $x \rightarrow \infty$ should be $x$ (the top becomes $x^2$, the bottom becomes $x$, and this then simplifies to $x$). However, if you just use the highest power available, Series returns 0 (you have to actually use Normal@Series[x^2 + x, {x, ∞, -1}]).

My question is, can anyone produce a generalized piece of code that can produce a limiting expression? It would be good if the procedure handled the other extreme as well, when the variable in question approaches 0 (in which case $x^2 + x$ would simplify to $x$).

Edit: It seems that the main issue for the solutions presented so far is that the form of the expression is not consistent. These operations are relatively easy to perform by hand, but sometimes tedious, which is why it would be nice to have Mathematica do it for me! Here's a pathological example that I can reduce by hand and for which the accepted solution should be able to return the correct result:

$\frac{\sqrt{x^3 + x}}{x^5 + x + 1} \frac{x^2}{x^{10} + x} + \frac{x^5 + x}{x}$

Mathematica code

Sqrt[x^3 + x]/(x^5 + x + 1) x^2/(x^10 + x) + (x^5 + x)/x

(The right answer is $x^4$)

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
Guillochon
  • 6,117
  • 2
  • 31
  • 57

4 Answers4

7

Method I

(1) Take series at infinity to get a (Laurent) polynomial.

(2) Find largest exponent.

(3) Find corresponding coefficient.

mainTerm[expr_, x_] := Module[
  {approxpoly, prec = 1, j = 0, expon, coef},
  approxpoly = Normal[Series[expr, {x, Infinity, prec}]];
  While[approxpoly === 0 && j <= 5,
   j++;
   prec = 2*prec + j;
   approxpoly = Normal[Series[expr, {x, Infinity, prec}]];
   ];
  approxpoly = PowerExpand@approxpoly;
  expon = Exponent[approxpoly, x];
  coef = Coefficient[approxpoly, x, expon];
  coef*x^expon
  ]

Example:

In[83]:= mainTerm[(x^3 + 1)/(x + 1), x]

(* Out[83]= x^2 *)

Method II

(1) Take the series at infinity to get a Laurent polynomial.

(2) Homogenize it wrt a new variable.

(3) Set that new variable to zero.

homogenize[poly_, vars_, new_] := 
 Module[{degfunc, totdeg, j}, 
  degfunc = Apply[Plus, Map[Function[x, Exponent[#, x] &], vars]];
  degfunc = Distribute[degfunc, Function, Plus];
  totdeg = Max[Map[degfunc, Apply[List, poly]]];
  Apply[Plus, 
   Table[poly[[j]]*new^(totdeg - degfunc[poly[[j]]]), {j, 
     Length[poly]}]]]

mainTerm2[expr_, x_] := Module[
  {approxpoly, prec = 1, j = 0, hpoly, y},
  approxpoly = Normal[Series[expr, {x, Infinity, prec}]];
  While[approxpoly === 0 && j <= 5,
   j++;
   prec = 2*prec + j;
   approxpoly = Normal[Series[expr, {x, Infinity, prec}]];
   ];
  hpoly = homogenize[approxpoly, {x}, y];
  hpoly /. y -> 0
  ]

Example:

In[91]:= mainTerm2[(x^3 + 1)/(x + 1), x]

(* Out[91]= x^2 *)

--- edit ---

For getting the asymptotic behavior at the origin you can do as follows.

(1) Replace x by 1/x. (2) Get the asymptotic term at infinity. (3) Transform back with x->1/x.

mainTermAtOrigin[expr_, x_] := 
 mainTerm[expr /. x -> 1/x, x] /. x -> 1/x

Example:

mainTermAtOrigin[(x^2 + 1)/(x + 1) - 1/x, x]

(* Out[106]= -(1/x) *)

--- end edit ---

--- edit 2 ---

After adding a PowerExpand to deal appropriately with fractional power issues, we can wotk with Puisieux expansions. Here is an example.

ee = Sqrt[x^3 + x]/(x^5 + x + 1)*x^2/(x^10 + x^7) + (x^5 + x)/x;

In[170]:= mt = mainTermAtOrigin[ee, x]

(* Out[170]= (1/x)^(9/2) *)

We can test that this is correct by checking whether the expression divided by it approaches unity as x goes to zero.

In[171]:= Limit[ee/mt, x -> 0]

(* Out[171]= 1 *)
Daniel Lichtblau
  • 58,970
  • 2
  • 101
  • 199
  • Verified that this works for my pathological example. How about as $x \rightarrow 0$? – Guillochon Aug 28 '12 at 17:52
  • Also, any particular reason for the j <= 5? – Guillochon Aug 28 '12 at 17:57
  • The limitation on j is just to prevent it from going forever on pathological examples. It will of course break in such cases. I did not put in error checking but that isn't too hard. – Daniel Lichtblau Aug 28 '12 at 18:04
  • See edit for handling at origin – Daniel Lichtblau Aug 28 '12 at 18:11
  • @Guillochon You can't expect it to work straight forward. When $x \rightarrow 0$ you are looking for the smallest power, while $x \rightarrow \infty$, you are looking for the greatest. If you are only interested on the order, a simple solution for rational functions would be something like (Exponent[Numerator[#],x]-Exponent[Denominator[#],x]) & @ rational[x] for the case $x \rightarrow \infty$. In the case $x \rightarrow 0$, (Exponent[Numerator[#],x,Min]-Exponent[Denominator[#],x,Min]) & @ rational[x] – Pragabhava Aug 28 '12 at 18:38
  • @Manuel (1) I'm not Guillochon. (2) The method I show above, with a modest change to handle fractional powers, appears to work alright at the origin. – Daniel Lichtblau Aug 28 '12 at 20:09
  • @DanielLichtblau My comment was aimed to the one by Guillochon, about the code working as is when $x \rightarrow 0$, and it was made before your edits. It wasn't intended to diss your answer, but to show the OP that is not trivial to work with divergent series. That's why you cannot feed any expression to Series and expect Mathematica to return a valid expansion. – Pragabhava Aug 28 '12 at 23:21
  • @Manuel I agree finding asymptotic terms is nontrivial. What I show will only handle bona fide Puiseux series. – Daniel Lichtblau Aug 29 '12 at 13:57
4

The solution to this requires just a minor modification of my answer here:

ClearAll[limitingTerm1]
SetAttributes[limitingTerm1, HoldAll]
limitingTerm1[expr_, var_Symbol, func_] := var^Exponent[#, var, func] &@Simplify[expr]

This gives the right answer for both the examples provided by the OP:

limitingTerm1[(x^2 + x)/(x + 1), x, Max]
(* x *)

limitingTerm1[Sqrt[x^3 + x]/(x^5 + x + 1) x^2/(x^10 + x) + (x^5 + x)/x, x, Max]
(* x^4 *)

One can now generalize this to polynomials with arbitrary coefficients. It works as a two-pass approach, where the second pass is applied to the result of the first if its denominator still contains an x term. This seems to work very well in examples I've tested, but it might be possible to find edge cases where it doesn't work. Nevertheless, some modifications and extensions along these lines should help solve it.

ClearAll[limitingTerm2]
SetAttributes[limitingTerm2, HoldAll]
limitingTerm2[expr_, var_Symbol, func_] := Module[{term},
    term := With[{pow = Exponent[#, var, func]}, Coefficient[#, var, pow] var^pow] &;
    If[FreeQ[Denominator@#, x], #, term@Apart@#] &@term@Simplify[expr]
]

limitingTerm2[(a x^2 + bx)/(d + c x), x, Max]
(* (a x)/c *)

It also gives the correct answer for the other examples above.

rm -rf
  • 88,781
  • 21
  • 293
  • 472
  • For the second example, if I pass Min, it returns $O[x]^1$. Shouldn't it be $O[x]^0$? The first term reduces to $x^{3/2}$, the second to 1, so the limiting order is 0th, no? – Guillochon Aug 28 '12 at 18:09
  • @Guillochon Yes, I had removed the constant term for the previous usage, which was left behind in this. The above definition is far simpler and should give you 0 if you pass Min for the second example. – rm -rf Aug 28 '12 at 18:17
  • Great...I guess the last bit of functionality I would like is to include any coefficients, if they exist. So for instance $\frac{ax^2 + bx}{cx + d}$ should return $\frac{a}{c}x$. – Guillochon Aug 28 '12 at 18:21
  • This is a great answer, as it works the same way one would calculate the asymptotic expansion by hand. In the case of rational polynomials it's very straight forward, but for more complicated functions, one has to calculate the divergent part first, then feed the convergent part to Series. – Pragabhava Aug 28 '12 at 18:23
  • @Guillochon See my edit – rm -rf Aug 28 '12 at 18:42
  • @R.M Great, this is exactly what I was looking for. Accepted. – Guillochon Aug 28 '12 at 18:44
  • @R.M In case of rational functions it wont be that hard. One would factor the leading order for the numerator and denominator (i.e. Exponent @ Numerator), then apply Series to the rest of the rational function. My approach would be, if $r(x)=\frac{a_0+...+a_n x^n}{b0+...+b_m x^m}$, the asymptotic expansion to order $j$ would be x^(n-m) Series[a_0 x^(-n)+...+a_n,{x,Infinity,j}] Series[(b_0 x^(-m)+...+b_m)^(-1),{x,Infinity,j}]. I'd do it but with my poor programming skills, it would take forever. – Pragabhava Aug 28 '12 at 18:50
2

For finding the leading term of an asymptotic expansion, you can use the answer I gave to Get leading series expansion term?:

leadingSeries[expr_, {x_, x0_}] := Normal[
    expr /. 
        x -> Series[x, {x, x0, 1}] /.
        Verbatim[SeriesData][a__, {b_, ___}, c__] :> SeriesData[a, {b}, c]
]

For your examples:

leadingSeries[x^2+x, {x, Infinity}]
leadingSeries[(x^2+x)/(x+1), {x, Infinity}]
leadingSeries[Sqrt[x^3+x]/(x^5+x+1) x^2/(x^10+x)+(x^5+x)/x, {x, Infinity}]

x^2

x

x^4

The accepted answer gives an incorrect result for something like:

expr = 1 + x + Sqrt[x^5]/(x+1);

limitingTerm1[expr, x, Max]
leadingSeries[expr, {x, Infinity}]

x

x^(3/2)

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
0

This works for me:

Normal@Series[((x^2 + x ) / (x + 1) ) , {x, Infinity, 1}] -> x

or this..

Normal@Series[((x^2 + x ) / (x + 1) /. x -> 1/y ) , {y, 0, 1}] /.  y -> 1/x

Note this example is a case where there is not a Taylor series, but Series[] is being smart for you and returning a negative power solution, which should give a clue why a fully general method is going to be problematic.

Edit another approach:

n = 0;
While[ (lim = Limit[(1/x)^n (x^3 + x ) / (x + 1)  , x -> Infinity]) ==  Infinity , n++];
lim x^(n)

Obvoulsly you'd want to limit n to prevent runaway.

I'm suspecting your question isn't mathematically well posed. Suppse the "limit" is a Log[x], do you expect your 'general' approach to pick that up?

george2079
  • 38,913
  • 1
  • 43
  • 110
  • Unfortunately, this solution is no better than the series solution I prescribed, as it only works for that specific fraction. Change the $x^2$ to $x^3$ and it no longer works. I'm looking for a solution that can simplify arbitrary polynomial expressions. – Guillochon Aug 28 '12 at 17:30
  • No, only polynomial expressions. I have edited the question title. – Guillochon Aug 28 '12 at 18:01