acceleration.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. """
  2. Convergence acceleration / extrapolation methods for series and
  3. sequences.
  4. References:
  5. Carl M. Bender & Steven A. Orszag, "Advanced Mathematical Methods for
  6. Scientists and Engineers: Asymptotic Methods and Perturbation Theory",
  7. Springer 1999. (Shanks transformation: pp. 368-375, Richardson
  8. extrapolation: pp. 375-377.)
  9. """
  10. from sympy.core.numbers import Integer
  11. from sympy.core.singleton import S
  12. from sympy.functions.combinatorial.factorials import factorial
  13. def richardson(A, k, n, N):
  14. """
  15. Calculate an approximation for lim k->oo A(k) using Richardson
  16. extrapolation with the terms A(n), A(n+1), ..., A(n+N+1).
  17. Choosing N ~= 2*n often gives good results.
  18. Examples
  19. ========
  20. A simple example is to calculate exp(1) using the limit definition.
  21. This limit converges slowly; n = 100 only produces two accurate
  22. digits:
  23. >>> from sympy.abc import n
  24. >>> e = (1 + 1/n)**n
  25. >>> print(round(e.subs(n, 100).evalf(), 10))
  26. 2.7048138294
  27. Richardson extrapolation with 11 appropriately chosen terms gives
  28. a value that is accurate to the indicated precision:
  29. >>> from sympy import E
  30. >>> from sympy.series.acceleration import richardson
  31. >>> print(round(richardson(e, n, 10, 20).evalf(), 10))
  32. 2.7182818285
  33. >>> print(round(E.evalf(), 10))
  34. 2.7182818285
  35. Another useful application is to speed up convergence of series.
  36. Computing 100 terms of the zeta(2) series 1/k**2 yields only
  37. two accurate digits:
  38. >>> from sympy.abc import k, n
  39. >>> from sympy import Sum
  40. >>> A = Sum(k**-2, (k, 1, n))
  41. >>> print(round(A.subs(n, 100).evalf(), 10))
  42. 1.6349839002
  43. Richardson extrapolation performs much better:
  44. >>> from sympy import pi
  45. >>> print(round(richardson(A, n, 10, 20).evalf(), 10))
  46. 1.6449340668
  47. >>> print(round(((pi**2)/6).evalf(), 10)) # Exact value
  48. 1.6449340668
  49. """
  50. s = S.Zero
  51. for j in range(0, N + 1):
  52. s += (A.subs(k, Integer(n + j)).doit() * (n + j)**N *
  53. S.NegativeOne**(j + N) / (factorial(j) * factorial(N - j)))
  54. return s
  55. def shanks(A, k, n, m=1):
  56. """
  57. Calculate an approximation for lim k->oo A(k) using the n-term Shanks
  58. transformation S(A)(n). With m > 1, calculate the m-fold recursive
  59. Shanks transformation S(S(...S(A)...))(n).
  60. The Shanks transformation is useful for summing Taylor series that
  61. converge slowly near a pole or singularity, e.g. for log(2):
  62. >>> from sympy.abc import k, n
  63. >>> from sympy import Sum, Integer
  64. >>> from sympy.series.acceleration import shanks
  65. >>> A = Sum(Integer(-1)**(k+1) / k, (k, 1, n))
  66. >>> print(round(A.subs(n, 100).doit().evalf(), 10))
  67. 0.6881721793
  68. >>> print(round(shanks(A, n, 25).evalf(), 10))
  69. 0.6931396564
  70. >>> print(round(shanks(A, n, 25, 5).evalf(), 10))
  71. 0.6931471806
  72. The correct value is 0.6931471805599453094172321215.
  73. """
  74. table = [A.subs(k, Integer(j)).doit() for j in range(n + m + 2)]
  75. table2 = table[:]
  76. for i in range(1, m + 1):
  77. for j in range(i, n + m + 1):
  78. x, y, z = table[j - 1], table[j], table[j + 1]
  79. table2[j] = (z*x - y**2) / (z + x - 2*y)
  80. table = table2[:]
  81. return table[n]