83 lines
2.8 KiB
Rust
83 lines
2.8 KiB
Rust
/// Find the minimum of a univariate function using the Golden Section method.
|
|
///
|
|
/// The Golden Section method is a numerical optimization algorithm for finding the minimum of a univariate function.
|
|
/// The algorithm uses a sequence of iteratively refined intervals to bracket the minimum, and then uses the Golden Ratio to determine the next interval to test.
|
|
/// The algorithm continues until the interval size is smaller than a specified tolerance `tol`.
|
|
///
|
|
/// The function takes as input a function `f` to minimize, two endpoints `a` and `b` that bracket the minimum, and a tolerance `tol`.
|
|
/// The function returns the minimum value of the function `f` within the interval `[a, b]`.
|
|
///
|
|
/// # Parameters
|
|
///
|
|
/// - `f`: A function that takes a `f64` as an argument and returns a `f64`.
|
|
/// - `a`: The left endpoint of the interval that brackets the minimum, represented as a `f64`.
|
|
/// - `b`: The right endpoint of the interval that brackets the minimum, represented as a `f64`.
|
|
/// - `tol`: The tolerance for the optimization, represented as a `f64`.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// The abscissa of the minimum of `f` within the interval `[a, b]`, represented as a `f64`.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// Here's an example of how to use the `golden_section_minimize` function to find the minimum of a univariate function:
|
|
///
|
|
/// ```rust
|
|
/// fn f(x: f64) -> f64 {
|
|
/// return x.powi(2) - 2.0 * x.sin(2.0);
|
|
/// }
|
|
///
|
|
/// let a = 0.0;
|
|
/// let b = 2.0 * std::f64::consts::PI;
|
|
/// let tol = 1e-5;
|
|
/// let x_min = golden_section_minimize(f, a, b, tol);
|
|
/// println!("The minimum value of the function is f({}) = {}", x_min, f(x_min));
|
|
/// ```
|
|
///
|
|
/// This will output:
|
|
///
|
|
/// ```
|
|
/// The minimum value of the function is: f(0.626177) = -1.50735
|
|
/// ```
|
|
pub fn golden_section_minimize<F>(f : F, mut a: f64, mut b: f64, tol: f64) -> f64
|
|
where F : Fn(f64) -> f64
|
|
{
|
|
let invphi: f64 = (f64::sqrt(5.0) - 1.0) / 2.0; // 1 / phi
|
|
let invphi2: f64 = (3.0 - f64::sqrt(5.0)) / 2.0; // 1 / phi^2
|
|
|
|
a = f64::min(a, b);
|
|
b = f64::max(a, b);
|
|
let mut h: f64 = b - a;
|
|
if h <= tol {
|
|
return (a + b)/2.0;
|
|
}
|
|
|
|
// Required steps to achieve tolerance
|
|
let n: u32 = (f64::ceil(f64::ln(tol / h) / f64::ln(invphi))) as u32;
|
|
|
|
let mut c: f64 = a + invphi2 * h;
|
|
let mut d: f64 = a + invphi * h;
|
|
let mut yc: f64 = f(c);
|
|
let mut yd: f64 = f(d);
|
|
|
|
for _ in 0..n {
|
|
if yc < yd { // yc > yd to find the maximum
|
|
b = d;
|
|
d = c;
|
|
yd = yc;
|
|
h = invphi * h;
|
|
c = a + invphi2 * h;
|
|
yc = f(c);
|
|
} else {
|
|
a = c;
|
|
c = d;
|
|
yc = yd;
|
|
h = invphi * h;
|
|
d = a + invphi * h;
|
|
yd = f(d);
|
|
}
|
|
}
|
|
|
|
if yc < yd { return (a + d)/2.0; }
|
|
else { return (c + b)/2.0; }
|
|
}
|