Added golden section search
This commit is contained in:
parent
5f56865f33
commit
6134559471
2 changed files with 78 additions and 7 deletions
36
src/main.rs
36
src/main.rs
|
|
@ -1,6 +1,7 @@
|
||||||
extern crate colored;
|
extern crate colored;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
mod univariate_solvers;
|
mod univariate_solvers;
|
||||||
|
mod univariate_minimizers;
|
||||||
|
|
||||||
/// x sin(x)
|
/// x sin(x)
|
||||||
/// e + ──────
|
/// e + ──────
|
||||||
|
|
@ -43,7 +44,7 @@ fn check_result(x : f64, x_true : f64, tol : f64, test_name: &str, verbose: bool
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
if verbose {
|
if verbose {
|
||||||
println!("{}\t: x = {}\tf(x) = {}\t{} (expected {})", test_name_padded, format!("{:<20}", x), format!("{:<40}", fct(x)), "failed".red(), x_true);
|
println!("{}\t: x = {}\tf(x) = {}\t{} (expected {}, delta = {})", test_name_padded, format!("{:<20}", x), format!("{:<40}", fct(x)), "failed".red(), x_true, (x - x_true));
|
||||||
} else {
|
} else {
|
||||||
println!("{} {} : expected {}, got {}", test_name_padded, "failed".red(), x_true, x);
|
println!("{} {} : expected {}, got {}", test_name_padded, "failed".red(), x_true, x);
|
||||||
}
|
}
|
||||||
|
|
@ -60,18 +61,18 @@ fn print_test_results(num_tests_passed: u32, num_tests_total: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn test_univariate_solvers(verbose: bool) {
|
||||||
println!("Testing Rust numerical solvers.");
|
println!("Testing univariate numerical solvers.");
|
||||||
let mut num_tests_passed : u32 = 0;
|
|
||||||
let num_tests_total : u32 = 7;
|
|
||||||
let verbose : bool = true;
|
|
||||||
let x0 : f64 = 1.0;
|
let x0 : f64 = 1.0;
|
||||||
let tol : f64 = 1e-10;
|
let tol : f64 = 1e-10;
|
||||||
let max_iter : u32 = 100;
|
let max_iter : u32 = 100;
|
||||||
let dx_num : f64 = 1e-6;
|
let dx_num : f64 = 1e-6;
|
||||||
|
let mut num_tests_passed : u32 = 0;
|
||||||
|
let num_tests_total : u32 = 7;
|
||||||
|
|
||||||
let x_mathematica: f64 = -3.26650043678562449167148755288;// 30 digits of precision
|
let x_mathematica: f64 = -3.26650043678562449167148755288;// 30 digits of precision
|
||||||
let x_mathematica_2: f64 = -6.27133405258685307845641527902;// 30 digits of precision
|
let x_mathematica_2: f64 = -6.27133405258685307845641527902;// 30 digits of precision
|
||||||
let x_mathematica_3: f64 = -9.42553801930504142668603949182;// 30 digits of precision
|
// let x_mathematica_3: f64 = -9.42553801930504142668603949182;// 30 digits of precision
|
||||||
let x_newton: f64 = univariate_solvers::newton_solve(&(fct as fn(f64) -> f64), &(dfct as fn(f64) -> f64), x0, tol, max_iter);
|
let x_newton: f64 = univariate_solvers::newton_solve(&(fct as fn(f64) -> f64), &(dfct as fn(f64) -> f64), x0, tol, max_iter);
|
||||||
let x_newton_num: f64 = univariate_solvers::newton_solve_num(&(fct as fn(f64) -> f64), x0, tol, dx_num, max_iter);
|
let x_newton_num: f64 = univariate_solvers::newton_solve_num(&(fct as fn(f64) -> f64), x0, tol, dx_num, max_iter);
|
||||||
let x_halley: f64 = univariate_solvers::halley_solve(&(fct as fn(f64) -> f64), &(dfct as fn(f64) -> f64), &(ddfct as fn(f64) -> f64), x0, tol, max_iter, false).unwrap();
|
let x_halley: f64 = univariate_solvers::halley_solve(&(fct as fn(f64) -> f64), &(dfct as fn(f64) -> f64), &(ddfct as fn(f64) -> f64), x0, tol, max_iter, false).unwrap();
|
||||||
|
|
@ -89,3 +90,24 @@ fn main() {
|
||||||
|
|
||||||
print_test_results(num_tests_passed, num_tests_total);
|
print_test_results(num_tests_passed, num_tests_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_univariate_optimizers(verbose: bool) {
|
||||||
|
let tol : f64 = 1e-10;
|
||||||
|
let max_iter : u32 = 100;
|
||||||
|
let dx_num : f64 = 1e-6;
|
||||||
|
let mut num_tests_passed : u32 = 0;
|
||||||
|
let num_tests_total : u32 = 1;
|
||||||
|
|
||||||
|
let x_mathematica: f64 = -4.54295618675514754103476876324;// 30 digits of precision
|
||||||
|
let y_mathematica: f64 = -0.206327079359226884630654987440;// 30 digits of precision
|
||||||
|
let x_golden_section: f64 = univariate_minimizers::golden_section_minimize(&(fct as fn(f64) -> f64), -7.0, -1.0, tol);
|
||||||
|
num_tests_passed += check_result(x_golden_section, x_mathematica, tol*1e2, "Golden section search", verbose);
|
||||||
|
print_test_results(num_tests_passed, num_tests_total);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Testing Rust numerical solvers.");
|
||||||
|
let verbose : bool = true;
|
||||||
|
test_univariate_solvers(verbose);
|
||||||
|
test_univariate_optimizers(verbose);
|
||||||
|
}
|
||||||
|
|
|
||||||
49
src/univariate_minimizers.rs
Normal file
49
src/univariate_minimizers.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
/// Golden section search for minimizing a function f(x)
|
||||||
|
/// @param f function to minimize
|
||||||
|
/// @param a left bracket
|
||||||
|
/// @param b right bracket
|
||||||
|
/// @param tol tolerance
|
||||||
|
/// @return solution
|
||||||
|
/// @note The interval [a, b] must bracket the minimum, and the function must have f''(x) > 0 over the interval [a, b] to garantee convergence.
|
||||||
|
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; }
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue