123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- """Numerical Methods for Holonomic Functions"""
- from sympy.core.sympify import sympify
- from sympy.holonomic.holonomic import DMFsubs
- from mpmath import mp
- def _evalf(func, points, derivatives=False, method='RK4'):
- """
- Numerical methods for numerical integration along a given set of
- points in the complex plane.
- """
- ann = func.annihilator
- a = ann.order
- R = ann.parent.base
- K = R.get_field()
- if method == 'Euler':
- meth = _euler
- else:
- meth = _rk4
- dmf = []
- for j in ann.listofpoly:
- dmf.append(K.new(j.rep))
- red = [-dmf[i] / dmf[a] for i in range(a)]
- y0 = func.y0
- if len(y0) < a:
- raise TypeError("Not Enough Initial Conditions")
- x0 = func.x0
- sol = [meth(red, x0, points[0], y0, a)]
- for i, j in enumerate(points[1:]):
- sol.append(meth(red, points[i], j, sol[-1], a))
- if not derivatives:
- return [sympify(i[0]) for i in sol]
- else:
- return sympify(sol)
- def _euler(red, x0, x1, y0, a):
- """
- Euler's method for numerical integration.
- From x0 to x1 with initial values given at x0 as vector y0.
- """
- A = sympify(x0)._to_mpmath(mp.prec)
- B = sympify(x1)._to_mpmath(mp.prec)
- y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0]
- h = B - A
- f_0 = y_0[1:]
- f_0_n = 0
- for i in range(a):
- f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i]
- f_0.append(f_0_n)
- sol = []
- for i in range(a):
- sol.append(y_0[i] + h * f_0[i])
- return sol
- def _rk4(red, x0, x1, y0, a):
- """
- Runge-Kutta 4th order numerical method.
- """
- A = sympify(x0)._to_mpmath(mp.prec)
- B = sympify(x1)._to_mpmath(mp.prec)
- y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0]
- h = B - A
- f_0_n = 0
- f_1_n = 0
- f_2_n = 0
- f_3_n = 0
- f_0 = y_0[1:]
- for i in range(a):
- f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i]
- f_0.append(f_0_n)
- f_1 = [y_0[i] + f_0[i]*h/2 for i in range(1, a)]
- for i in range(a):
- f_1_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_0[i]*h/2)
- f_1.append(f_1_n)
- f_2 = [y_0[i] + f_1[i]*h/2 for i in range(1, a)]
- for i in range(a):
- f_2_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_1[i]*h/2)
- f_2.append(f_2_n)
- f_3 = [y_0[i] + f_2[i]*h for i in range(1, a)]
- for i in range(a):
- f_3_n += sympify(DMFsubs(red[i], A + h, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_2[i]*h)
- f_3.append(f_3_n)
- sol = []
- for i in range(a):
- sol.append(y_0[i] + h * (f_0[i]+2*f_1[i]+2*f_2[i]+f_3[i])/6)
- return sol
|