summaryrefslogtreecommitdiff
path: root/tutorials/module_3/4_numerical_integration.md
diff options
context:
space:
mode:
Diffstat (limited to 'tutorials/module_3/4_numerical_integration.md')
-rw-r--r--tutorials/module_3/4_numerical_integration.md177
1 files changed, 162 insertions, 15 deletions
diff --git a/tutorials/module_3/4_numerical_integration.md b/tutorials/module_3/4_numerical_integration.md
index 6e534b5..78b0328 100644
--- a/tutorials/module_3/4_numerical_integration.md
+++ b/tutorials/module_3/4_numerical_integration.md
@@ -47,40 +47,187 @@ $$
It is simple to implement and works especially well for tabulated data. Like the midpoint rule,
its accuracy is of order $O(h^2)$.
+
+
+```python
+import numpy as np
+
+a = 0
+b = np.pi
+n = 11
+h = (b - a) / (n - 1)
+x = np.linspace(a, b, n)
+f = np.sin(x)
+
+I_trap = (h/2)*(f[0] + 2 * sum(f[1:n-1]) + f[n-1])
+err_trap = 2 - I_trap
+
+print(I_trap)
+print(err_trap)
+```
+
+
### Simpson’s Rule
Simpson’s rules use polynomial interpolation to achieve higher accuracy.
-- **Simpson’s 1/3 Rule (order $O(h^4)$)**
+**Simpson’s 1/3 Rule (order $O(h^4)$)**
Requires an even number of sub-intervals $n$:
$$
I \approx \frac{h}{3}\Big[f(x_0) + 4\sum_{\text{odd } i} f(x_i) +
2\sum_{\text{even } i<n} f(x_i) + f(x_n)\Big].
$$
+```python
+import numpy as np
+
+a = 0
+b = np.pi
+n = 11
+h = (b - a) / (n - 1)
+x = np.linspace(a, b, n)
+f = np.sin(x)
+
+I_simp = (h/3) * (f[0] + 2*sum(f[:n-2:2]) \
+ + 4*sum(f[1:n-1:2]) + f[n-1])
+err_simp = 2 - I_simp
-- **Simpson’s 3/8 Rule**
- Based on cubic interpolation across three subintervals:
+print(I_simp)
+print(err_simp)
+```
+
+
+**Simpson’s 3/8 Rule**
+Based on cubic interpolation across three subintervals:
$$
I \approx \frac{3h}{8}\Big[f(x_0) + 3f(x_1) + 3f(x_2) + f(x_3)\Big].
$$
- Often used to handle the final three panels when \(n\) is not divisible by two.
+Often used to handle the final three panels when \(n\) is not divisible by two.
+
+```python
+import numpy as np
+
+a = 0
+b = np.pi
+n = 11
+h = (b - a) / (n - 1)
+x = np.linspace(a, b, n)
+f = np.sin(x)
+
+I_simp = (h/3) * (f[0] + 2*sum(f[:n-2:2]) \
+ + 4*sum(f[1:n-1:2]) + f[n-1])
+err_simp = 2 - I_simp
+
+print(I_simp)
+print(err_simp)
+```
### Romberg Integration
Romberg integration refines trapezoidal approximations using Richardson extrapolation to cancel error terms. This results in very rapid convergence for smooth functions, making it a powerful method once the trapezoidal rule is implemented.
+```python
+import numpy as np
+
+a = 0.0
+b = 1.0
+
+f = lambda x: np.exp(-x**2)
+
+iter_ = 0
+iter_max = 50
+err = 1.0
+tol = 1e-14
+
+I = np.zeros((iter_max + 2, iter_max + 2), dtype=float)
+
+def trap_func(func, a, b, n):
+ """Composite trapezoidal rule with n subintervals on [a, b]."""
+ h = (b - a) / n
+ x = np.linspace(a, b, n + 1)
+ y = func(x)
+ return h * (0.5 * y[0] + y[1:-1].sum() + 0.5 * y[-1])
+
+
+n = 1
+I[0, 0] = trap_func(f, a, b, n)
+
+# ---- Romberg loop ----
+while (iter_ < iter_max) and (err > tol):
+ iter_ += 1
+ n = 2 ** iter_
+ I[iter_, 0] = trap_func(f, a, b, n)
+ for k in range(1, iter_ + 1):
+ j = iter_ - k
+ I[j, k] = (4**k * I[j + 1, k - 1] - I[j, k - 1]) / (4**k - 1)
+ if iter_ >= 1:
+ err = abs((I[0, iter_] - I_]()
+```
+
### Gaussian Quadrature
-Gaussian quadrature chooses evaluation points and weights optimally (based on Legendre
-polynomials) to maximize accuracy. With $n$ evaluation points, Gaussian quadrature is exact for polynomials of degree up to $2n-1$. This makes it extremely efficient for smooth integrands.
+Gaussian quadrature chooses evaluation points and weights optimally (based on Legendre polynomials) to maximize accuracy. With $n$ evaluation points, Gaussian quadrature is exact for polynomials of degree up to $2n-1$. This makes it extremely efficient for smooth integrands.
+
+```python
+import numpy as np
+
+a, b = 0.0, 1.0 # integration limits [a, b]
+n_list = [2, 3, 4, 5, 8, 16] # quadrature orders to try
+
+for n in n_list:
+ xi, wi = np.polynomial.legendre.leggauss(n)
+ x = 0.5*(b - a)*xi + 0.5*(b + a)
+ f_vals = np.exp(-x**2) # f(x) = e^(-x^2)
+
+ I_approx = 0.5*(b - a) * np.sum(wi * f_vals)
+ print(f"{n:<3}| {I_approx:.12f}")
+
+```
+
+
+
+```python
+#!/usr/bin/env python3
+# Gauss Quadrature using Gauss-Legendre method (manual 2-point & 3-point)
+
+import numpy as np
+from scipy.integrate import quad # for reference "exact" integral
+
+# ---- Establish a, b, and the function ----
+a = 0.0
+b = 1.0
+f = lambda x: np.exp(-x**2) # example: f(x) = e^(-x^2)
+
+# ---- Common factor ----
+dx = (b - a) / 2.0
+
+# ---- Two-point Gauss-Legendre ----
+x0 = ((b + a) + (b - a) * (-1/np.sqrt(3))) / 2
+x1 = ((b + a) + (b - a) * ( 1/np.sqrt(3))) / 2
+I_2Point = (f(x0) + f(x1)) * dx
+print(f"2-point Gauss-Legendre: {I_2Point:.10f}")
+
+# ---- Three-point Gauss-Legendre ----
+c0, c1, c2 = 5/9, 8/9, 5/9
+x0 = ((b + a) + (b - a) * (-np.sqrt(3/5))) / 2
+x1 = ((b + a) + (b - a) * (0.0)) / 2
+x2 = ((b + a) + (b - a) * ( np.sqrt(3/5))) / 2
+I_3Point = (c0*f(x0) + c1*f(x1) + c2*f(x2)) * dx
+print(f"3-point Gauss-Legendre: {I_3Point:.10f}")
+
+# ---- Actual value using scipy.integrate.quad ----
+I_actual, _ = quad(f, a, b)
+print(f"Actual (scipy.quad): {I_actual:.10f}")
+
+# ---- Errors ----
+err2 = abs(I_actual - I_2Point)
+err3 = abs(I_actual - I_3Point)
+print(f"Error (2-point): {err2:.2e}")
+print(f"Error (3-point): {err3:.2e}")
+
+```
+
+
----
-## Taking this further
-- **Romberg Integration:** Demonstrates how extrapolation accelerates convergence of trapezoidal approximations.
-- **Gaussian Quadrature:** Introduces optimal integration points and highlights efficiency for
-polynomial and smooth functions.
-- **Simpson’s Rules:** Show how higher-order polynomial interpolation improves accuracy.
-These methods will be implemented and compared in subsequent assignments to build a deeper understanding of numerical integration accuracy and efficiency.
---
@@ -121,12 +268,12 @@ Students should compare results for increasing $n$ and observe how the error dec
## Gaussian Quadrature
-Implement a Python function for two-point and three-point Gauss–Legendre quadrature over an arbitrary interval $[a,b]$. Verify exactness for polynomials up to the appropriate degree and compare performance against the trapezoidal rule on oscillatory test functions.
+Write a Python function for two-point and three-point Gauss–Legendre quadrature over an arbitrary interval $[a,b]$. Verify exactness for polynomials up to the appropriate degree and compare performance against the trapezoidal rule on oscillatory test functions.
---
## Simpson’s 1/3 Rule
-Implement the composite Simpson’s 1/3 rule. Test its accuracy on smooth functions and compare its performance to the trapezoidal rule and Gaussian quadrature. Document error trends and discuss cases where Simpson’s method is preferable.
+Code the composite Simpson’s 1/3 rule. Test its accuracy on smooth functions and compare its performance to the trapezoidal rule and Gaussian quadrature. Document error trends and discuss cases where Simpson’s method is preferable.
---