scirs2_optimize/derivative_free/
mod.rs1use crate::error::OptimizeResult;
20use crate::result::OptimizeResults;
21use scirs2_core::ndarray::{s, Array1, Array2};
22
23pub mod bobyqa;
24pub mod nelder_mead;
25pub mod pattern_search;
26
27pub use bobyqa::{BOBYQAOptions, BOBYQASolver};
28pub use nelder_mead::{NelderMeadOptions, NelderMeadSolver};
29pub use pattern_search::{PatternSearchOptions, PatternSearchSolver};
30
31#[derive(Debug, Clone)]
33pub struct DfOptResult {
34 pub x: Array1<f64>,
36 pub fun: f64,
38 pub nfev: usize,
40 pub nit: usize,
42 pub success: bool,
44 pub message: String,
46}
47
48impl From<DfOptResult> for OptimizeResults<f64> {
49 fn from(r: DfOptResult) -> Self {
50 OptimizeResults {
51 x: r.x,
52 fun: r.fun,
53 jac: None,
54 hess: None,
55 constr: None,
56 nit: r.nit,
57 nfev: r.nfev,
58 njev: 0,
59 nhev: 0,
60 maxcv: 0,
61 message: r.message,
62 success: r.success,
63 status: if r.success { 0 } else { 1 },
64 }
65 }
66}
67
68pub trait DerivativeFreeOptimizer {
70 fn minimize<F>(&self, func: F, x0: &[f64]) -> OptimizeResult<DfOptResult>
72 where
73 F: Fn(&[f64]) -> f64;
74}
75
76pub(crate) fn centroid(simplex: &Array2<f64>, n: usize) -> Array1<f64> {
78 let mut c = Array1::zeros(n);
79 for i in 0..n {
80 c += &simplex.slice(s![i, ..]);
81 }
82 c / n as f64
83}
84
85pub(crate) fn norm(v: &[f64]) -> f64 {
87 v.iter().map(|x| x * x).sum::<f64>().sqrt()
88}
89
90#[allow(dead_code)]
92pub(crate) fn finite_diff_grad<F: Fn(&[f64]) -> f64>(f: &F, x: &[f64], h: f64) -> Vec<f64> {
93 let n = x.len();
94 let mut g = vec![0.0; n];
95 let mut xp = x.to_vec();
96 let mut xm = x.to_vec();
97 for i in 0..n {
98 xp[i] += h;
99 xm[i] -= h;
100 g[i] = (f(&xp) - f(&xm)) / (2.0 * h);
101 xp[i] = x[i];
102 xm[i] = x[i];
103 }
104 g
105}
106
107#[inline]
109pub(crate) fn clip(v: f64, lo: f64, hi: f64) -> f64 {
110 v.max(lo).min(hi)
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_centroid_2d() {
119 let mut s = Array2::zeros((3, 2));
120 s[[0, 0]] = 0.0;
121 s[[0, 1]] = 0.0;
122 s[[1, 0]] = 1.0;
123 s[[1, 1]] = 0.0;
124 s[[2, 0]] = 0.0;
125 s[[2, 1]] = 1.0;
126 let c = centroid(&s, 2);
128 assert!((c[0] - 0.5).abs() < 1e-12);
129 assert!((c[1] - 0.0).abs() < 1e-12);
130 }
131
132 #[test]
133 fn test_norm() {
134 let v = vec![3.0_f64, 4.0];
135 assert!((norm(&v) - 5.0).abs() < 1e-12);
136 }
137}