numerical.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """Numerical Methods for Holonomic Functions"""
  2. from sympy.core.sympify import sympify
  3. from sympy.holonomic.holonomic import DMFsubs
  4. from mpmath import mp
  5. def _evalf(func, points, derivatives=False, method='RK4'):
  6. """
  7. Numerical methods for numerical integration along a given set of
  8. points in the complex plane.
  9. """
  10. ann = func.annihilator
  11. a = ann.order
  12. R = ann.parent.base
  13. K = R.get_field()
  14. if method == 'Euler':
  15. meth = _euler
  16. else:
  17. meth = _rk4
  18. dmf = []
  19. for j in ann.listofpoly:
  20. dmf.append(K.new(j.rep))
  21. red = [-dmf[i] / dmf[a] for i in range(a)]
  22. y0 = func.y0
  23. if len(y0) < a:
  24. raise TypeError("Not Enough Initial Conditions")
  25. x0 = func.x0
  26. sol = [meth(red, x0, points[0], y0, a)]
  27. for i, j in enumerate(points[1:]):
  28. sol.append(meth(red, points[i], j, sol[-1], a))
  29. if not derivatives:
  30. return [sympify(i[0]) for i in sol]
  31. else:
  32. return sympify(sol)
  33. def _euler(red, x0, x1, y0, a):
  34. """
  35. Euler's method for numerical integration.
  36. From x0 to x1 with initial values given at x0 as vector y0.
  37. """
  38. A = sympify(x0)._to_mpmath(mp.prec)
  39. B = sympify(x1)._to_mpmath(mp.prec)
  40. y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0]
  41. h = B - A
  42. f_0 = y_0[1:]
  43. f_0_n = 0
  44. for i in range(a):
  45. f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i]
  46. f_0.append(f_0_n)
  47. sol = []
  48. for i in range(a):
  49. sol.append(y_0[i] + h * f_0[i])
  50. return sol
  51. def _rk4(red, x0, x1, y0, a):
  52. """
  53. Runge-Kutta 4th order numerical method.
  54. """
  55. A = sympify(x0)._to_mpmath(mp.prec)
  56. B = sympify(x1)._to_mpmath(mp.prec)
  57. y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0]
  58. h = B - A
  59. f_0_n = 0
  60. f_1_n = 0
  61. f_2_n = 0
  62. f_3_n = 0
  63. f_0 = y_0[1:]
  64. for i in range(a):
  65. f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i]
  66. f_0.append(f_0_n)
  67. f_1 = [y_0[i] + f_0[i]*h/2 for i in range(1, a)]
  68. for i in range(a):
  69. f_1_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_0[i]*h/2)
  70. f_1.append(f_1_n)
  71. f_2 = [y_0[i] + f_1[i]*h/2 for i in range(1, a)]
  72. for i in range(a):
  73. f_2_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_1[i]*h/2)
  74. f_2.append(f_2_n)
  75. f_3 = [y_0[i] + f_2[i]*h for i in range(1, a)]
  76. for i in range(a):
  77. f_3_n += sympify(DMFsubs(red[i], A + h, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_2[i]*h)
  78. f_3.append(f_3_n)
  79. sol = []
  80. for i in range(a):
  81. sol.append(y_0[i] + h * (f_0[i]+2*f_1[i]+2*f_2[i]+f_3[i])/6)
  82. return sol