Skip to content

Commit 566d47d

Browse files
committed
feat(maths): add numerical methods for solving ordinary differential equations
1 parent e3b01ec commit 566d47d

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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

Comments
 (0)