Laguerre polynomials in python using scipy, lack o

2019-08-31 02:19发布

问题:

The laguerre polynomials don't seem to be converging at some orders as can be demonstrated by running the following code.

import numpy as np
from sympy import mpmath as mp
from scipy.special import genlaguerre as genlag
from sympy.mpmath import laguerre as genlag2
from matplotlib import pyplot as plt

def laguerre(x, r_ord, phi_ord, useArbitraryPrecision=False):
    if (r_ord < 30 and phi_ord < 30) and not useArbitraryPrecision:
        polyCoef = genlag(r_ord, phi_ord)
        out = np.polyval(polyCoef, x)
    else:
        fun = lambda arg: genlag2(r_ord, phi_ord, arg)
        fun2 = np.frompyfunc(genlag2, 3, 1)
        # fun2 = np.vectorize(fun)
        out = fun2(r_ord, phi_ord, x)
    return out

r_ord = 29
phi_ord = 29
f = lambda x, useArb : mp.log10(laguerre(x, 29, 29, useArb))
mp.plot(lambda y : f(y, True) - f(y, False), [0, 200], points = 1e3)
plt.show()

I was wondering if anyone knew what is going on or of any accuracy limitations of the scipy function? Do you recommend I simply use the mpmath function? At first I thought it might be that after a certain order it doesn't work but for (100, 100) it seems to be working just fine.

by running

mp.plot([lambda y : f(y, True), lambda y: f(y, False)], [0, 200], points = 1e3)

you get the following image where the discrepancy becomes pretty clear.

Any help appreciated.

Let me know if anything needs clarification.

回答1:

Using polyval with high-order polynomials (about n > 20) is in general a bad idea, because evaluating polynomial using the coefficients (in power basis) will start giving large errors in floating point at high orders. The warning in the Scipy documentation tries to tell you that.

You should use scipy.special.eval_genlaguerre(r_ord, phi_ord, float(x)) instead of genlaguerre + polyval; it uses a stabler numerical algorithm for evaluating the polynomial.



回答2:

Instead of using scipy.special.eval_genlaguerre to evaluate a high-degree polynomial as pv suggested, you can also use numpy.polynomial.Laguerre as explained in the NumPy documentation.

Unfortunately, it doesn't seem to provide a function for generalized Laguerre polynomials.

import numpy as np
from numpy.polynomial import Laguerre
p = Laguerre([1, -2, 1])
x = np.arange(5)
p(x)

NumPy output: 0, 0.5, 2, 4.5, 8