123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- from sympy.core.singleton import S
- from sympy.core.symbol import Symbol
- from sympy.utilities import public
- @public
- def approximants(l, X=Symbol('x'), simplify=False):
- """
- Return a generator for consecutive Pade approximants for a series.
- It can also be used for computing the rational generating function of a
- series when possible, since the last approximant returned by the generator
- will be the generating function (if any).
- Explanation
- ===========
- The input list can contain more complex expressions than integer or rational
- numbers; symbols may also be involved in the computation. An example below
- show how to compute the generating function of the whole Pascal triangle.
- The generator can be asked to apply the sympy.simplify function on each
- generated term, which will make the computation slower; however it may be
- useful when symbols are involved in the expressions.
- Examples
- ========
- >>> from sympy.series import approximants
- >>> from sympy import lucas, fibonacci, symbols, binomial
- >>> g = [lucas(k) for k in range(16)]
- >>> [e for e in approximants(g)]
- [2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)]
- >>> h = [fibonacci(k) for k in range(16)]
- >>> [e for e in approximants(h)]
- [x, -x/(x - 1), (x**2 - x)/(2*x - 1), -x/(x**2 + x - 1)]
- >>> x, t = symbols("x,t")
- >>> p=[sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)]
- >>> y = approximants(p, t)
- >>> for k in range(3): print(next(y))
- 1
- (x + 1)/((-x - 1)*(t*(x + 1) + (x + 1)/(-x - 1)))
- nan
- >>> y = approximants(p, t, simplify=True)
- >>> for k in range(3): print(next(y))
- 1
- -1/(t*(x + 1) - 1)
- nan
- See Also
- ========
- See function sympy.concrete.guess.guess_generating_function_rational and
- function mpmath.pade
- """
- p1, q1 = [S.One], [S.Zero]
- p2, q2 = [S.Zero], [S.One]
- while len(l):
- b = 0
- while l[b]==0:
- b += 1
- if b == len(l):
- return
- m = [S.One/l[b]]
- for k in range(b+1, len(l)):
- s = 0
- for j in range(b, k):
- s -= l[j+1] * m[b-j-1]
- m.append(s/l[b])
- l = m
- a, l[0] = l[0], 0
- p = [0] * max(len(p2), b+len(p1))
- q = [0] * max(len(q2), b+len(q1))
- for k in range(len(p2)):
- p[k] = a*p2[k]
- for k in range(b, b+len(p1)):
- p[k] += p1[k-b]
- for k in range(len(q2)):
- q[k] = a*q2[k]
- for k in range(b, b+len(q1)):
- q[k] += q1[k-b]
- while p[-1]==0: p.pop()
- while q[-1]==0: q.pop()
- p1, p2 = p2, p
- q1, q2 = q2, q
- # yield result
- from sympy.polys.polytools import lcm
- from sympy.simplify import simplify as simp
- from sympy.simplify.radsimp import denom
- c = 1
- for x in p:
- c = lcm(c, denom(x))
- for x in q:
- c = lcm(c, denom(x))
- out = ( sum(c*e*X**k for k, e in enumerate(p))
- / sum(c*e*X**k for k, e in enumerate(q)) )
- if simplify:
- yield(simp(out))
- else:
- yield out
- return
|