def inverse_pade(f, x0, m, n): """ Padé approximant coefficients of the inverse of f. Given a callable f, and a point x0, find the Padé approximant of degree (m, n) of the inverse of f at x0. If y0 = f(x0), and if the inverse of f is g, this function returns the Padé approximant coefficients of g(y) at y0. f'(x0) must be nonzero. Examples -------- >>> import mpmath >>> mpmath.mp.dps = 40 Compute the Padé approximant to the inverse of sin(x) at x=1. >>> inverse_pade(mpmath.sin, 1, 5, 4) ([mpf('1.0'), mpf('-5.428836087225345782152614868037223199487785'), mpf('-14.59025586448337482707922792297134121701713'), mpf('76.66727054306441691994858675947043862200347'), mpf('20.92630843471146736348587129663693571301545'), mpf('-91.95538065543221755259217919809770565490541')], [mpf('1.0'), mpf('-7.279651804906271400064368109435873392958164'), mpf('-3.784426620962357975179374311522526358975659'), mpf('94.34419434777145262733458338059694153109452'), mpf('-114.4848137234397209897780633142520390436954')]) Compare that to computing the Padé approximant of the arcsine function directly. >>> c = mpmath.taylor(mpmath.asin, mpmath.sin(1), 10) >>> mpmath.pade(c, 5, 4) ([mpf('1.0'), mpf('-5.428836087225345782152614868037223199022362'), mpf('-14.59025586448337482707922792297134122127003'), mpf('76.66727054306441691994858675947043863057723'), mpf('20.92630843471146736348587129663693571903839'), mpf('-91.95538065543221755259217919809770566742443')], [mpf('1.0'), mpf('-7.279651804906271400064368109435873392492793'), mpf('-3.784426620962357975179374311522526364090111'), mpf('94.34419434777145262733458338059694154789217'), mpf('-114.4848137234397209897780633142520390591904')]) """ d = m + n + 1 c = inverse_taylor(f, x0, d) pc, qc = mpmath.pade(c, m, n) return pc, qc
def pade(t, n): """ pade approximation of a time delay, as per mathworks' controls toolkit. supports arbitrary precision mathematics via mpmath and sympy" for more information, see: * http://home.hit.no/~hansha/documents/control/theory/pade_approximation.pdf * http://www.mathworks.com/help/control/ref/pade.html """ # e**(s*t) -> laplace transform of a time delay with 't' duration # e**x -> taylor series taylor = mpmath.taylor(sympy.exp, 0, n * 2) (num, den) = mpmath.pade(taylor, n, n) num = sum([x * (-t * s)**y for y, x in enumerate(num[::-1])]) den = sum([x * (-t * s)**y for y, x in enumerate(den[::-1])]) return num / den
def pade_coefs(*, pade_order, k0, dx, alpha=0): mpmath.mp.dps = 63 if alpha == 0: def sqrt_1plus(x): return mpmath.mp.sqrt(1 + x) else: a_n, b_n = pade_sqrt_coefs(pade_order[1]) def sqrt_1plus(x): return pade_sqrt(x, a_n, b_n, alpha) def propagator_func(s): return mpmath.mp.exp(1j * k0 * dx * (sqrt_1plus(s) - 1)) t = mpmath.taylor(propagator_func, 0, pade_order[0] + pade_order[1] + 20) p, q = mpmath.pade(t, pade_order[0], pade_order[1]) num_coefs = np.array([complex(v) for v in p]) den_coefs = np.array([complex(v) for v in q]) return num_coefs[::-1], den_coefs[::-1]
def __init__(self, n): self.n = n mpmath.mp.dps = 100 def func(x): return mpmath.exp(-x) * mpmath.besseli(0, x) t = mpmath.taylor(func, 0, 2 * n + 1) self.p, self.q = mpmath.pade(t, n, n) # self.pade_coefs = list(zip_longest([-1 / complex(v) for v in mpmath.polyroots(p[::-1], maxsteps=2000)], # [-1 / complex(v) for v in mpmath.polyroots(q[::-1], maxsteps=2000)], # fillvalue=0.0j)) #self.pade_roots_num = [complex(v) for v in mpmath.polyroots(self.p[::-1], maxsteps=5000)] #self.pade_roots_den = [complex(v) for v in mpmath.polyroots(self.q[::-1], maxsteps=5000)] self.pade_coefs_num = [complex(v) for v in self.p] self.pade_coefs_den = [complex(v) for v in self.q] self.taylor_coefs = [complex(v) for v in t] a = [self.q[-1]] + [b + c for b, c in zip(self.q[:-1:], self.p)] self.a_roots = [ complex(v) for v in mpmath.polyroots(a[::-1], maxsteps=5000) ]
def pade_propagator_coefs(*, pade_order, diff2, k0, dx, spe=False, alpha=0): """ :param pade_order: order of Pade approximation, tuple, for ex (7, 8) :param diff2: :param k0: :param dx: :param spe: :param alpha: rotation angle, see F. A. Milinazzo et. al. Rational square-root approximations for parabolic equation algorithms. 1997. Acoustical Society of America. :return: """ mpmath.mp.dps = 63 if spe: def sqrt_1plus(x): return 1 + x / 2 elif alpha == 0: def sqrt_1plus(x): return mpmath.mp.sqrt(1 + x) else: a_n, b_n = pade_sqrt_coefs(pade_order[1]) def sqrt_1plus(x): return pade_sqrt(x, a_n, b_n, alpha) def propagator_func(s): return mpmath.mp.exp(1j * k0 * dx * (sqrt_1plus(diff2(s)) - 1)) t = mpmath.taylor(propagator_func, 0, pade_order[0] + pade_order[1] + 2) p, q = mpmath.pade(t, pade_order[0], pade_order[1]) pade_coefs = list( zip_longest([ -1 / complex(v) for v in mpmath.polyroots(p[::-1], maxsteps=2000) ], [-1 / complex(v) for v in mpmath.polyroots(q[::-1], maxsteps=2000)], fillvalue=0.0j)) return pade_coefs
def lambertw_pade(): derivs = [mpmath.diff(mpmath.lambertw, 0, n=n) for n in range(6)] p, q = mpmath.pade(derivs, 3, 2) return p, q
def lambertw_pade(): derivs = [] for n in range(6): derivs.append(mpmath.diff(mpmath.lambertw, 0, n=n)) p, q = mpmath.pade(derivs, 3, 2) return p, q
import mpmath def f(x): return (mpmath.pi + x + mpmath.sin(x)) / (2*mpmath.pi) # Note: 40 digits might be overkill; a few more digits than the default # might be sufficient. mpmath.mp.dps = 40 ts = mpmath.taylor(f, -mpmath.pi, 20) p, q = mpmath.pade(ts, 9, 10) p = [float(c) for c in p] q = [float(c) for c in q] print('p =', p) print('q =', q)