1+ """
2+ Numerical methods for solving Ordinary Differential Equations (ODEs) of the form y' = f(x, y).
3+ This module implements the Euler method and Heun's method.
4+
5+ References:
6+ - Euler Method: https://en.wikipedia.org/wiki/Euler_method
7+ - Heun's Method: https://en.wikipedia.org/wiki/Heun%27s_method
8+
9+ """
10+
11+ from typing import Callable , List , Tuple
12+
13+
14+ def euler_method (
15+ f : Callable [[float , float ], float ], x0 : float , y0 : float , h : float , steps : int
16+ ) -> Tuple [List [float ], List [float ]]:
17+ """
18+ Approximates the solution of a first-order ODE y' = f(x, y) using Euler's method.
19+
20+ :param f: The differential equation function f(x, y).
21+ :param x0: Initial value of x.
22+ :param y0: Initial value of y (y(x0) = y0).
23+ :param h: Step size.
24+ :param steps: Number of iterations to perform.
25+ :return: A tuple containing lists of x and y coordinates.
26+
27+ >>> def f_ode(x: float, y: float) -> float: return y - x**2 + 1
28+ >>> x_vals, y_vals = euler_method(f_ode, 0.0, 0.5, 0.25, 2)
29+ >>> [round(i, 4) for i in x_vals]
30+ [0.0, 0.25, 0.5]
31+ >>> [round(i, 4) for i in y_vals]
32+ [0.5, 0.875, 1.3281]
33+ """
34+ x = [0.0 ] * (steps + 1 )
35+ y = [0.0 ] * (steps + 1 )
36+ x [0 ], y [0 ] = x0 , y0
37+
38+ for i in range (steps ):
39+ y [i + 1 ] = y [i ] + f (x [i ], y [i ]) * h
40+ x [i + 1 ] = x [i ] + h
41+
42+ return x , y
43+
44+
45+ def heuns_method (
46+ f : Callable [[float , float ], float ], x0 : float , y0 : float , h : float , steps : int
47+ ) -> Tuple [List [float ], List [float ]]:
48+ """
49+ Approximates the solution of a firs -order ODE y' = f(x, y) using Heun's method
50+ (also known as the improved Euler method).
51+
52+ :param f: The differential equation function f(x, y).
53+ :param x0: Initial value of x.
54+ :param y0: Initial value of y.
55+ :param h: Step size.
56+ :param steps: Number of iterations to perform.
57+ :return: A tuple containing lists of x and y coordinates.
58+
59+ >>> def f_ode(x: float, y: float) -> float: return y - x**2 + 1
60+ >>> x_vals, y_vals = heuns_method(f_ode, 0.0, 0.5, 0.25, 2)
61+ >>> [round(i, 4) for i in y_vals]
62+ [0.5, 0.9141, 1.4114]
63+ """
64+ x = [0.0 ] * (steps + 1 )
65+ y = [0.0 ] * (steps + 1 )
66+ x [0 ], y [0 ] = x0 , y0
67+
68+ for i in range (steps ):
69+ y_predictor = y [i ] + f (x [i ], y [i ]) * h
70+ x [i + 1 ] = x [i ] + h
71+ y [i + 1 ] = y [i ] + ((f (x [i ], y [i ]) + f (x [i + 1 ], y_predictor )) / 2.0 ) * h
72+
73+ return x , y
74+
75+
76+
77+
78+
79+ if __name__ == "__main__" :
80+ import doctest
81+
82+ doctest .testmod ()
83+
84+ # example
85+ def example_ode (x : float , y : float ) -> float :
86+ return y - x ** 2 + 1
87+
88+ x_res , y_res = heuns_method (example_ode , 0.0 , 0.5 , 0.25 , 4 )
89+ print (f"Final heuns methot y value at x={ x_res [- 1 ]} : { round (y_res [- 1 ], 4 )} " )
0 commit comments