In [1]:
# Import modules
import math
import numpy as np
import scipy
from scipy.integrate import ode
from matplotlib import pyplot as plt
In [24]:
def euler_method(f, a, b, y0, step=10):
t = a
w = y0
ws = np.zeros(step + 1)
ws[0] = y0
h = (b - a) / step
for i in range(step):
w += h * f(t, w)
t += h
ws[i + 1] = w
return w, ws
In [27]:
f = lambda t, y : t * y + np.power(t, 3)
w = euler_method(f, 0, 1, 1)
print(w[0])
In [65]:
f = lambda t, y : -4 * np.power(t, 3) * np.power(y, 2)
y = lambda t : 1 / (np.power(t, 4) + 1)
_, ws4 = euler_method(f, -10, 0, 1.0 / 10001.0, int(1e4))
_, ws5 = euler_method(f, -10, 0, 1.0 / 10001.0, int(1e5))
w, ws6 = euler_method(f, -10, 0, 1.0 / 10001.0, int(1e6))
x4 = np.linspace(-10, 0 , int(1e4) + 1)
x5 = np.linspace(-10, 0 , int(1e5) + 1)
x6 = np.linspace(-10, 0 , int(1e6) + 1)
plt.plot(x4, ws4, linewidth=3, label='$h = 10^{-3}$')
plt.plot(x5, ws5, linewidth=3, label='$h = 10^{-4}$')
plt.plot(x6, ws6, linewidth=3, label='$h = 10^{-5}$')
plt.axhline(1.0, color='gray', linewidth=3, linestyle='--')
plt.axvline(0, color='black')
plt.axhline(0, color='black')
plt.legend()
plt.show()
In [4]:
def explicit_trapezoid_method(f, a, b, y0, step = 10):
t = a
w = y0
ws = np.zeros(step + 1)
ws[0] = y0
h = (b - a) / step
for i in range(step):
w += ( h / 2 ) * ( f(t, w) + f(t + h, w + h * f(t, w) ) )
t += h
ws[i + 1] = w
return w, ws
In [69]:
f = lambda t, y : t * y + np.power(t, 3)
w, _ = explicit_trapezoid_method(f, 0, 1, 1, step = int(1e1) )
print(w)
In [3]:
def euler_method_vec(f1, f2, a, b, y0, step=10):
t = a
ws1 = np.zeros(step + 1)
ws2 = np.zeros(step + 1)
ws1[0] = y0[0]
ws2[0] = y0[1]
h = (b - a) / step
for i in range(step):
ws1[i + 1] = ws1[i] + h * f1(ws1[i], ws2[i])
ws2[i + 1] = ws2[i] + h * f2(t, ws1[i], ws2[i])
t += h
return ws1, ws2
In [7]:
f1 = lambda y1, y2 : np.power(y2, 2) - 2 * y1
f2 = lambda t, y1, y2 : y1 - y2 - t * np.power(y2, 2)
euler_method_vec(f1, f2, 0, 1, np.array([0, 1]), 10)
Out[7]:
In [29]:
def midpoint_method(f, a, b, y0, step = 10):
t = a
w = y0
ws = np.zeros(step + 1)
ws[0] = y0
h = (b - a) / step
for i in range(step):
w += h * f(t + h / 2, w + h / 2 * f(t, w))
t += h
ws[i + 1] = w
return ws
In [97]:
def runge_kutta_method(f, a, b, y0, step = 10):
t = a
h = (b - a) / step
w_data = np.zeros(step + 1)
w = w_data[0] = y0
for i in range(step):
s1 = f(t, w)
s2 = f(t + h / 2, w + s1 * h / 2)
s3 = f(t + h / 2, w + s2 * h / 2)
s4 = f(t + h, w + h * s3)
t += h
w += h / 6 * (s1 + 2 * s2 + 2 * s3 + s4)
w_data[i + 1] = w
return w_data
In [100]:
f = lambda t, y : t * y + np.power(t, 3)
ans = lambda t : - pow(t, 2) - 2 + 3 * math.exp(pow(t, 2) / 2)
w_data = runge_kutta_method(f, 0, 1, 1, step = 10)
print(' answer:%.15f' %ans(1) )
print('predict:%.15f' %w_data[-1] )
where
$$ \begin{align*} s_1 &= f(t_i, w_i) \\ s_2 &= f(t_i + h, w_i + hs_1) \\ s_3 &= f(t_i + \frac{1}{2}h, w_i + \frac{1}{2}h\frac{s_1 + s_2}{2}) \\ e_{i+1} &\approx |w_{i+1} - z_{i+1}| = |h\frac{s_1 - 2s_3 + s_2}{3}| \end{align*} $$
In [2]:
def ode_rkf45(f, t0, b, y0, h = 1e-3, tol = 1e-6):
w = y0
t = t0
while(t < b):
w_this, t_this = w, t
s1 = f(t, w)
hs1 = h * s1
s2 = f(t + h / 4, w + hs1 / 4)
hs2 = h * s2
s3 = f(t + 3 / 8 * h, w + 3 / 32 * hs1 + 9 / 32 * hs2)
hs3 = h * s3
s4 = f(t + 12 / 13 * h, w + 1932 / 2197 * hs1 - 7200 / 2197 * hs2 + 7296 / 2197 * hs3)
hs4 = h * s4
s5 = f(t + h, w + 439 / 216 * hs1 - 8 * hs2 + 3680 / 513 * hs3 - 845 / 4104 * hs4)
hs5 = s5 * h
s6 = f(t + h / 2, w - 8 / 27 * hs1 + 2 * hs2 - 3544 / 2565 * hs3 + 1859 / 4104 * hs4 - 11 / 40 * hs5)
z = w + h * (16 / 135 * s1 + 6656 / 12825 * s3 + 28561 / 56430 * s4 - 9 / 50 * s5 + 2 / 55 * s6)
w += h * (25 / 216 * s1 + 1408 / 2565 * s3 + 2197 / 4104 * s4 - s5 / 5)
t += h
e = abs(z - w)
if e / abs(w) < tol:
w = z
else:
h = 0.8 * pow(tol * abs(w) / e, 1 / 5) * h
return w
In [89]:
f = lambda t, y : t * y + np.power(t, 3)
ans = lambda t : - pow(t, 2) - 2 + 3 * math.exp(pow(t, 2) / 2)
print('%.15f' %ans(1) )
print('%.15f' %ode_rkf45(f, 0, 1, 1, tol=1e-13) )
In [27]:
f = lambda t, y : t * y + np.power(t, 3)
r = ode(f).set_integrator('dopri5')
r.set_initial_value(1, 0)
terminate = 0.9
dt = 0.1
while r.successful() and r.t <= terminate:
print(r.t + dt, r.integrate(r.t + dt))
In [3]:
step = 20
f = lambda z, h, d : 9 * h * np.power(z, 3) - 8 * h * np.power(z, 2) + (1 - h) * z - d
x0 = 0.5
h = 0.15
y0 =0.5
for _ in range(step):
z = scipy.optimize.newton(f, x0, args=(h, y0))
x0 = y0 = z
print(z)
In [37]:
def adams_bashforth(f, a, b, y0, step = 10):
h = (b - a) / step
w = y0
w_n = explicit_trapezoid_method(f, a, b, y0)[0]
t = a
t_n = a + h
for _ in range(step - 1):
tmp_w_n = w_n
w_n += h * (1.5 * f(t_n, w_n) - 0.5 * f(t, w))
w = tmp_w_n
t_n += h
t += h
return w_n
In [38]:
f = lambda t, w : -3 * w
w = adams_bashforth(f, 0, 2, 1, step = 20)
print(w)