Re: LegendreP Evaluation Mystery

• To: mathgroup at smc.vnet.net
• Subject: [mg75247] Re: LegendreP Evaluation Mystery
• From: Roman <rschmied at gmail.com>
• Date: Sat, 21 Apr 2007 23:17:58 -0400 (EDT)
• References: <evvaqs\$95r\$1@smc.vnet.net><f013r8\$8ih\$1@smc.vnet.net>

```Antonio:

> Well if I try to evaluate LegendreP numerically by recursion relation, no=
t only will it be slow but also carry on any round offs up to the high n's =
I am interested in.

I think you misunderstand here: all numbers will always carry a
roundoff on the order of the machine precision, but this is not a
problem unless this error exponentially (or otherwise badly) increases
during each step of a recursion relation. If you have a stable
recursion, this is not a problem, and is indeed how things are done
properly.

> Since I need all {n,m}'s up to the big ones none, I think it is best to h=
ave the extended function (polynimial) determined by Rodrigues.

Again, not really. Evaluating high-order polynomials numerically is
not a simple issue, as you can see in Numerical Recipes, section on
"evaluation of functions" - "polynomials and rational functions".

Abramowitz and Stegun list some useful recursion relations, and I've
assembled a procedure that will generate all the LegendreP[n,m,x] for
all {n,m} up to a given value:

first, define a list of coefficients to be used later, to speed things
up a little:

coefflist[n_] := coefflist[n] = N[Table[{1/a-1, 2-1/a}, {a,1,n}]]

make a list of LegendreP[a,z] for a=0..n by recursion of the formula
P[n,z] = (2-1/n)*z*P[n-1,z]-(1-1/n)*P[n-2,z]

P0list[n_, z_] := Transpose[FoldList[{#1[[2]], ({1, z}#1).#2} &,
{0,1}, coefflist[n]]][[2]]

lastly, from these P[n,z] compute the associated Legendre polynomials
from the formula
P[n,m+1,z] = ((n-m)*z*P[n,m,z]-(n+m)*P[n-1,m,z])/sqrt(1-z^2)

Plist[n_, z_] := Module[{zz,nextm},
zz = 1/Sqrt[1-z^2];
nextm[m_, p_] := MapIndexed[zz(#2[[1]] z #1[[2]]-(2m
+#2[[1]])#1[[1]])&,
Transpose[{Most[p],Rest[p]}]];
FoldList[nextm[#2,#1]&, P0list[n,z], Range[0,n-1]]]

Now if you call Plist[10,0.3] it will calculate all the P[n,m,0.3] for
n=0..10 and m=0..n

This should be fast and numerically stable. Maybe you can make it even
faster by using Compile[]; please ask if you need help with that.

Roman.

On Apr 20, 6:52 am, "Antonio Neves" <ane... at gmail.com> wrote:
> Dear Carl and list members,
>
> Thank you for your suggestions. I believe that maybe the extended
> precision arithmatic would be too time consuming, but the posibility
> of using Function Interpolation seems interesting.
>
> It is now clear to me that with the "Set" instead of Set Delayed the
> polynomial and not the LegendreP is passed on. But still, when doing a
> plot, why is there a problem with tha evaluation of LegendreP? As in,
>
> n = 49; m = 12;
> Plot[Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m, x], {x,
>           0, 1}, PlotRange -> All, PlotPoints -> 200,
>        PlotLabel -> "LegendreP[n,m,x]"];
>
> I suppose that LegendreP[n,m,x] will behave the same way inside Plot
> as in NIntegrate, true? Using "Set", as you said in your post, I
> obtain a smooth curve, without apart numerical singularity around
> x=0.6.
>
> n = 49; m = 12;
> NewFunc[n_, m_,
>  x_] = Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m, x];
> Plot[NewFunc[n, m, x], {x, 0, 1}, PlotRange -> All,
>                      PlotPoints -> 200, PlotLabel -> "NewFunc[n,m,x]"];
>
> This I do not know how to explain and it seems to be a problem of how
> LegendreP[n,m,x] is evaluated. But lets say, okay, lets have a lower
> m, such as m=1. Then,
>
> n = 49; m = 1;
> NewFunc[n_, m_,
> x_] = Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m, x];
> Plot[NewFunc[n, m,
>           x], {x, 0, 1}, PlotRange -> All, PlotPoints -> 200, PlotLabel -=
> "
>         NewFunc[n,m,x]"];
> Plot[Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m,
>     x], {x, 0, 1}, PlotRange -> All, PlotPoints -> 200, PlotLabel -> "
>       LegendreP[n,m,x]"];
>
> Yes we see some numerical instabilities, probably due to standard machine
> precision, when we get nearer to x=1 (due to the (1-x)^(1/2) terms in
> the polinomial). But then again, if we use,
>
> Pnm = Table[(-1)^m*((Sqrt[((2*n + 1)*(
>         n - m)!)/((4*
>                   Pi)*(n + m)!)]*(1 - x^2)^(m/2)*D[(x^2 - 1)^
>                     n, {x, n + m}])/(n!*2^n)), {n, 1, 51}, {m, 0, n}];
> PnmO = Map[Experimental`OptimizeExpression, Pnm, {2}];
> PnmC = Map[(Compile[{{x, _Real}}, #]) &, PnmO, {2}];
> P[n_, m_, x_?NumericQ] := PnmC[[n, m + 1]][x];
> n = 49; m = 1;
> Plot[Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[
>       n, m, x], {x, 0, 1}, PlotRange -> All,
>      PlotPoints -> 200, PlotLabel -> "LegendreP[n,m,x]"];
> Plot[P[n, m, x], {x, 0, 1}, PlotRange -> All, PlotPoints ->
>        200, PlotLabel -> "P[n,m,x]"];
>
> We obtain P[n,m,x] as a curve without the numerical instabilities as
> the NewFunc[n,m,x] above, and without the singular type behaviour as
> LegendreP[n,m,x]. I am using Mathematica 5.2.0.0 on Windows XP 32-bit
> system, I do not know if the singularities/numerical instabilities
> appears for 64bit system.
>
> And finally, my problematic integral that resulted in this query.
>
> (* Some typical values *)
> nGlass = 1.55;
> nWater = 1.33;
> Crit = ArcSin[nWater/nGlass];
> ko = 7.98;
> zo = 0.03;
> d = 50.0;
> fw = 0.68;
>
> (*The Integral*)
> IntFunc[(n_Integer)?Positive, (m_Integer)?NonNegative, (r_Real)?Positive]=
:=
>    Block[{func}, func[(a_)?NumericQ] := I^(n - m)*Cos[a]*Sqrt[((2*n +
> 1)/(n*(n + 1)))*((n - m)!/(n + m)!)]*Sqrt[Cos[a]]*Exp[-(fw*Sin[a])^2]*
>        Exp[(-I)*ko*nWater*zo*Sqrt[1 -
> (nGlass*(Sin[a]/nWater))^2]]*Exp[(-I)*ko*d*(nGlass*Cos[a] -
> nWater*Sqrt[1 - (nGlass*(Sin[a]/nWater))^2])]*
>        (m^2*LegendreP[n, m, Sqrt[1 -
> (nGlass*(Sin[a]/nWater))^2]]*(BesselJ[m,
> ko*nGlass*r*Sin[a]]/(ko*nGlass*r*Sin[a]*
>            (nGlass*Cos[a] + nWater*Sqrt[1 - (nGlass*(Sin[a]/nWater))^2]))=
) -
>         ((1/2)*(BesselJ[-1 + m, ko*nGlass*r*Sin[a]] - BesselJ[1 + m,
> ko*nGlass*r*Sin[a]]))*
>          (((-1 - n)*Sqrt[1 - (nGlass*(Sin[a]/nWater))^2]*LegendreP[n,
> m, Sqrt[1 - (nGlass*(Sin[a]/nWater))^2]] +
>            (1 - m + n)*LegendreP[1 + n, m, Sqrt[1 -
> (nGlass*(Sin[a]/nWater))^2]])/(nWater*Cos[a] + nGlass*Sqrt[1 -
> (nGlass*(Sin[a]/nWater))^2])));
>      NIntegrate[func[a], {a, 0, Crit}, AccuracyGoal -> Infinity,
> PrecisionGoal -> 7, MaxRecursion -> 30, MinRecursion -> 6, Method ->
> DoubleExponential,
>       Compiled -> False, SingularityDepth -> 1000]];
>
> Trying,
>
> n = 50; m = 4; r = 3.21;
> IntFunc[n, m, r]
>
> Takes too long to evaluate, I believe is LegendreP[n,m,x] is the
> bottleneck, and I need to determine for each element of a grid as in,
>
> Grid = Table[{n, m, r}, {0, 70}, {m, 0, n}, {r, 0.001, 5, .1}];
>
> Carl, how do you suggest to use Function Interpolation?
>
> Regards,
> Antonio
>
> On 4/19/07, Carl Woll <c... at wolfram.com> wrote:
>
> > Antonio wrote:
>
> > >On 17 abr, 01:19, "Norbert Marxer" <mar... at mec.li> wrote:
>
> > >>On 16 Apr., 10:06, "Antonio" <ane... at gmail.com> wrote:
>
> > >>>Dear all,
>
> > >>>I have found that Mathematica v5.2 evaluates BesselJ and LegendreP
> > >>>differently. Why is this? I have written this test below to illustra=
te
> > >>>the timing.
>
> > >>>In[11]:=
> > >>>k=10000;
> > >>>n=51;
> > >>>m=Random[Integer,{0,n}];
> > >>>x=Random[Real,{0,1}];
> > >>>P[y_]=LegendreP[n,m,y];
> > >>>J[y_]=BesselJ[n,y];
> > >>>Timing[Do[LegendreP[n,m,x],{k}]]
> > >>>Timing[Do[P[x],{k}]]
> > >>>Timing[Do[BesselJ[n,x],{k}]]
> > >>>Timing[Do[J[x],{k}]]
>
> > >>>Out[17]=
> > >>>{4.531 Second,Null}
>
> > >>>Out[18]=
> > >>>{0.484 Second,Null}
>
> > >>>Out[19]=
> > >>>{0.61 Second,Null}
>
> > >>>Out[20]=
> > >>>{0.657 Second,Null}
>
> > >>>The emphasis here is with the Associated Legendre Function, since it=
is
> > >>>a bottel neck of my current calculations for big n's (n>50), used
> > >>>inside NIntegrate. The form LegendreP[n,m,x] takes longer to evaluate
> > >>>than in extended form (P[y])? If I try to use the extended form to do
> > >>>some numerical integration, it results in a wrong result even though
> > >>>it is faster.
>
> > >>>When plotting the functions, it seems to show some numerical
> > >>>instabilities (for low m):
>
> > >>>n = 51; m = 3;
> > >>>Plot[LegendreP[n, m, x], {x, 0, 1}, PlotRange -> All, PlotPoints ->
> > >>>100];
> > >>>Plot[P[x], {x, 0, 1}, PlotRange -> All, PlotPoints -> 100];
>
> > >>>And it is worse for m=0. Does Mathematica evaluate LegendreP
> > >>>differently for high n's, why does it take so long? Is there any way
> > >>>that I build an array of extended Associated Legendre functions, so =
as
> > >>>to speed up calculations and wouldn't fail numerically as above?
>
> > >>>Antonio
>
> > >>Hello
>
> > >>If you use SetDelayed (:=) instead of Set (=) in your defintions =
for
> > >>m, x, P and J then all your mysteries and questions will (probably)
> > >>evaporate.
>
> > >>With your definition the random numbers are evaluated only once and
> > >>therefore m is constant.
>
> > >>Similarly your associated Legendre polynomial (P) is evaluated only
> > >>once (for specific values of n and m) and set to a specific constant
> > >>polynomial with the independent variable y. The evaluation of this
> > >>polynomial takes obviously less time than the calculation and
> > >>evaluation of the associated Legendre polynomial.
>
> > >>Best Regards
> > >>Norbert Marxer- Ocultar texto entre aspas -
>
> > >>- Mostrar texto entre aspas -
>
> > >Dear Norbert and list members,
>
> > >The Set instead of SetDelayed, was purposely placed so it will be
> > >evaluated only once.
>
> > If you use Set, you are *not* using Mathematica's algorithm for
> > computing LegendreP functions. Notice:
>
> > In[11]:=P1[x_] =  LegendreP[4, 3, x]
> > Out[11]= -105 x (1 - x^2)^(3/2)
>
> > does not have the head LegendreP. So, when evaluating P1[.7], you are
> > evaluating the expression -105 .7 (1 - .7^2)^(3/2) and not the
> > expression LegendreP[4,3,.7]. Mathematica is smart enough to figure out
> > a good machine precision approximation to LegendreP[4,3,.7]. On the
> > other hand, Mathematica knows nothing about the expression -105 x
> > (1-x^2)^(3/2), so all it can do is plug in .7 and use standard machine
> > precision arithmetic. For n=4, m=3, plugging in .7 and using arithm=
etic
> > produces a reasonable answer. For large n, small m, standard machine
> > precision arithmetic will typically produce a completely incorrect
> > answer due to numeric instability.
>
> > Perhaps you can give a simple example of the integrals you are trying to
> > evaluate. Some possible remedies might include using extended precision
> > arithmetic with the polynomial form of the LegendreP functions, or using
> > FunctionInterpolation to create a substitute for the LegendreP function=
s=2E
>
> > Carl Woll
> > Wolfram Research
>
> > >The problem with the example above is that the extended function
> > >numerical result isn't identical with the one for LegendreP[n,m,x]
> > >function. So does Mathematica evaluate LegendreP with a different
> > >algorithm for low and high n's?
>
> > >Any help with this question is appreciated.
>
> > >Anyhow continuing to determine accuratelly an extended form for
> > >associated LegendreP of high n's, I wrote:
>
> > >P1 = Table[Sqrt[((2*n + 1)*(n - m)!)/((4*Pi)*(n + m)!)]*LegendreP[n,
> > >m, x], {n, 1, 52}, {m, 0, n}];
> > >P2 = Table[(-1)^m*((Sqrt[((2*n + 1)*(n - m)!)/((4*Pi)*(n + m)!)]*(1 -
> > >x^2)^(m/2)*D[(x^2 - 1)^n, {x, n + m}])/(n!*2^n)), {n, 1, 52},
> > >    {m, 0, n}];
> > >A[n_, m_, y_] := P1[[n,m + 1]] /. x -> y;
> > >B[n_, m_, y_] := P2[[n,m + 1]] /. x -> y;
>
> > >This defines P1 using Mathematicas algoritm for LegendreP, and P2
> > >using Rodrigues.
> > >When plotting, for a particular n (big),m (Note that I have included a
> > >normalization factor to avoid big numbers, Sqrt[...]):
>
> > >n = 49; m = 12;
> > >Plot[Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m, x],
> > >{x, 0, 1}, PlotRange -> All, PlotPoints -> 100,
> > >   PlotLabel -> "LegendreP"];
> > >Plot[A[n, m, x], {x, 0, 1}, PlotRange -> All, PlotPoints -> 100,
> > >PlotLabel -> "P1"];
> > >Plot[B[n, m, x], {x, 0, 1}, PlotRange -> All, PlotPoints -> 100,
> > >PlotLabel -> "P2"];
> > >Plot[Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m, x] -
> > >A[n, m, x], {x, 0, 1}, PlotRange -> All, PlotPoints -> 100,
> > >   PlotLabel -> "LegendreP-P1"];
> > >Plot[Sqrt[((2*n + 1)/(4*Pi))*((n - m)!/(n + m)!)]*LegendreP[n, m, x] -
>
> ...
>
> read more =BB

```

• Prev by Date: RootSum
• Next by Date: Integration of rational functions (reprise!)
• Previous by thread: Re: Re: LegendreP Evaluation Mystery
• Next by thread: what does this error message mean