Skip to main content

39_finite_difference_derivative/
39_finite_difference_derivative.rs

1//! # Example: Finite-Difference Derivative
2//!
3//! Run: cargo run --example 39_finite_difference_derivative
4//!
5//! ## Problem
6//! Approximate the derivative of a function sampled on a grid, without any symbolic
7//! math — just function values and arithmetic.
8//!
9//! ## Math idea
10//! The central difference `(f(x+h) - f(x-h)) / (2h)` approximates `f'(x)` with an
11//! error that shrinks like `h²` (second-order accurate). Here `f(x) = x³`, whose
12//! exact derivative is `3x²`; for a cubic the central-difference error is exactly
13//! `h²`, which makes the approximation easy to see.
14//!
15//! ## Tensor representation
16//! The sample grid is a 1-D `Tensor` built with `linspace`; the function values are
17//! another `Tensor` computed with elementwise multiplication.
18//!
19//! ## What this demonstrates
20//! - `Tensor::linspace` for an evenly spaced grid;
21//! - elementwise `Tensor` arithmetic (`&x * &x`) to evaluate `f`;
22//! - a central-difference stencil over the sampled values.
23//!
24//! ## Expected output
25//! ```text
26//! h = 0.25
27//!    x    f'approx   f'exact
28//! 0.25     0.2500    0.1875
29//! 0.50     0.8125    0.7500
30//! 0.75     1.7500    1.6875
31//! 1.00     3.0625    3.0000
32//! 1.25     4.7500    4.6875
33//! 1.50     6.8125    6.7500
34//! 1.75     9.2500    9.1875
35//! max abs error = 0.0625 (= h^2 = 0.0625)
36//! Finite-difference derivative: OK
37//! ```
38//!
39//! This is a numerical approximation, not symbolic differentiation.
40
41use matten::Tensor;
42
43fn main() {
44    // Evenly spaced sample grid on [0, 2].
45    let x = Tensor::linspace(0.0, 2.0, 9);
46    let xs = x.as_slice();
47    let h = xs[1] - xs[0];
48
49    // f(x) = x^3, evaluated with elementwise Tensor multiplication.
50    let x2 = &x * &x;
51    let f = &x2 * &x;
52    let fs = f.as_slice();
53
54    println!("h = {h}");
55    println!("   x    f'approx   f'exact");
56    let mut max_err = 0.0f64;
57    for i in 1..xs.len() - 1 {
58        let approx = (fs[i + 1] - fs[i - 1]) / (2.0 * h);
59        let exact = 3.0 * xs[i] * xs[i]; // d/dx x^3 = 3x^2
60        let err = (approx - exact).abs();
61        max_err = max_err.max(err);
62        println!("{:4.2}     {:6.4}    {:6.4}", xs[i], approx, exact);
63        // Central difference of x^3 has error exactly h^2.
64        assert!((approx - (exact + h * h)).abs() < 1e-9);
65    }
66    println!("max abs error = {max_err:.4} (= h^2 = {:.4})", h * h);
67    assert!((max_err - h * h).abs() < 1e-9);
68    println!("Finite-difference derivative: OK");
69}