Coverage for /usr/lib/python3/dist-packages/sympy/series/formal.py: 17%
776 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""Formal Power Series"""
3from collections import defaultdict
5from sympy.core.numbers import (nan, oo, zoo)
6from sympy.core.add import Add
7from sympy.core.expr import Expr
8from sympy.core.function import Derivative, Function, expand
9from sympy.core.mul import Mul
10from sympy.core.numbers import Rational
11from sympy.core.relational import Eq
12from sympy.sets.sets import Interval
13from sympy.core.singleton import S
14from sympy.core.symbol import Wild, Dummy, symbols, Symbol
15from sympy.core.sympify import sympify
16from sympy.discrete.convolutions import convolution
17from sympy.functions.combinatorial.factorials import binomial, factorial, rf
18from sympy.functions.combinatorial.numbers import bell
19from sympy.functions.elementary.integers import floor, frac, ceiling
20from sympy.functions.elementary.miscellaneous import Min, Max
21from sympy.functions.elementary.piecewise import Piecewise
22from sympy.series.limits import Limit
23from sympy.series.order import Order
24from sympy.series.sequences import sequence
25from sympy.series.series_class import SeriesBase
26from sympy.utilities.iterables import iterable
30def rational_algorithm(f, x, k, order=4, full=False):
31 """
32 Rational algorithm for computing
33 formula of coefficients of Formal Power Series
34 of a function.
36 Explanation
37 ===========
39 Applicable when f(x) or some derivative of f(x)
40 is a rational function in x.
42 :func:`rational_algorithm` uses :func:`~.apart` function for partial fraction
43 decomposition. :func:`~.apart` by default uses 'undetermined coefficients
44 method'. By setting ``full=True``, 'Bronstein's algorithm' can be used
45 instead.
47 Looks for derivative of a function up to 4'th order (by default).
48 This can be overridden using order option.
50 Parameters
51 ==========
53 x : Symbol
54 order : int, optional
55 Order of the derivative of ``f``, Default is 4.
56 full : bool
58 Returns
59 =======
61 formula : Expr
62 ind : Expr
63 Independent terms.
64 order : int
65 full : bool
67 Examples
68 ========
70 >>> from sympy import log, atan
71 >>> from sympy.series.formal import rational_algorithm as ra
72 >>> from sympy.abc import x, k
74 >>> ra(1 / (1 - x), x, k)
75 (1, 0, 0)
76 >>> ra(log(1 + x), x, k)
77 (-1/((-1)**k*k), 0, 1)
79 >>> ra(atan(x), x, k, full=True)
80 ((-I/(2*(-I)**k) + I/(2*I**k))/k, 0, 1)
82 Notes
83 =====
85 By setting ``full=True``, range of admissible functions to be solved using
86 ``rational_algorithm`` can be increased. This option should be used
87 carefully as it can significantly slow down the computation as ``doit`` is
88 performed on the :class:`~.RootSum` object returned by the :func:`~.apart`
89 function. Use ``full=False`` whenever possible.
91 See Also
92 ========
94 sympy.polys.partfrac.apart
96 References
97 ==========
99 .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf
100 .. [2] Power Series in Computer Algebra - Wolfram Koepf
102 """
103 from sympy.polys import RootSum, apart
104 from sympy.integrals import integrate
106 diff = f
107 ds = [] # list of diff
109 for i in range(order + 1):
110 if i:
111 diff = diff.diff(x)
113 if diff.is_rational_function(x):
114 coeff, sep = S.Zero, S.Zero
116 terms = apart(diff, x, full=full)
117 if terms.has(RootSum):
118 terms = terms.doit()
120 for t in Add.make_args(terms):
121 num, den = t.as_numer_denom()
122 if not den.has(x):
123 sep += t
124 else:
125 if isinstance(den, Mul):
126 # m*(n*x - a)**j -> (n*x - a)**j
127 ind = den.as_independent(x)
128 den = ind[1]
129 num /= ind[0]
131 # (n*x - a)**j -> (x - b)
132 den, j = den.as_base_exp()
133 a, xterm = den.as_coeff_add(x)
135 # term -> m/x**n
136 if not a:
137 sep += t
138 continue
140 xc = xterm[0].coeff(x)
141 a /= -xc
142 num /= xc**j
144 ak = ((-1)**j * num *
145 binomial(j + k - 1, k).rewrite(factorial) /
146 a**(j + k))
147 coeff += ak
149 # Hacky, better way?
150 if coeff.is_zero:
151 return None
152 if (coeff.has(x) or coeff.has(zoo) or coeff.has(oo) or
153 coeff.has(nan)):
154 return None
156 for j in range(i):
157 coeff = (coeff / (k + j + 1))
158 sep = integrate(sep, x)
159 sep += (ds.pop() - sep).limit(x, 0) # constant of integration
160 return (coeff.subs(k, k - i), sep, i)
162 else:
163 ds.append(diff)
165 return None
168def rational_independent(terms, x):
169 """
170 Returns a list of all the rationally independent terms.
172 Examples
173 ========
175 >>> from sympy import sin, cos
176 >>> from sympy.series.formal import rational_independent
177 >>> from sympy.abc import x
179 >>> rational_independent([cos(x), sin(x)], x)
180 [cos(x), sin(x)]
181 >>> rational_independent([x**2, sin(x), x*sin(x), x**3], x)
182 [x**3 + x**2, x*sin(x) + sin(x)]
183 """
184 if not terms:
185 return []
187 ind = terms[0:1]
189 for t in terms[1:]:
190 n = t.as_independent(x)[1]
191 for i, term in enumerate(ind):
192 d = term.as_independent(x)[1]
193 q = (n / d).cancel()
194 if q.is_rational_function(x):
195 ind[i] += t
196 break
197 else:
198 ind.append(t)
199 return ind
202def simpleDE(f, x, g, order=4):
203 r"""
204 Generates simple DE.
206 Explanation
207 ===========
209 DE is of the form
211 .. math::
212 f^k(x) + \sum\limits_{j=0}^{k-1} A_j f^j(x) = 0
214 where :math:`A_j` should be rational function in x.
216 Generates DE's upto order 4 (default). DE's can also have free parameters.
218 By increasing order, higher order DE's can be found.
220 Yields a tuple of (DE, order).
221 """
222 from sympy.solvers.solveset import linsolve
224 a = symbols('a:%d' % (order))
226 def _makeDE(k):
227 eq = f.diff(x, k) + Add(*[a[i]*f.diff(x, i) for i in range(0, k)])
228 DE = g(x).diff(x, k) + Add(*[a[i]*g(x).diff(x, i) for i in range(0, k)])
229 return eq, DE
231 found = False
232 for k in range(1, order + 1):
233 eq, DE = _makeDE(k)
234 eq = eq.expand()
235 terms = eq.as_ordered_terms()
236 ind = rational_independent(terms, x)
237 if found or len(ind) == k:
238 sol = dict(zip(a, (i for s in linsolve(ind, a[:k]) for i in s)))
239 if sol:
240 found = True
241 DE = DE.subs(sol)
242 DE = DE.as_numer_denom()[0]
243 DE = DE.factor().as_coeff_mul(Derivative)[1][0]
244 yield DE.collect(Derivative(g(x))), k
247def exp_re(DE, r, k):
248 """Converts a DE with constant coefficients (explike) into a RE.
250 Explanation
251 ===========
253 Performs the substitution:
255 .. math::
256 f^j(x) \\to r(k + j)
258 Normalises the terms so that lowest order of a term is always r(k).
260 Examples
261 ========
263 >>> from sympy import Function, Derivative
264 >>> from sympy.series.formal import exp_re
265 >>> from sympy.abc import x, k
266 >>> f, r = Function('f'), Function('r')
268 >>> exp_re(-f(x) + Derivative(f(x)), r, k)
269 -r(k) + r(k + 1)
270 >>> exp_re(Derivative(f(x), x) + Derivative(f(x), (x, 2)), r, k)
271 r(k) + r(k + 1)
273 See Also
274 ========
276 sympy.series.formal.hyper_re
277 """
278 RE = S.Zero
280 g = DE.atoms(Function).pop()
282 mini = None
283 for t in Add.make_args(DE):
284 coeff, d = t.as_independent(g)
285 if isinstance(d, Derivative):
286 j = d.derivative_count
287 else:
288 j = 0
289 if mini is None or j < mini:
290 mini = j
291 RE += coeff * r(k + j)
292 if mini:
293 RE = RE.subs(k, k - mini)
294 return RE
297def hyper_re(DE, r, k):
298 """
299 Converts a DE into a RE.
301 Explanation
302 ===========
304 Performs the substitution:
306 .. math::
307 x^l f^j(x) \\to (k + 1 - l)_j . a_{k + j - l}
309 Normalises the terms so that lowest order of a term is always r(k).
311 Examples
312 ========
314 >>> from sympy import Function, Derivative
315 >>> from sympy.series.formal import hyper_re
316 >>> from sympy.abc import x, k
317 >>> f, r = Function('f'), Function('r')
319 >>> hyper_re(-f(x) + Derivative(f(x)), r, k)
320 (k + 1)*r(k + 1) - r(k)
321 >>> hyper_re(-x*f(x) + Derivative(f(x), (x, 2)), r, k)
322 (k + 2)*(k + 3)*r(k + 3) - r(k)
324 See Also
325 ========
327 sympy.series.formal.exp_re
328 """
329 RE = S.Zero
331 g = DE.atoms(Function).pop()
332 x = g.atoms(Symbol).pop()
334 mini = None
335 for t in Add.make_args(DE.expand()):
336 coeff, d = t.as_independent(g)
337 c, v = coeff.as_independent(x)
338 l = v.as_coeff_exponent(x)[1]
339 if isinstance(d, Derivative):
340 j = d.derivative_count
341 else:
342 j = 0
343 RE += c * rf(k + 1 - l, j) * r(k + j - l)
344 if mini is None or j - l < mini:
345 mini = j - l
347 RE = RE.subs(k, k - mini)
349 m = Wild('m')
350 return RE.collect(r(k + m))
353def _transformation_a(f, x, P, Q, k, m, shift):
354 f *= x**(-shift)
355 P = P.subs(k, k + shift)
356 Q = Q.subs(k, k + shift)
357 return f, P, Q, m
360def _transformation_c(f, x, P, Q, k, m, scale):
361 f = f.subs(x, x**scale)
362 P = P.subs(k, k / scale)
363 Q = Q.subs(k, k / scale)
364 m *= scale
365 return f, P, Q, m
368def _transformation_e(f, x, P, Q, k, m):
369 f = f.diff(x)
370 P = P.subs(k, k + 1) * (k + m + 1)
371 Q = Q.subs(k, k + 1) * (k + 1)
372 return f, P, Q, m
375def _apply_shift(sol, shift):
376 return [(res, cond + shift) for res, cond in sol]
379def _apply_scale(sol, scale):
380 return [(res, cond / scale) for res, cond in sol]
383def _apply_integrate(sol, x, k):
384 return [(res / ((cond + 1)*(cond.as_coeff_Add()[1].coeff(k))), cond + 1)
385 for res, cond in sol]
388def _compute_formula(f, x, P, Q, k, m, k_max):
389 """Computes the formula for f."""
390 from sympy.polys import roots
392 sol = []
393 for i in range(k_max + 1, k_max + m + 1):
394 if (i < 0) == True:
395 continue
396 r = f.diff(x, i).limit(x, 0) / factorial(i)
397 if r.is_zero:
398 continue
400 kterm = m*k + i
401 res = r
403 p = P.subs(k, kterm)
404 q = Q.subs(k, kterm)
405 c1 = p.subs(k, 1/k).leadterm(k)[0]
406 c2 = q.subs(k, 1/k).leadterm(k)[0]
407 res *= (-c1 / c2)**k
409 res *= Mul(*[rf(-r, k)**mul for r, mul in roots(p, k).items()])
410 res /= Mul(*[rf(-r, k)**mul for r, mul in roots(q, k).items()])
412 sol.append((res, kterm))
414 return sol
417def _rsolve_hypergeometric(f, x, P, Q, k, m):
418 """
419 Recursive wrapper to rsolve_hypergeometric.
421 Explanation
422 ===========
424 Returns a Tuple of (formula, series independent terms,
425 maximum power of x in independent terms) if successful
426 otherwise ``None``.
428 See :func:`rsolve_hypergeometric` for details.
429 """
430 from sympy.polys import lcm, roots
431 from sympy.integrals import integrate
433 # transformation - c
434 proots, qroots = roots(P, k), roots(Q, k)
435 all_roots = dict(proots)
436 all_roots.update(qroots)
437 scale = lcm([r.as_numer_denom()[1] for r, t in all_roots.items()
438 if r.is_rational])
439 f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale)
441 # transformation - a
442 qroots = roots(Q, k)
443 if qroots:
444 k_min = Min(*qroots.keys())
445 else:
446 k_min = S.Zero
447 shift = k_min + m
448 f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift)
450 l = (x*f).limit(x, 0)
451 if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0
452 return None
454 qroots = roots(Q, k)
455 if qroots:
456 k_max = Max(*qroots.keys())
457 else:
458 k_max = S.Zero
460 ind, mp = S.Zero, -oo
461 for i in range(k_max + m + 1):
462 r = f.diff(x, i).limit(x, 0) / factorial(i)
463 if r.is_finite is False:
464 old_f = f
465 f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i)
466 f, P, Q, m = _transformation_e(f, x, P, Q, k, m)
467 sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m)
468 sol = _apply_integrate(sol, x, k)
469 sol = _apply_shift(sol, i)
470 ind = integrate(ind, x)
471 ind += (old_f - ind).limit(x, 0) # constant of integration
472 mp += 1
473 return sol, ind, mp
474 elif r:
475 ind += r*x**(i + shift)
476 pow_x = Rational((i + shift), scale)
477 if pow_x > mp:
478 mp = pow_x # maximum power of x
479 ind = ind.subs(x, x**(1/scale))
481 sol = _compute_formula(f, x, P, Q, k, m, k_max)
482 sol = _apply_shift(sol, shift)
483 sol = _apply_scale(sol, scale)
485 return sol, ind, mp
488def rsolve_hypergeometric(f, x, P, Q, k, m):
489 """
490 Solves RE of hypergeometric type.
492 Explanation
493 ===========
495 Attempts to solve RE of the form
497 Q(k)*a(k + m) - P(k)*a(k)
499 Transformations that preserve Hypergeometric type:
501 a. x**n*f(x): b(k + m) = R(k - n)*b(k)
502 b. f(A*x): b(k + m) = A**m*R(k)*b(k)
503 c. f(x**n): b(k + n*m) = R(k/n)*b(k)
504 d. f(x**(1/m)): b(k + 1) = R(k*m)*b(k)
505 e. f'(x): b(k + m) = ((k + m + 1)/(k + 1))*R(k + 1)*b(k)
507 Some of these transformations have been used to solve the RE.
509 Returns
510 =======
512 formula : Expr
513 ind : Expr
514 Independent terms.
515 order : int
517 Examples
518 ========
520 >>> from sympy import exp, ln, S
521 >>> from sympy.series.formal import rsolve_hypergeometric as rh
522 >>> from sympy.abc import x, k
524 >>> rh(exp(x), x, -S.One, (k + 1), k, 1)
525 (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1)
527 >>> rh(ln(1 + x), x, k**2, k*(k + 1), k, 1)
528 (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1),
529 Eq(Mod(k, 1), 0)), (0, True)), x, 2)
531 References
532 ==========
534 .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf
535 .. [2] Power Series in Computer Algebra - Wolfram Koepf
536 """
537 result = _rsolve_hypergeometric(f, x, P, Q, k, m)
539 if result is None:
540 return None
542 sol_list, ind, mp = result
544 sol_dict = defaultdict(lambda: S.Zero)
545 for res, cond in sol_list:
546 j, mk = cond.as_coeff_Add()
547 c = mk.coeff(k)
549 if j.is_integer is False:
550 res *= x**frac(j)
551 j = floor(j)
553 res = res.subs(k, (k - j) / c)
554 cond = Eq(k % c, j % c)
555 sol_dict[cond] += res # Group together formula for same conditions
557 sol = []
558 for cond, res in sol_dict.items():
559 sol.append((res, cond))
560 sol.append((S.Zero, True))
561 sol = Piecewise(*sol)
563 if mp is -oo:
564 s = S.Zero
565 elif mp.is_integer is False:
566 s = ceiling(mp)
567 else:
568 s = mp + 1
570 # save all the terms of
571 # form 1/x**k in ind
572 if s < 0:
573 ind += sum(sequence(sol * x**k, (k, s, -1)))
574 s = S.Zero
576 return (sol, ind, s)
579def _solve_hyper_RE(f, x, RE, g, k):
580 """See docstring of :func:`rsolve_hypergeometric` for details."""
581 terms = Add.make_args(RE)
583 if len(terms) == 2:
584 gs = list(RE.atoms(Function))
585 P, Q = map(RE.coeff, gs)
586 m = gs[1].args[0] - gs[0].args[0]
587 if m < 0:
588 P, Q = Q, P
589 m = abs(m)
590 return rsolve_hypergeometric(f, x, P, Q, k, m)
593def _solve_explike_DE(f, x, DE, g, k):
594 """Solves DE with constant coefficients."""
595 from sympy.solvers import rsolve
597 for t in Add.make_args(DE):
598 coeff, d = t.as_independent(g)
599 if coeff.free_symbols:
600 return
602 RE = exp_re(DE, g, k)
604 init = {}
605 for i in range(len(Add.make_args(RE))):
606 if i:
607 f = f.diff(x)
608 init[g(k).subs(k, i)] = f.limit(x, 0)
610 sol = rsolve(RE, g(k), init)
612 if sol:
613 return (sol / factorial(k), S.Zero, S.Zero)
616def _solve_simple(f, x, DE, g, k):
617 """Converts DE into RE and solves using :func:`rsolve`."""
618 from sympy.solvers import rsolve
620 RE = hyper_re(DE, g, k)
622 init = {}
623 for i in range(len(Add.make_args(RE))):
624 if i:
625 f = f.diff(x)
626 init[g(k).subs(k, i)] = f.limit(x, 0) / factorial(i)
628 sol = rsolve(RE, g(k), init)
630 if sol:
631 return (sol, S.Zero, S.Zero)
634def _transform_explike_DE(DE, g, x, order, syms):
635 """Converts DE with free parameters into DE with constant coefficients."""
636 from sympy.solvers.solveset import linsolve
638 eq = []
639 highest_coeff = DE.coeff(Derivative(g(x), x, order))
640 for i in range(order):
641 coeff = DE.coeff(Derivative(g(x), x, i))
642 coeff = (coeff / highest_coeff).expand().collect(x)
643 for t in Add.make_args(coeff):
644 eq.append(t)
645 temp = []
646 for e in eq:
647 if e.has(x):
648 break
649 elif e.has(Symbol):
650 temp.append(e)
651 else:
652 eq = temp
653 if eq:
654 sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s)))
655 if sol:
656 DE = DE.subs(sol)
657 DE = DE.factor().as_coeff_mul(Derivative)[1][0]
658 DE = DE.collect(Derivative(g(x)))
659 return DE
662def _transform_DE_RE(DE, g, k, order, syms):
663 """Converts DE with free parameters into RE of hypergeometric type."""
664 from sympy.solvers.solveset import linsolve
666 RE = hyper_re(DE, g, k)
668 eq = []
669 for i in range(1, order):
670 coeff = RE.coeff(g(k + i))
671 eq.append(coeff)
672 sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s)))
673 if sol:
674 m = Wild('m')
675 RE = RE.subs(sol)
676 RE = RE.factor().as_numer_denom()[0].collect(g(k + m))
677 RE = RE.as_coeff_mul(g)[1][0]
678 for i in range(order): # smallest order should be g(k)
679 if RE.coeff(g(k + i)) and i:
680 RE = RE.subs(k, k - i)
681 break
682 return RE
685def solve_de(f, x, DE, order, g, k):
686 """
687 Solves the DE.
689 Explanation
690 ===========
692 Tries to solve DE by either converting into a RE containing two terms or
693 converting into a DE having constant coefficients.
695 Returns
696 =======
698 formula : Expr
699 ind : Expr
700 Independent terms.
701 order : int
703 Examples
704 ========
706 >>> from sympy import Derivative as D, Function
707 >>> from sympy import exp, ln
708 >>> from sympy.series.formal import solve_de
709 >>> from sympy.abc import x, k
710 >>> f = Function('f')
712 >>> solve_de(exp(x), x, D(f(x), x) - f(x), 1, f, k)
713 (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1)
715 >>> solve_de(ln(1 + x), x, (x + 1)*D(f(x), x, 2) + D(f(x)), 2, f, k)
716 (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1),
717 Eq(Mod(k, 1), 0)), (0, True)), x, 2)
718 """
719 sol = None
720 syms = DE.free_symbols.difference({g, x})
722 if syms:
723 RE = _transform_DE_RE(DE, g, k, order, syms)
724 else:
725 RE = hyper_re(DE, g, k)
726 if not RE.free_symbols.difference({k}):
727 sol = _solve_hyper_RE(f, x, RE, g, k)
729 if sol:
730 return sol
732 if syms:
733 DE = _transform_explike_DE(DE, g, x, order, syms)
734 if not DE.free_symbols.difference({x}):
735 sol = _solve_explike_DE(f, x, DE, g, k)
737 if sol:
738 return sol
741def hyper_algorithm(f, x, k, order=4):
742 """
743 Hypergeometric algorithm for computing Formal Power Series.
745 Explanation
746 ===========
748 Steps:
749 * Generates DE
750 * Convert the DE into RE
751 * Solves the RE
753 Examples
754 ========
756 >>> from sympy import exp, ln
757 >>> from sympy.series.formal import hyper_algorithm
759 >>> from sympy.abc import x, k
761 >>> hyper_algorithm(exp(x), x, k)
762 (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1)
764 >>> hyper_algorithm(ln(1 + x), x, k)
765 (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1),
766 Eq(Mod(k, 1), 0)), (0, True)), x, 2)
768 See Also
769 ========
771 sympy.series.formal.simpleDE
772 sympy.series.formal.solve_de
773 """
774 g = Function('g')
776 des = [] # list of DE's
777 sol = None
778 for DE, i in simpleDE(f, x, g, order):
779 if DE is not None:
780 sol = solve_de(f, x, DE, i, g, k)
781 if sol:
782 return sol
783 if not DE.free_symbols.difference({x}):
784 des.append(DE)
786 # If nothing works
787 # Try plain rsolve
788 for DE in des:
789 sol = _solve_simple(f, x, DE, g, k)
790 if sol:
791 return sol
794def _compute_fps(f, x, x0, dir, hyper, order, rational, full):
795 """Recursive wrapper to compute fps.
797 See :func:`compute_fps` for details.
798 """
799 if x0 in [S.Infinity, S.NegativeInfinity]:
800 dir = S.One if x0 is S.Infinity else -S.One
801 temp = f.subs(x, 1/x)
802 result = _compute_fps(temp, x, 0, dir, hyper, order, rational, full)
803 if result is None:
804 return None
805 return (result[0], result[1].subs(x, 1/x), result[2].subs(x, 1/x))
806 elif x0 or dir == -S.One:
807 if dir == -S.One:
808 rep = -x + x0
809 rep2 = -x
810 rep2b = x0
811 else:
812 rep = x + x0
813 rep2 = x
814 rep2b = -x0
815 temp = f.subs(x, rep)
816 result = _compute_fps(temp, x, 0, S.One, hyper, order, rational, full)
817 if result is None:
818 return None
819 return (result[0], result[1].subs(x, rep2 + rep2b),
820 result[2].subs(x, rep2 + rep2b))
822 if f.is_polynomial(x):
823 k = Dummy('k')
824 ak = sequence(Coeff(f, x, k), (k, 1, oo))
825 xk = sequence(x**k, (k, 0, oo))
826 ind = f.coeff(x, 0)
827 return ak, xk, ind
829 # Break instances of Add
830 # this allows application of different
831 # algorithms on different terms increasing the
832 # range of admissible functions.
833 if isinstance(f, Add):
834 result = False
835 ak = sequence(S.Zero, (0, oo))
836 ind, xk = S.Zero, None
837 for t in Add.make_args(f):
838 res = _compute_fps(t, x, 0, S.One, hyper, order, rational, full)
839 if res:
840 if not result:
841 result = True
842 xk = res[1]
843 if res[0].start > ak.start:
844 seq = ak
845 s, f = ak.start, res[0].start
846 else:
847 seq = res[0]
848 s, f = res[0].start, ak.start
849 save = Add(*[z[0]*z[1] for z in zip(seq[0:(f - s)], xk[s:f])])
850 ak += res[0]
851 ind += res[2] + save
852 else:
853 ind += t
854 if result:
855 return ak, xk, ind
856 return None
858 # The symbolic term - symb, if present, is being separated from the function
859 # Otherwise symb is being set to S.One
860 syms = f.free_symbols.difference({x})
861 (f, symb) = expand(f).as_independent(*syms)
863 result = None
865 # from here on it's x0=0 and dir=1 handling
866 k = Dummy('k')
867 if rational:
868 result = rational_algorithm(f, x, k, order, full)
870 if result is None and hyper:
871 result = hyper_algorithm(f, x, k, order)
873 if result is None:
874 return None
876 from sympy.simplify.powsimp import powsimp
877 if symb.is_zero:
878 symb = S.One
879 else:
880 symb = powsimp(symb)
881 ak = sequence(result[0], (k, result[2], oo))
882 xk_formula = powsimp(x**k * symb)
883 xk = sequence(xk_formula, (k, 0, oo))
884 ind = powsimp(result[1] * symb)
886 return ak, xk, ind
889def compute_fps(f, x, x0=0, dir=1, hyper=True, order=4, rational=True,
890 full=False):
891 """
892 Computes the formula for Formal Power Series of a function.
894 Explanation
895 ===========
897 Tries to compute the formula by applying the following techniques
898 (in order):
900 * rational_algorithm
901 * Hypergeometric algorithm
903 Parameters
904 ==========
906 x : Symbol
907 x0 : number, optional
908 Point to perform series expansion about. Default is 0.
909 dir : {1, -1, '+', '-'}, optional
910 If dir is 1 or '+' the series is calculated from the right and
911 for -1 or '-' the series is calculated from the left. For smooth
912 functions this flag will not alter the results. Default is 1.
913 hyper : {True, False}, optional
914 Set hyper to False to skip the hypergeometric algorithm.
915 By default it is set to False.
916 order : int, optional
917 Order of the derivative of ``f``, Default is 4.
918 rational : {True, False}, optional
919 Set rational to False to skip rational algorithm. By default it is set
920 to True.
921 full : {True, False}, optional
922 Set full to True to increase the range of rational algorithm.
923 See :func:`rational_algorithm` for details. By default it is set to
924 False.
926 Returns
927 =======
929 ak : sequence
930 Sequence of coefficients.
931 xk : sequence
932 Sequence of powers of x.
933 ind : Expr
934 Independent terms.
935 mul : Pow
936 Common terms.
938 See Also
939 ========
941 sympy.series.formal.rational_algorithm
942 sympy.series.formal.hyper_algorithm
943 """
944 f = sympify(f)
945 x = sympify(x)
947 if not f.has(x):
948 return None
950 x0 = sympify(x0)
952 if dir == '+':
953 dir = S.One
954 elif dir == '-':
955 dir = -S.One
956 elif dir not in [S.One, -S.One]:
957 raise ValueError("Dir must be '+' or '-'")
958 else:
959 dir = sympify(dir)
961 return _compute_fps(f, x, x0, dir, hyper, order, rational, full)
964class Coeff(Function):
965 """
966 Coeff(p, x, n) represents the nth coefficient of the polynomial p in x
967 """
968 @classmethod
969 def eval(cls, p, x, n):
970 if p.is_polynomial(x) and n.is_integer:
971 return p.coeff(x, n)
974class FormalPowerSeries(SeriesBase):
975 """
976 Represents Formal Power Series of a function.
978 Explanation
979 ===========
981 No computation is performed. This class should only to be used to represent
982 a series. No checks are performed.
984 For computing a series use :func:`fps`.
986 See Also
987 ========
989 sympy.series.formal.fps
990 """
991 def __new__(cls, *args):
992 args = map(sympify, args)
993 return Expr.__new__(cls, *args)
995 def __init__(self, *args):
996 ak = args[4][0]
997 k = ak.variables[0]
998 self.ak_seq = sequence(ak.formula, (k, 1, oo))
999 self.fact_seq = sequence(factorial(k), (k, 1, oo))
1000 self.bell_coeff_seq = self.ak_seq * self.fact_seq
1001 self.sign_seq = sequence((-1, 1), (k, 1, oo))
1003 @property
1004 def function(self):
1005 return self.args[0]
1007 @property
1008 def x(self):
1009 return self.args[1]
1011 @property
1012 def x0(self):
1013 return self.args[2]
1015 @property
1016 def dir(self):
1017 return self.args[3]
1019 @property
1020 def ak(self):
1021 return self.args[4][0]
1023 @property
1024 def xk(self):
1025 return self.args[4][1]
1027 @property
1028 def ind(self):
1029 return self.args[4][2]
1031 @property
1032 def interval(self):
1033 return Interval(0, oo)
1035 @property
1036 def start(self):
1037 return self.interval.inf
1039 @property
1040 def stop(self):
1041 return self.interval.sup
1043 @property
1044 def length(self):
1045 return oo
1047 @property
1048 def infinite(self):
1049 """Returns an infinite representation of the series"""
1050 from sympy.concrete import Sum
1051 ak, xk = self.ak, self.xk
1052 k = ak.variables[0]
1053 inf_sum = Sum(ak.formula * xk.formula, (k, ak.start, ak.stop))
1055 return self.ind + inf_sum
1057 def _get_pow_x(self, term):
1058 """Returns the power of x in a term."""
1059 xterm, pow_x = term.as_independent(self.x)[1].as_base_exp()
1060 if not xterm.has(self.x):
1061 return S.Zero
1062 return pow_x
1064 def polynomial(self, n=6):
1065 """
1066 Truncated series as polynomial.
1068 Explanation
1069 ===========
1071 Returns series expansion of ``f`` upto order ``O(x**n)``
1072 as a polynomial(without ``O`` term).
1073 """
1074 terms = []
1075 sym = self.free_symbols
1076 for i, t in enumerate(self):
1077 xp = self._get_pow_x(t)
1078 if xp.has(*sym):
1079 xp = xp.as_coeff_add(*sym)[0]
1080 if xp >= n:
1081 break
1082 elif xp.is_integer is True and i == n + 1:
1083 break
1084 elif t is not S.Zero:
1085 terms.append(t)
1087 return Add(*terms)
1089 def truncate(self, n=6):
1090 """
1091 Truncated series.
1093 Explanation
1094 ===========
1096 Returns truncated series expansion of f upto
1097 order ``O(x**n)``.
1099 If n is ``None``, returns an infinite iterator.
1100 """
1101 if n is None:
1102 return iter(self)
1104 x, x0 = self.x, self.x0
1105 pt_xk = self.xk.coeff(n)
1106 if x0 is S.NegativeInfinity:
1107 x0 = S.Infinity
1109 return self.polynomial(n) + Order(pt_xk, (x, x0))
1111 def zero_coeff(self):
1112 return self._eval_term(0)
1114 def _eval_term(self, pt):
1115 try:
1116 pt_xk = self.xk.coeff(pt)
1117 pt_ak = self.ak.coeff(pt).simplify() # Simplify the coefficients
1118 except IndexError:
1119 term = S.Zero
1120 else:
1121 term = (pt_ak * pt_xk)
1123 if self.ind:
1124 ind = S.Zero
1125 sym = self.free_symbols
1126 for t in Add.make_args(self.ind):
1127 pow_x = self._get_pow_x(t)
1128 if pow_x.has(*sym):
1129 pow_x = pow_x.as_coeff_add(*sym)[0]
1130 if pt == 0 and pow_x < 1:
1131 ind += t
1132 elif pow_x >= pt and pow_x < pt + 1:
1133 ind += t
1134 term += ind
1136 return term.collect(self.x)
1138 def _eval_subs(self, old, new):
1139 x = self.x
1140 if old.has(x):
1141 return self
1143 def _eval_as_leading_term(self, x, logx=None, cdir=0):
1144 for t in self:
1145 if t is not S.Zero:
1146 return t
1148 def _eval_derivative(self, x):
1149 f = self.function.diff(x)
1150 ind = self.ind.diff(x)
1152 pow_xk = self._get_pow_x(self.xk.formula)
1153 ak = self.ak
1154 k = ak.variables[0]
1155 if ak.formula.has(x):
1156 form = []
1157 for e, c in ak.formula.args:
1158 temp = S.Zero
1159 for t in Add.make_args(e):
1160 pow_x = self._get_pow_x(t)
1161 temp += t * (pow_xk + pow_x)
1162 form.append((temp, c))
1163 form = Piecewise(*form)
1164 ak = sequence(form.subs(k, k + 1), (k, ak.start - 1, ak.stop))
1165 else:
1166 ak = sequence((ak.formula * pow_xk).subs(k, k + 1),
1167 (k, ak.start - 1, ak.stop))
1169 return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
1171 def integrate(self, x=None, **kwargs):
1172 """
1173 Integrate Formal Power Series.
1175 Examples
1176 ========
1178 >>> from sympy import fps, sin, integrate
1179 >>> from sympy.abc import x
1180 >>> f = fps(sin(x))
1181 >>> f.integrate(x).truncate()
1182 -1 + x**2/2 - x**4/24 + O(x**6)
1183 >>> integrate(f, (x, 0, 1))
1184 1 - cos(1)
1185 """
1186 from sympy.integrals import integrate
1188 if x is None:
1189 x = self.x
1190 elif iterable(x):
1191 return integrate(self.function, x)
1193 f = integrate(self.function, x)
1194 ind = integrate(self.ind, x)
1195 ind += (f - ind).limit(x, 0) # constant of integration
1197 pow_xk = self._get_pow_x(self.xk.formula)
1198 ak = self.ak
1199 k = ak.variables[0]
1200 if ak.formula.has(x):
1201 form = []
1202 for e, c in ak.formula.args:
1203 temp = S.Zero
1204 for t in Add.make_args(e):
1205 pow_x = self._get_pow_x(t)
1206 temp += t / (pow_xk + pow_x + 1)
1207 form.append((temp, c))
1208 form = Piecewise(*form)
1209 ak = sequence(form.subs(k, k - 1), (k, ak.start + 1, ak.stop))
1210 else:
1211 ak = sequence((ak.formula / (pow_xk + 1)).subs(k, k - 1),
1212 (k, ak.start + 1, ak.stop))
1214 return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
1216 def product(self, other, x=None, n=6):
1217 """
1218 Multiplies two Formal Power Series, using discrete convolution and
1219 return the truncated terms upto specified order.
1221 Parameters
1222 ==========
1224 n : Number, optional
1225 Specifies the order of the term up to which the polynomial should
1226 be truncated.
1228 Examples
1229 ========
1231 >>> from sympy import fps, sin, exp
1232 >>> from sympy.abc import x
1233 >>> f1 = fps(sin(x))
1234 >>> f2 = fps(exp(x))
1236 >>> f1.product(f2, x).truncate(4)
1237 x + x**2 + x**3/3 + O(x**4)
1239 See Also
1240 ========
1242 sympy.discrete.convolutions
1243 sympy.series.formal.FormalPowerSeriesProduct
1245 """
1247 if n is None:
1248 return iter(self)
1250 other = sympify(other)
1252 if not isinstance(other, FormalPowerSeries):
1253 raise ValueError("Both series should be an instance of FormalPowerSeries"
1254 " class.")
1256 if self.dir != other.dir:
1257 raise ValueError("Both series should be calculated from the"
1258 " same direction.")
1259 elif self.x0 != other.x0:
1260 raise ValueError("Both series should be calculated about the"
1261 " same point.")
1263 elif self.x != other.x:
1264 raise ValueError("Both series should have the same symbol.")
1266 return FormalPowerSeriesProduct(self, other)
1268 def coeff_bell(self, n):
1269 r"""
1270 self.coeff_bell(n) returns a sequence of Bell polynomials of the second kind.
1271 Note that ``n`` should be a integer.
1273 The second kind of Bell polynomials (are sometimes called "partial" Bell
1274 polynomials or incomplete Bell polynomials) are defined as
1276 .. math::
1277 B_{n,k}(x_1, x_2,\dotsc x_{n-k+1}) =
1278 \sum_{j_1+j_2+j_2+\dotsb=k \atop j_1+2j_2+3j_2+\dotsb=n}
1279 \frac{n!}{j_1!j_2!\dotsb j_{n-k+1}!}
1280 \left(\frac{x_1}{1!} \right)^{j_1}
1281 \left(\frac{x_2}{2!} \right)^{j_2} \dotsb
1282 \left(\frac{x_{n-k+1}}{(n-k+1)!} \right) ^{j_{n-k+1}}.
1284 * ``bell(n, k, (x1, x2, ...))`` gives Bell polynomials of the second kind,
1285 `B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})`.
1287 See Also
1288 ========
1290 sympy.functions.combinatorial.numbers.bell
1292 """
1294 inner_coeffs = [bell(n, j, tuple(self.bell_coeff_seq[:n-j+1])) for j in range(1, n+1)]
1296 k = Dummy('k')
1297 return sequence(tuple(inner_coeffs), (k, 1, oo))
1299 def compose(self, other, x=None, n=6):
1300 r"""
1301 Returns the truncated terms of the formal power series of the composed function,
1302 up to specified ``n``.
1304 Explanation
1305 ===========
1307 If ``f`` and ``g`` are two formal power series of two different functions,
1308 then the coefficient sequence ``ak`` of the composed formal power series `fp`
1309 will be as follows.
1311 .. math::
1312 \sum\limits_{k=0}^{n} b_k B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})
1314 Parameters
1315 ==========
1317 n : Number, optional
1318 Specifies the order of the term up to which the polynomial should
1319 be truncated.
1321 Examples
1322 ========
1324 >>> from sympy import fps, sin, exp
1325 >>> from sympy.abc import x
1326 >>> f1 = fps(exp(x))
1327 >>> f2 = fps(sin(x))
1329 >>> f1.compose(f2, x).truncate()
1330 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6)
1332 >>> f1.compose(f2, x).truncate(8)
1333 1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8)
1335 See Also
1336 ========
1338 sympy.functions.combinatorial.numbers.bell
1339 sympy.series.formal.FormalPowerSeriesCompose
1341 References
1342 ==========
1344 .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974.
1346 """
1348 if n is None:
1349 return iter(self)
1351 other = sympify(other)
1353 if not isinstance(other, FormalPowerSeries):
1354 raise ValueError("Both series should be an instance of FormalPowerSeries"
1355 " class.")
1357 if self.dir != other.dir:
1358 raise ValueError("Both series should be calculated from the"
1359 " same direction.")
1360 elif self.x0 != other.x0:
1361 raise ValueError("Both series should be calculated about the"
1362 " same point.")
1364 elif self.x != other.x:
1365 raise ValueError("Both series should have the same symbol.")
1367 if other._eval_term(0).as_coeff_mul(other.x)[0] is not S.Zero:
1368 raise ValueError("The formal power series of the inner function should not have any "
1369 "constant coefficient term.")
1371 return FormalPowerSeriesCompose(self, other)
1373 def inverse(self, x=None, n=6):
1374 r"""
1375 Returns the truncated terms of the inverse of the formal power series,
1376 up to specified ``n``.
1378 Explanation
1379 ===========
1381 If ``f`` and ``g`` are two formal power series of two different functions,
1382 then the coefficient sequence ``ak`` of the composed formal power series ``fp``
1383 will be as follows.
1385 .. math::
1386 \sum\limits_{k=0}^{n} (-1)^{k} x_0^{-k-1} B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})
1388 Parameters
1389 ==========
1391 n : Number, optional
1392 Specifies the order of the term up to which the polynomial should
1393 be truncated.
1395 Examples
1396 ========
1398 >>> from sympy import fps, exp, cos
1399 >>> from sympy.abc import x
1400 >>> f1 = fps(exp(x))
1401 >>> f2 = fps(cos(x))
1403 >>> f1.inverse(x).truncate()
1404 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6)
1406 >>> f2.inverse(x).truncate(8)
1407 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8)
1409 See Also
1410 ========
1412 sympy.functions.combinatorial.numbers.bell
1413 sympy.series.formal.FormalPowerSeriesInverse
1415 References
1416 ==========
1418 .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974.
1420 """
1422 if n is None:
1423 return iter(self)
1425 if self._eval_term(0).is_zero:
1426 raise ValueError("Constant coefficient should exist for an inverse of a formal"
1427 " power series to exist.")
1429 return FormalPowerSeriesInverse(self)
1431 def __add__(self, other):
1432 other = sympify(other)
1434 if isinstance(other, FormalPowerSeries):
1435 if self.dir != other.dir:
1436 raise ValueError("Both series should be calculated from the"
1437 " same direction.")
1438 elif self.x0 != other.x0:
1439 raise ValueError("Both series should be calculated about the"
1440 " same point.")
1442 x, y = self.x, other.x
1443 f = self.function + other.function.subs(y, x)
1445 if self.x not in f.free_symbols:
1446 return f
1448 ak = self.ak + other.ak
1449 if self.ak.start > other.ak.start:
1450 seq = other.ak
1451 s, e = other.ak.start, self.ak.start
1452 else:
1453 seq = self.ak
1454 s, e = self.ak.start, other.ak.start
1455 save = Add(*[z[0]*z[1] for z in zip(seq[0:(e - s)], self.xk[s:e])])
1456 ind = self.ind + other.ind + save
1458 return self.func(f, x, self.x0, self.dir, (ak, self.xk, ind))
1460 elif not other.has(self.x):
1461 f = self.function + other
1462 ind = self.ind + other
1464 return self.func(f, self.x, self.x0, self.dir,
1465 (self.ak, self.xk, ind))
1467 return Add(self, other)
1469 def __radd__(self, other):
1470 return self.__add__(other)
1472 def __neg__(self):
1473 return self.func(-self.function, self.x, self.x0, self.dir,
1474 (-self.ak, self.xk, -self.ind))
1476 def __sub__(self, other):
1477 return self.__add__(-other)
1479 def __rsub__(self, other):
1480 return (-self).__add__(other)
1482 def __mul__(self, other):
1483 other = sympify(other)
1485 if other.has(self.x):
1486 return Mul(self, other)
1488 f = self.function * other
1489 ak = self.ak.coeff_mul(other)
1490 ind = self.ind * other
1492 return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
1494 def __rmul__(self, other):
1495 return self.__mul__(other)
1498class FiniteFormalPowerSeries(FormalPowerSeries):
1499 """Base Class for Product, Compose and Inverse classes"""
1501 def __init__(self, *args):
1502 pass
1504 @property
1505 def ffps(self):
1506 return self.args[0]
1508 @property
1509 def gfps(self):
1510 return self.args[1]
1512 @property
1513 def f(self):
1514 return self.ffps.function
1516 @property
1517 def g(self):
1518 return self.gfps.function
1520 @property
1521 def infinite(self):
1522 raise NotImplementedError("No infinite version for an object of"
1523 " FiniteFormalPowerSeries class.")
1525 def _eval_terms(self, n):
1526 raise NotImplementedError("(%s)._eval_terms()" % self)
1528 def _eval_term(self, pt):
1529 raise NotImplementedError("By the current logic, one can get terms"
1530 "upto a certain order, instead of getting term by term.")
1532 def polynomial(self, n):
1533 return self._eval_terms(n)
1535 def truncate(self, n=6):
1536 ffps = self.ffps
1537 pt_xk = ffps.xk.coeff(n)
1538 x, x0 = ffps.x, ffps.x0
1540 return self.polynomial(n) + Order(pt_xk, (x, x0))
1542 def _eval_derivative(self, x):
1543 raise NotImplementedError
1545 def integrate(self, x):
1546 raise NotImplementedError
1549class FormalPowerSeriesProduct(FiniteFormalPowerSeries):
1550 """Represents the product of two formal power series of two functions.
1552 Explanation
1553 ===========
1555 No computation is performed. Terms are calculated using a term by term logic,
1556 instead of a point by point logic.
1558 There are two differences between a :obj:`FormalPowerSeries` object and a
1559 :obj:`FormalPowerSeriesProduct` object. The first argument contains the two
1560 functions involved in the product. Also, the coefficient sequence contains
1561 both the coefficient sequence of the formal power series of the involved functions.
1563 See Also
1564 ========
1566 sympy.series.formal.FormalPowerSeries
1567 sympy.series.formal.FiniteFormalPowerSeries
1569 """
1571 def __init__(self, *args):
1572 ffps, gfps = self.ffps, self.gfps
1574 k = ffps.ak.variables[0]
1575 self.coeff1 = sequence(ffps.ak.formula, (k, 0, oo))
1577 k = gfps.ak.variables[0]
1578 self.coeff2 = sequence(gfps.ak.formula, (k, 0, oo))
1580 @property
1581 def function(self):
1582 """Function of the product of two formal power series."""
1583 return self.f * self.g
1585 def _eval_terms(self, n):
1586 """
1587 Returns the first ``n`` terms of the product formal power series.
1588 Term by term logic is implemented here.
1590 Examples
1591 ========
1593 >>> from sympy import fps, sin, exp
1594 >>> from sympy.abc import x
1595 >>> f1 = fps(sin(x))
1596 >>> f2 = fps(exp(x))
1597 >>> fprod = f1.product(f2, x)
1599 >>> fprod._eval_terms(4)
1600 x**3/3 + x**2 + x
1602 See Also
1603 ========
1605 sympy.series.formal.FormalPowerSeries.product
1607 """
1608 coeff1, coeff2 = self.coeff1, self.coeff2
1610 aks = convolution(coeff1[:n], coeff2[:n])
1612 terms = []
1613 for i in range(0, n):
1614 terms.append(aks[i] * self.ffps.xk.coeff(i))
1616 return Add(*terms)
1619class FormalPowerSeriesCompose(FiniteFormalPowerSeries):
1620 """
1621 Represents the composed formal power series of two functions.
1623 Explanation
1624 ===========
1626 No computation is performed. Terms are calculated using a term by term logic,
1627 instead of a point by point logic.
1629 There are two differences between a :obj:`FormalPowerSeries` object and a
1630 :obj:`FormalPowerSeriesCompose` object. The first argument contains the outer
1631 function and the inner function involved in the omposition. Also, the
1632 coefficient sequence contains the generic sequence which is to be multiplied
1633 by a custom ``bell_seq`` finite sequence. The finite terms will then be added up to
1634 get the final terms.
1636 See Also
1637 ========
1639 sympy.series.formal.FormalPowerSeries
1640 sympy.series.formal.FiniteFormalPowerSeries
1642 """
1644 @property
1645 def function(self):
1646 """Function for the composed formal power series."""
1647 f, g, x = self.f, self.g, self.ffps.x
1648 return f.subs(x, g)
1650 def _eval_terms(self, n):
1651 """
1652 Returns the first `n` terms of the composed formal power series.
1653 Term by term logic is implemented here.
1655 Explanation
1656 ===========
1658 The coefficient sequence of the :obj:`FormalPowerSeriesCompose` object is the generic sequence.
1659 It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get
1660 the final terms for the polynomial.
1662 Examples
1663 ========
1665 >>> from sympy import fps, sin, exp
1666 >>> from sympy.abc import x
1667 >>> f1 = fps(exp(x))
1668 >>> f2 = fps(sin(x))
1669 >>> fcomp = f1.compose(f2, x)
1671 >>> fcomp._eval_terms(6)
1672 -x**5/15 - x**4/8 + x**2/2 + x + 1
1674 >>> fcomp._eval_terms(8)
1675 x**7/90 - x**6/240 - x**5/15 - x**4/8 + x**2/2 + x + 1
1677 See Also
1678 ========
1680 sympy.series.formal.FormalPowerSeries.compose
1681 sympy.series.formal.FormalPowerSeries.coeff_bell
1683 """
1685 ffps, gfps = self.ffps, self.gfps
1686 terms = [ffps.zero_coeff()]
1688 for i in range(1, n):
1689 bell_seq = gfps.coeff_bell(i)
1690 seq = (ffps.bell_coeff_seq * bell_seq)
1691 terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i))
1693 return Add(*terms)
1696class FormalPowerSeriesInverse(FiniteFormalPowerSeries):
1697 """
1698 Represents the Inverse of a formal power series.
1700 Explanation
1701 ===========
1703 No computation is performed. Terms are calculated using a term by term logic,
1704 instead of a point by point logic.
1706 There is a single difference between a :obj:`FormalPowerSeries` object and a
1707 :obj:`FormalPowerSeriesInverse` object. The coefficient sequence contains the
1708 generic sequence which is to be multiplied by a custom ``bell_seq`` finite sequence.
1709 The finite terms will then be added up to get the final terms.
1711 See Also
1712 ========
1714 sympy.series.formal.FormalPowerSeries
1715 sympy.series.formal.FiniteFormalPowerSeries
1717 """
1718 def __init__(self, *args):
1719 ffps = self.ffps
1720 k = ffps.xk.variables[0]
1722 inv = ffps.zero_coeff()
1723 inv_seq = sequence(inv ** (-(k + 1)), (k, 1, oo))
1724 self.aux_seq = ffps.sign_seq * ffps.fact_seq * inv_seq
1726 @property
1727 def function(self):
1728 """Function for the inverse of a formal power series."""
1729 f = self.f
1730 return 1 / f
1732 @property
1733 def g(self):
1734 raise ValueError("Only one function is considered while performing"
1735 "inverse of a formal power series.")
1737 @property
1738 def gfps(self):
1739 raise ValueError("Only one function is considered while performing"
1740 "inverse of a formal power series.")
1742 def _eval_terms(self, n):
1743 """
1744 Returns the first ``n`` terms of the composed formal power series.
1745 Term by term logic is implemented here.
1747 Explanation
1748 ===========
1750 The coefficient sequence of the `FormalPowerSeriesInverse` object is the generic sequence.
1751 It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get
1752 the final terms for the polynomial.
1754 Examples
1755 ========
1757 >>> from sympy import fps, exp, cos
1758 >>> from sympy.abc import x
1759 >>> f1 = fps(exp(x))
1760 >>> f2 = fps(cos(x))
1761 >>> finv1, finv2 = f1.inverse(), f2.inverse()
1763 >>> finv1._eval_terms(6)
1764 -x**5/120 + x**4/24 - x**3/6 + x**2/2 - x + 1
1766 >>> finv2._eval_terms(8)
1767 61*x**6/720 + 5*x**4/24 + x**2/2 + 1
1769 See Also
1770 ========
1772 sympy.series.formal.FormalPowerSeries.inverse
1773 sympy.series.formal.FormalPowerSeries.coeff_bell
1775 """
1776 ffps = self.ffps
1777 terms = [ffps.zero_coeff()]
1779 for i in range(1, n):
1780 bell_seq = ffps.coeff_bell(i)
1781 seq = (self.aux_seq * bell_seq)
1782 terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i))
1784 return Add(*terms)
1787def fps(f, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, full=False):
1788 """
1789 Generates Formal Power Series of ``f``.
1791 Explanation
1792 ===========
1794 Returns the formal series expansion of ``f`` around ``x = x0``
1795 with respect to ``x`` in the form of a ``FormalPowerSeries`` object.
1797 Formal Power Series is represented using an explicit formula
1798 computed using different algorithms.
1800 See :func:`compute_fps` for the more details regarding the computation
1801 of formula.
1803 Parameters
1804 ==========
1806 x : Symbol, optional
1807 If x is None and ``f`` is univariate, the univariate symbols will be
1808 supplied, otherwise an error will be raised.
1809 x0 : number, optional
1810 Point to perform series expansion about. Default is 0.
1811 dir : {1, -1, '+', '-'}, optional
1812 If dir is 1 or '+' the series is calculated from the right and
1813 for -1 or '-' the series is calculated from the left. For smooth
1814 functions this flag will not alter the results. Default is 1.
1815 hyper : {True, False}, optional
1816 Set hyper to False to skip the hypergeometric algorithm.
1817 By default it is set to False.
1818 order : int, optional
1819 Order of the derivative of ``f``, Default is 4.
1820 rational : {True, False}, optional
1821 Set rational to False to skip rational algorithm. By default it is set
1822 to True.
1823 full : {True, False}, optional
1824 Set full to True to increase the range of rational algorithm.
1825 See :func:`rational_algorithm` for details. By default it is set to
1826 False.
1828 Examples
1829 ========
1831 >>> from sympy import fps, ln, atan, sin
1832 >>> from sympy.abc import x, n
1834 Rational Functions
1836 >>> fps(ln(1 + x)).truncate()
1837 x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6)
1839 >>> fps(atan(x), full=True).truncate()
1840 x - x**3/3 + x**5/5 + O(x**6)
1842 Symbolic Functions
1844 >>> fps(x**n*sin(x**2), x).truncate(8)
1845 -x**(n + 6)/6 + x**(n + 2) + O(x**(n + 8))
1847 See Also
1848 ========
1850 sympy.series.formal.FormalPowerSeries
1851 sympy.series.formal.compute_fps
1852 """
1853 f = sympify(f)
1855 if x is None:
1856 free = f.free_symbols
1857 if len(free) == 1:
1858 x = free.pop()
1859 elif not free:
1860 return f
1861 else:
1862 raise NotImplementedError("multivariate formal power series")
1864 result = compute_fps(f, x, x0, dir, hyper, order, rational, full)
1866 if result is None:
1867 return f
1869 return FormalPowerSeries(f, x, x0, dir, result)