rustamath_mnmz/
golden_section.rs1use super::bracket::{find_bracket, shft3, shft2};
12
13const MIN_TOLERANCE: f64 = 3.0e-8_f64;
18
19pub fn golden_section_search<F: Fn (f64) -> f64>(
46 fun: F,
47 a: f64,
48 b: f64,
49 tol: f64,
50 max_iterations: usize
51) -> (f64, f64, usize)
52{
53 let tol = tol.max(MIN_TOLERANCE);
54 let max_iterations = if max_iterations < 1 { 500 } else { max_iterations.min(1000) };
55 const R: f64 = 0.61803399_f64;
56 const C: f64 = 1.0 - R; let bracket = find_bracket(&fun, a, b);
59 let a = bracket.a;
60 let b = bracket.b;
61 let c = bracket.c;
62
63 let mut x1: f64;
65 let mut x2: f64;
66 let mut x0 = a;
67 let mut x3 = c;
68
69 if (c-b).abs() > (b-a).abs() {
71 x1 = b;
72 x2 = b + C*(c-b);
73 } else {
74 x2 = b;
75 x1 = b - C*(b-a);
76 }
77
78 let mut f1 = fun(x1);
81 let mut f2 = fun(x2);
82 let mut nr_iterations: usize = 0;
83
84 while (x3-x0).abs() > tol*(x1.abs() + x2.abs()) {
85 if f2 < f1 {
86 let d = R*x2 + C*x3;
87 shft3(&mut x0, &mut x1, &mut x2, d);
88 shft2(&mut f1, &mut f2, fun(x2));
89 }
90 else {
91 let d = R*x1 + C*x0;
92 shft3(&mut x3, &mut x2, &mut x1, d);
93 shft2(&mut f2, &mut f1, fun(x1));
94 }
95 nr_iterations += 1;
96
97 if nr_iterations >= max_iterations { break; }
98
99 if nr_iterations > 10 && (x3-x0).abs() < tol && (f1 - f2).abs() < tol { break; }
103 }
104
105 if f1 < f2 {
107 (x1, f1, nr_iterations)
108 }
109 else {
110 (x2, f2, nr_iterations)
111 }
112}
113
114#[cfg(test)]
115#[test]
116fn test_poly2() {
117 let poly2 = |x: f64| (x-1.0)*(x-2.0);
119
120 let ranges = vec![(10.0, 20.0), (20.0, 10.0), (-10.0, 0.0),
121 (-2000.0, -1000.0), (-10_000.0, 30_000.0), (0.0001, 0.0002), (-0.00001, 1.4999)];
122
123 for range in ranges {
124 let (xmin, f, nr_iterations) = golden_section_search(poly2, range.0, range.1, 0.0, 0);
125
126 println!("MIN: {:.8} f(xmin): {:6.2} iterations:{}",
127 xmin, f, nr_iterations
128 );
129
130 assert_float_relative_eq!(xmin, 1.5, 1.0e-8);
131 }
132}
133
134#[cfg(test)]
135#[test]
136fn test_cosine() {
137 let cosine = |x: f64| x.cos();
139
140 let ranges = vec![(0.01, 1.0)];
141
142 for range in ranges {
143 let (xmin, f, nr_iterations) = golden_section_search(cosine, range.0, range.1, 0.0, 0);
144
145 println!("MIN: {:.8} f(xmin): {:6.2} iterations:{}",
146 xmin, f, nr_iterations
147 );
148
149 assert_float_relative_eq!(xmin, std::f64::consts::PI, 1.0e-8);
150 }
151}
152
153#[cfg(test)]
154#[test]
155fn test_saw() {
156 let saw = |x: f64| if x >= 0.0 { x*x*x } else { -x / 1000.0 } ;
157
158 let ranges = vec![(10.0, 20.0), (20.0, 10.0), (-10.0, 0.0),
159 (-2000.0, -1000.0), (-10_000.0, 30_000.0), (0.0001, 0.0002), (-0.00001, 1.4999)];
160
161 for range in ranges {
162 let (xmin, f, nr_iterations) = golden_section_search(saw, range.0, range.1, 1.0e-5, 0);
163
164 println!("MIN: {:.8} f(xmin): {:6.2} iterations:{}",
165 xmin, f, nr_iterations
166 );
167
168 assert_float_absolute_eq!(xmin, 0.0, 1.0e-5);
169 }
170}