1use crate::{Native, linalg::{Factor, axpy, dot, givens, lstsq}, random::{Key, unit}};
9use rand::Rng;
10use std::collections::VecDeque;
11
12pub trait Objective<F> {
14 type Error;
16 fn value(&mut self, x: &[F]) -> Result<F, Self::Error>;
18 fn batch(&self) -> bool { false }
20 fn values(&mut self, xs: &[F], out: &mut [F]) -> Result<(), Self::Error> { let _ = (xs, out); unreachable!("this objective evaluates no batches") }
22 fn has_gradient(&self) -> bool { false }
24 fn gradient(&mut self, x: &[F], g: &mut [F]) -> Result<(), Self::Error> { let _ = (x, g); unreachable!("this objective has no gradient") }
26}
27
28impl<F, E, V: FnMut(&[F]) -> Result<F, E>> Objective<F> for V {
29 type Error = E;
30 fn value(&mut self, x: &[F]) -> Result<F, E> { self(x) }
31}
32
33pub trait Mapping<F> {
35 type Error;
37 fn value(&mut self, x: &[F], out: &mut [F]) -> Result<(), Self::Error>;
39 fn has_vjp(&self) -> bool { false }
41 fn vjp(&mut self, u: &[F], x: &[F], out: &mut [F]) -> Result<(), Self::Error> {
43 let _ = (u, x, out);
44 unreachable!("this mapping has no vector–Jacobian product")
45 }
46 fn has_jvp(&self) -> bool { false }
48 fn jvp(&mut self, v: &[F], x: &[F], out: &mut [F]) -> Result<bool, Self::Error> {
50 let _ = (v, x, out);
51 unreachable!("this mapping has no Jacobian–vector product")
52 }
53 fn jacobian(&mut self, x: &[F], j: &mut [F]) -> Result<bool, Self::Error> where F: Native {
55 let n = x.len();
56 if n == 0 { return Ok(false); }
57 let m = j.len() / n;
58 if self.has_vjp() && (m <= n || !self.has_jvp()) {
59 let mut u = vec![F::zero(); m];
60 for (i, row) in j.chunks_exact_mut(n).enumerate() {
61 u[i] = F::one();
62 self.vjp(&u, x, row)?;
63 u[i] = F::zero();
64 }
65 return Ok(true);
66 }
67 if !self.has_jvp() { return Ok(false); }
68 let (mut v, mut column) = (vec![F::zero(); n], vec![F::zero(); m]);
69 for c in 0..n {
70 v[c] = F::one();
71 if !self.jvp(&v, x, &mut column)? { return Ok(false); }
72 v[c] = F::zero();
73 for (i, &value) in column.iter().enumerate() { j[i * n + c] = value; }
74 }
75 Ok(true)
76 }
77 fn has_preconditioner(&self) -> bool { false }
79 fn precondition(&mut self, v: &[F], out: &mut [F]) -> Result<(), Self::Error> { let _ = (v, out); unreachable!("this mapping has no preconditioner") }
81}
82
83impl<F, E, V: FnMut(&[F], &mut [F]) -> Result<(), E>> Mapping<F> for V {
84 type Error = E;
85 fn value(&mut self, x: &[F], out: &mut [F]) -> Result<(), E> { self(x, out) }
86}
87
88pub struct Differentiable<V, G> { pub value: V, pub derivative: G }
90
91impl<F, E, V: FnMut(&[F]) -> Result<F, E>, G: FnMut(&[F], &mut [F]) -> Result<(), E>> Objective<F> for Differentiable<V, G> {
92 type Error = E;
93 fn value(&mut self, x: &[F]) -> Result<F, E> { (self.value)(x) }
94 fn has_gradient(&self) -> bool { true }
95 fn gradient(&mut self, x: &[F], g: &mut [F]) -> Result<(), E> { (self.derivative)(x, g) }
96}
97
98impl<F, E, V: FnMut(&[F], &mut [F]) -> Result<(), E>, G: FnMut(&[F], &[F], &mut [F]) -> Result<(), E>> Mapping<F> for Differentiable<V, G> {
99 type Error = E;
100 fn value(&mut self, x: &[F], out: &mut [F]) -> Result<(), E> { (self.value)(x, out) }
101 fn has_vjp(&self) -> bool { true }
102 fn vjp(&mut self, u: &[F], x: &[F], out: &mut [F]) -> Result<(), E> { (self.derivative)(u, x, out) }
103}
104
105#[derive(Clone, Copy, Debug, PartialEq, Eq)]
107pub enum Method {
108 Brent,
110 NelderMead,
112 Powell,
114 Lbfgs,
116 Evolution,
118 LevenbergMarquardt,
120 Cg,
122 Minres,
124 Gmres,
126}
127
128impl Method {
129 pub const NAMES: [(&'static str, Method); 9] = [
131 ("brent", Method::Brent), ("nelder-mead", Method::NelderMead), ("powell", Method::Powell), ("l-bfgs", Method::Lbfgs),
132 ("differential-evolution", Method::Evolution), ("levenberg-marquardt", Method::LevenbergMarquardt), ("cg", Method::Cg), ("minres", Method::Minres),
133 ("gmres", Method::Gmres),
134 ];
135
136 pub fn choose(task: Task, variables: usize, bounded: bool) -> Method {
138 match task {
139 Task::Minimize { gradient } => {
140 if variables == 1 { Method::Brent }
141 else if gradient && !bounded { Method::Lbfgs }
142 else if bounded { Method::Powell }
143 else { Method::NelderMead }
144 }
145 Task::Solve { residuals } => { if variables == 1 && residuals == 1 { Method::Brent } else { Method::LevenbergMarquardt } }
146 Task::Linear { .. } => { if task.least_squares(variables) { Method::Minres } else { Method::Gmres } }
147 }
148 }
149}
150
151impl std::str::FromStr for Method {
152 type Err = crate::error::Error;
153 fn from_str(name: &str) -> Result<Method, Self::Err> {
154 let found = Method::NAMES.iter().find(|(key, _)| key.eq_ignore_ascii_case(name));
155 let unknown =
156 || crate::error::Error::new(crate::error::Kind::Domain, format!("unknown method: use one of {}", Method::NAMES.map(|(key, _)| key).join(", ")));
157 found.map(|&(_, method)| method).ok_or_else(unknown)
158 }
159}
160
161impl std::fmt::Display for Method {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 f.write_str(Method::NAMES.iter().find(|&&(_, method)| method == *self).expect("every method has a name").0)
164 }
165}
166
167#[derive(Clone, Copy, Debug, PartialEq, Eq)]
169pub enum Task {
170 Minimize { gradient: bool },
172 Solve { residuals: usize },
174 Linear { equations: usize, adjoint: bool },
176}
177
178impl Task {
179 pub fn least_squares(&self, variables: usize) -> bool { matches!(*self, Task::Linear { equations, adjoint } if equations != variables || adjoint) }
181}
182
183#[derive(Clone, Copy, Debug)]
185pub struct Bounds<'a, F> { pub lower: &'a [F], pub upper: &'a [F] }
186
187impl<F: Native> Bounds<'_, F> {
188 fn clamp(&self, x: &mut [F]) { for ((x, &l), &u) in x.iter_mut().zip(self.lower).zip(self.upper) { *x = x.max(l).min(u) } }
190
191 fn along(&self, x: &[F], d: &[F]) -> (F, F) {
193 let mut range = (F::neg_infinity(), F::infinity());
194 for i in (0..x.len()).filter(|&i| d[i] != F::zero()) {
195 let (p, q) = ((self.lower[i] - x[i]) / d[i], (self.upper[i] - x[i]) / d[i]);
196 range = (range.0.max(p.min(q)), range.1.min(p.max(q)));
197 }
198 range
199 }
200}
201
202#[derive(Clone, Copy, Debug)]
204pub struct Options<'a, F> {
205 pub method: Option<Method>,
207 pub bounds: Option<Bounds<'a, F>>,
209 pub tolerance: Option<F>,
211 pub evaluations: Option<usize>,
213 pub population: Option<usize>,
215 pub seed: u64,
217}
218
219impl<F> Default for Options<'_, F> {
220 fn default() -> Self { Options { method: None, bounds: None, tolerance: None, evaluations: None, population: None, seed: 0 } }
221}
222
223impl<F: Native> Options<'_, F> {
224 pub fn method_for(&self, task: Task, variables: usize) -> Method { self.method.unwrap_or_else(|| Method::choose(task, variables, self.bounds.is_some())) }
226
227 pub fn check(&self, task: Task, variables: usize) -> Result<(), crate::error::Error> {
229 self.problem(task, variables).map_err(|reason| crate::error::Error::new(crate::error::Kind::Domain, reason))
230 }
231
232 fn problem(&self, task: Task, variables: usize) -> Result<(), &'static str> {
233 use Method::*;
234 let bounds = self.bounds;
235 if bounds.is_some_and(|b| b.lower.len() != variables || b.upper.len() != variables) {
236 return Err("bounds need a lower and an upper limit for each variable");
237 }
238 if bounds.is_some_and(|b| b.lower.iter().zip(b.upper).any(|(l, u)| !(l <= u))) { return Err("each lower limit must be at most its upper limit"); }
239 if self.tolerance.is_some_and(|t| !(t > F::zero() && t.is_finite())) { return Err("the tolerance must be a positive number"); }
240 let method = self.method_for(task, variables);
241 match task {
242 Task::Minimize { gradient } => match method {
243 Brent if variables > 1 => Err("Brent's method takes one variable"), Lbfgs if !gradient => Err("L-BFGS needs an objective with a gradient"),
244 Lbfgs if bounds.is_some() => Err("L-BFGS takes no bounds"),
245 Evolution if !bounds.is_some_and(|b| b.lower.iter().chain(b.upper).all(|v| v.is_finite())) => Err("differential evolution needs finite bounds"),
246 Evolution if self.population.is_some_and(|p| p < 4) => Err("differential evolution needs a population of at least 4"),
247 Brent | NelderMead | Powell | Lbfgs | Evolution => Ok(()), _ => Err("that method solves equations, and doesn't minimize")
248 },
249 Task::Solve { residuals } => match method {
250 Brent if variables != 1 || residuals != 1 => Err("Brent's method solves one equation in one variable"),
251 LevenbergMarquardt if bounds.is_some() => Err("Levenberg–Marquardt takes no bounds"), Brent | LevenbergMarquardt => Ok(()),
252 _ => Err("that method doesn't solve nonlinear equations")
253 },
254 Task::Linear { equations, adjoint } => match method {
255 Cg | Minres | Gmres if bounds.is_some() => Err("linear solving takes no bounds"),
256 Cg | Minres | Gmres if equations != variables && !adjoint => Err("least squares needs products with the transpose"),
257 Cg | Minres | Gmres => Ok(()), _ => Err("that method doesn't solve linear equations")
258 },
259 }
260 }
261
262 fn settings(&self, task: Task, variables: usize) -> (Method, F) {
264 if let Err(problem) = self.check(task, variables) { panic!("{problem}") }
265 (self.method_for(task, variables), self.tolerance.unwrap_or_else(|| F::epsilon().sqrt()))
266 }
267}
268
269#[derive(Clone, Debug, PartialEq)]
271pub struct Found<X, F> {
272 pub x: X,
274 pub value: F,
276 pub evaluations: usize,
278 pub converged: bool,
280}
281
282pub fn minimize<F: Native, O: Objective<F>>(objective: &mut O, start: &[F], options: &Options<'_, F>) -> Result<Found<Vec<F>, F>, O::Error> {
288 let (n, task) = (start.len(), Task::Minimize { gradient: objective.has_gradient() });
289 let (method, tolerance) = options.settings(task, n);
290 let population = options.population.unwrap_or((15 * n).max(5));
291 let limit = options.evaluations.unwrap_or(1000 * (n + 1) + if method == Method::Evolution { 1000 * population } else { 0 });
292 let mut search = Search::new(objective, start, options.bounds, limit);
293 let outcome = match method {
294 _ if n == 0 => search.value(&mut []).map(|_| true), Method::Brent => brent_method(&mut search, tolerance),
295 Method::NelderMead => nelder_mead(&mut search, tolerance), Method::Powell => powell(&mut search, tolerance),
296 Method::Lbfgs => lbfgs(&mut search, tolerance), Method::Evolution => evolution(&mut search, population, tolerance, options.seed),
297 _ => unreachable!("`check` accepts only methods that minimize")
298 };
299 passed(outcome).map(|converged| search.found(converged))
300}
301
302pub fn solve<F: Native + Factor, M: Mapping<F>>(mapping: &mut M, start: &[F], first: &[F], options: &Options<'_, F>) -> Result<Found<Vec<F>, F>, M::Error> {
308 let (n, task) = (start.len(), Task::Solve { residuals: first.len() });
309 let (method, tolerance) = options.settings(task, n);
310 let mut residual = Norm { mapping, r: first.to_vec() };
311 let mut search = Search::new(&mut residual, start, options.bounds, options.evaluations.unwrap_or(1000 * (n + 1)));
312 search.seed(start, norm(first));
313 let outcome = match method {
314 _ if n == 0 => Ok(true), Method::Brent => root(&mut search, (start[0], first[0]), tolerance), _ => levenberg_marquardt(&mut search, tolerance)
315 };
316 passed(outcome).map(|converged| search.found(converged))
317}
318
319pub fn solve_linear<F: Native, M: Mapping<F>>(a: &mut M, b: &[F], start: &[F], options: &Options<'_, F>) -> Result<Found<Vec<F>, F>, M::Error> {
325 let (m, n) = (b.len(), start.len());
326 let task = Task::Linear { equations: m, adjoint: a.has_vjp() };
327 let (method, tolerance) = options.settings(task, n);
328 let limit = options.evaluations.unwrap_or(20 * (n + 1));
329 let mut op = Products { a, at: start, normal: task.least_squares(n), inner: vec![F::zero(); m], products: 0, limit };
330 let mut x = start.to_vec();
331 let outcome = op.rhs(b).and_then(|rhs| {
332 if norm(&rhs) == F::zero() { x.fill(F::zero()); return Ok(true); }
333 match method {
334 Method::Cg => cg(&mut op, &rhs, &mut x, tolerance), Method::Minres => minres(&mut op, &rhs, &mut x, tolerance),
335 _ => gmres(&mut op, &rhs, &mut x, tolerance)
336 }
337 });
338 let converged = passed(outcome)?;
339 op.a.value(&x, &mut op.inner)?;
340 for (r, &v) in op.inner.iter_mut().zip(b) { *r = v - *r }
341 Ok(Found { value: norm(&op.inner), x, evaluations: op.products + 1, converged })
342}
343
344pub fn solve_affine<F: Native, M: Mapping<F>>(f: &mut M, start: &[F], first: &[F], options: &Options<'_, F>) -> Result<Found<Vec<F>, F>, M::Error> {
350 let f0 = if start.iter().all(|&x| x == F::zero()) { first.to_vec() } else {
351 let mut f0 = vec![F::zero(); first.len()];
352 f.value(&vec![F::zero(); start.len()], &mut f0)?;
353 f0
354 };
355 let b: Vec<F> = f0.iter().map(|&v| -v).collect();
356 let mut a = Affine { f, size: norm(&b), f0, ratio: None, scaled: Vec::with_capacity(start.len()) };
357 solve_linear(&mut a, &b, start, options)
358}
359
360enum Halt<E> { Error(E), Spent }
362
363fn passed<E>(outcome: Result<bool, Halt<E>>) -> Result<bool, E> {
365 match outcome { Ok(converged) => Ok(converged), Err(Halt::Spent) => Ok(false), Err(Halt::Error(e)) => Err(e) }
366}
367
368struct Search<'a, F, O> { objective: &'a mut O, bounds: Option<Bounds<'a, F>>, limit: usize, evaluations: usize, best: Vec<F>, least: F }
370
371impl<'a, F: Native, O: Objective<F>> Search<'a, F, O> {
372 fn new(objective: &'a mut O, start: &[F], bounds: Option<Bounds<'a, F>>, limit: usize) -> Self {
373 let mut best = start.to_vec();
374 if let Some(b) = bounds { b.clamp(&mut best) }
375 Search { objective, bounds, limit, evaluations: 0, best, least: F::infinity() }
376 }
377
378 fn prepare(&mut self, xs: &mut [F], k: usize) -> Result<(), Halt<O::Error>> {
380 if self.evaluations + k > self.limit { return Err(Halt::Spent); }
381 self.evaluations += k;
382 if let Some(b) = self.bounds { for x in xs.chunks_exact_mut(self.best.len()) { b.clamp(x) } }
383 Ok(())
384 }
385
386 fn record(&mut self, y: F, x: &[F]) -> F {
388 let y = if y.is_nan() { F::infinity() } else { y };
389 if y < self.least {
390 self.least = y;
391 self.best.copy_from_slice(x);
392 }
393 y
394 }
395
396 fn seed(&mut self, start: &[F], y: F) { self.evaluations += 1; if start == self.best { self.record(y, start); } }
398
399 fn value(&mut self, x: &mut [F]) -> Result<F, Halt<O::Error>> {
401 self.prepare(x, 1)?;
402 let y = self.objective.value(x).map_err(Halt::Error)?;
403 Ok(self.record(y, x))
404 }
405
406 fn values(&mut self, xs: &mut [F], out: &mut [F]) -> Result<(), Halt<O::Error>> {
408 self.prepare(xs, out.len())?;
409 let n = self.best.len();
410 if self.objective.batch() { self.objective.values(xs, out).map_err(Halt::Error)? } else {
411 for (y, x) in out.iter_mut().zip(xs.chunks_exact(n)) { *y = self.objective.value(x).map_err(Halt::Error)? }
412 }
413 for (y, x) in out.iter_mut().zip(xs.chunks_exact(n)) { *y = self.record(*y, x) }
414 Ok(())
415 }
416
417 fn gradient(&mut self, x: &[F], g: &mut [F]) -> Result<(), Halt<O::Error>> { self.objective.gradient(x, g).map_err(Halt::Error) }
418
419 fn found(self, converged: bool) -> Found<Vec<F>, F> { Found { x: self.best, value: self.least, evaluations: self.evaluations, converged } }
420}
421
422fn largest<F: Native>(x: &[F]) -> F { x.iter().fold(F::zero(), |m, v| m.max(v.abs())) }
424
425fn first_step<F: Native>(x: F) -> F { F::narrow(0.1) * x.abs().max(F::one()) }
427
428fn line<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, x: &mut [F], d: &[F], fx: F, tolerance: F, trial: &mut [F]) -> Result<F, Halt<O::Error>> {
430 let (lo, hi) = search.bounds.map_or((F::neg_infinity(), F::infinity()), |b| b.along(x, d));
431 let floor = tolerance * (largest(x) + tolerance) / largest(d);
432 let (t, ft) = {
433 let mut phi = |t: F| {
434 trial.copy_from_slice(x);
435 axpy(trial, t, d);
436 search.value(trial)
437 };
438 least_along(&mut phi, fx, lo, hi, tolerance, floor)?
439 };
440 axpy(x, t, d);
441 Ok(ft)
442}
443
444fn least_along<F: Native, H>(phi: &mut impl FnMut(F) -> Result<F, H>, f0: F, lo: F, hi: F, tolerance: F, floor: F) -> Result<(F, F), H> {
446 let within = |t: F| t.max(lo).min(hi);
447 let mut a = F::zero();
448 let mut b = within(F::one());
449 if b == a { b = within(-F::one()) }
450 if b == a { return Ok((a, f0)); }
451 let mut fb = phi(b)?;
452 if fb > f0 { (a, b, fb) = (b, a, f0) }
453 loop {
454 let c = within(b + F::narrow(1.618_033_988_749_895) * (b - a));
455 if c == b || !c.is_finite() { return Ok((b, fb)); }
456 let fc = phi(c)?;
457 if fc >= fb { return brent(phi, a.min(c), a.max(c), b, fb, tolerance, floor); }
458 (a, b, fb) = (b, c, fc);
459 }
460}
461
462#[allow(clippy::too_many_arguments)]
464fn brent<F: Native, H>(phi: &mut impl FnMut(F) -> Result<F, H>, mut a: F, mut b: F, mut x: F, mut fx: F, tolerance: F, floor: F) -> Result<(F, F), H> {
465 let (half, two, golden) = (F::narrow(0.5), F::narrow(2.0), F::narrow(0.381_966_011_250_105_1));
466 let (mut v, mut w, mut fv, mut fw) = (x, x, fx, fx);
467 let (mut d, mut e) = (F::zero(), F::zero());
468 loop {
469 let m = half * (a + b);
470 let tol1 = tolerance * x.abs() + floor;
471 let tol2 = two * tol1;
472 if (x - m).abs() <= tol2 - half * (b - a) { return Ok((x, fx)); }
473 let mut parabolic = false;
474 if e.abs() > tol1 {
475 let r = (x - w) * (fx - fv);
476 let q = (x - v) * (fx - fw);
477 let mut p = (x - v) * q - (x - w) * r;
478 let mut q = two * (q - r);
479 if q > F::zero() { p = -p }
480 else { q = -q }
481 if p.abs() < (half * q * e).abs() && p > q * (a - x) && p < q * (b - x) {
482 e = d;
483 d = p / q;
484 if x + d - a < tol2 || b - (x + d) < tol2 { d = tol1.copysign(m - x) }
485 parabolic = true;
486 }
487 }
488 if !parabolic {
489 e = if x >= m { a - x } else { b - x };
490 d = golden * e;
491 }
492 let u = if d.abs() >= tol1 { x + d } else { x + tol1.copysign(d) };
493 let fu = phi(u)?;
494 if fu <= fx {
495 if u >= x { a = x }
496 else { b = x }
497 (v, fv, w, fw, x, fx) = (w, fw, x, fx, u, fu);
498 } else {
499 if u < x { a = u }
500 else { b = u }
501 if fu <= fw || w == x { (v, fv, w, fw) = (w, fw, u, fu) } else if fu <= fv || v == x || v == w { (v, fv) = (u, fu) }
502 }
503 }
504}
505
506fn brent_method<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, tolerance: F) -> Result<bool, Halt<O::Error>> {
508 let mut x = search.best.clone();
509 let fx = search.value(&mut x)?;
510 let d = [first_step(x[0])];
511 line(search, &mut x, &d, fx, tolerance, &mut [F::zero()])?;
512 Ok(true)
513}
514
515fn nelder_mead<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, tolerance: F) -> Result<bool, Halt<O::Error>> {
517 let mut x = search.best.clone();
518 simplex(search, &x, tolerance)?;
519 loop {
520 let before = search.least;
521 x.copy_from_slice(&search.best);
522 simplex(search, &x, tolerance)?;
523 if before - search.least <= tolerance * (before.abs() + tolerance) { return Ok(true); }
524 }
525}
526
527fn simplex<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, x: &[F], tolerance: F) -> Result<(), Halt<O::Error>> {
529 let n = x.len();
530 let (one, k) = (F::one(), F::narrow(n.max(2) as f64));
531 let (expand, contract, shrink) = (one + F::narrow(2.0) / k, F::narrow(0.75) - one / (F::narrow(2.0) * k), one - one / k);
532 let mut points = Vec::with_capacity((n + 1) * n);
533 for i in 0..=n {
534 points.extend_from_slice(x);
535 if i > 0 {
536 let (j, s) = (i - 1, first_step(x[i - 1]));
537 let down = search.bounds.is_some_and(|b| x[j] + s > b.upper[j] && b.upper[j] - x[j] < x[j] - b.lower[j]);
538 points[i * n + j] = if down { x[j] - s } else { x[j] + s };
539 }
540 }
541 let mut values = vec![F::zero(); n + 1];
542 search.values(&mut points, &mut values)?;
543 let (mut centroid, mut trial, mut other) = (vec![F::zero(); n], vec![F::zero(); n], vec![F::zero(); n]);
544 loop {
545 let (b, s, w) = ranks(&values);
546 let best = &points[b * n..][..n];
547 let spread = (0..=n).map(|i| (0..n).fold(F::zero(), |m, j| m.max((points[i * n + j] - best[j]).abs()))).fold(F::zero(), F::max);
548 if values[w] - values[b] <= tolerance * (values[b].abs() + tolerance) && spread <= tolerance * (largest(best) + tolerance) { return Ok(()); }
549 centroid.fill(F::zero());
550 for i in (0..=n).filter(|&i| i != w) { axpy(&mut centroid, one / F::narrow(n as f64), &points[i * n..][..n]) }
551 let worst = w * n..(w + 1) * n;
552 let mut moved = |out: &mut [F], t: F| {
553 for j in 0..n { out[j] = centroid[j] + t * (points[w * n + j] - centroid[j]) }
554 search.value(out)
555 };
556 let fr = moved(&mut trial, -one)?;
557 let (point, value) = if fr < values[b] {
558 let fe = moved(&mut other, -expand)?;
559 if fe < fr { (&other, fe) } else { (&trial, fr) }
560 } else if fr < values[s] { (&trial, fr) } else {
561 let fc = moved(&mut other, if fr < values[w] { -contract } else { contract })?;
562 if fc >= fr.min(values[w]) {
563 swap_rows(&mut points, b, 0, n);
564 values.swap(b, 0);
565 let (first, rest) = points.split_at_mut(n);
566 for row in rest.chunks_exact_mut(n) { for j in 0..n { row[j] = first[j] + shrink * (row[j] - first[j]) } }
567 search.values(&mut points[n..], &mut values[1..])?;
568 continue;
569 }
570 (&other, fc)
571 };
572 points[worst].copy_from_slice(point);
573 values[w] = value;
574 }
575}
576
577fn ranks<F: Native>(values: &[F]) -> (usize, usize, usize) {
579 let (mut b, mut w) = (0, 0);
580 for (i, &v) in values.iter().enumerate() { if v < values[b] { b = i } if v > values[w] { w = i } }
581 if b == w { w = (b + 1) % values.len() }
582 let s = (0..values.len()).filter(|&i| i != w).fold(b, |s, i| if values[i] > values[s] { i } else { s });
583 (b, s, w)
584}
585
586fn swap_rows<F>(x: &mut [F], i: usize, j: usize, n: usize) { if i != j { for k in 0..n { x.swap(i * n + k, j * n + k) } } }
588
589fn powell<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, tolerance: F) -> Result<bool, Halt<O::Error>> {
591 let n = search.best.len();
592 let two = F::narrow(2.0);
593 let mut x = search.best.clone();
594 let mut fx = search.value(&mut x)?;
595 let coordinates = |directions: &mut [F], x: &[F]| {
596 directions.fill(F::zero());
597 for i in 0..n { directions[i * n + i] = first_step(x[i]) }
598 };
599 let mut directions = vec![F::zero(); n * n];
600 coordinates(&mut directions, &x);
601 let mut coordinate = true;
602 let (mut start, mut step, mut trial) = (x.clone(), vec![F::zero(); n], vec![F::zero(); n]);
603 loop {
604 start.copy_from_slice(&x);
605 let f0 = fx;
606 let (mut largest_drop, mut drop) = (0, F::zero());
607 for i in 0..n {
608 let before = fx;
609 fx = line(search, &mut x, &directions[i * n..][..n], fx, tolerance, &mut trial)?;
610 if before - fx > drop { (largest_drop, drop) = (i, before - fx) }
611 }
612 if two * (f0 - fx) <= tolerance * (f0.abs() + fx.abs() + tolerance) {
613 if coordinate { return Ok(true); }
614 coordinates(&mut directions, &x);
615 coordinate = true;
616 continue;
617 }
618 for j in 0..n { (step[j], trial[j]) = (x[j] - start[j], two * x[j] - start[j]) }
619 let fe = search.value(&mut trial)?;
620 let square = |v: F| v * v;
621 if fe < f0 && two * (f0 - two * fx + fe) * square(f0 - fx - drop) < drop * square(f0 - fe) {
622 fx = line(search, &mut x, &step, fx, tolerance, &mut trial)?;
623 directions.copy_within((largest_drop + 1) * n.., largest_drop * n);
624 directions[(n - 1) * n..].copy_from_slice(&step);
625 coordinate = false;
626 }
627 }
628}
629
630fn lbfgs<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, tolerance: F) -> Result<bool, Halt<O::Error>> {
632 const MEMORY: usize = 10;
633 let n = search.best.len();
634 let mut x = search.best.clone();
635 let mut fx = search.value(&mut x)?;
636 let mut g = vec![F::zero(); n];
637 search.gradient(&x, &mut g)?;
638 let mut history: VecDeque<(Vec<F>, Vec<F>, F)> = VecDeque::with_capacity(MEMORY);
639 let (mut d, mut xn, mut gn, mut weights) = (vec![F::zero(); n], vec![F::zero(); n], vec![F::zero(); n], [F::zero(); MEMORY]);
640 loop {
641 if largest(&g) == F::zero() { return Ok(true); }
642 d.copy_from_slice(&g);
643 for (k, (s, y, rho)) in history.iter().enumerate().rev() {
644 weights[k] = *rho * dot(s, &d);
645 axpy(&mut d, -weights[k], y);
646 }
647 let scale = history.back().map_or_else(|| F::one() / largest(&g), |(s, y, _)| dot(s, y) / dot(y, y));
648 d.iter_mut().for_each(|v| *v = -*v * scale);
649 for (k, (s, y, rho)) in history.iter().enumerate() {
650 let b = *rho * dot(y, &d);
651 axpy(&mut d, -weights[k] - b, s);
652 }
653 let mut slope = dot(&g, &d);
654 if slope >= F::zero() {
655 history.clear();
656 let scale = F::one() / largest(&g);
657 for j in 0..n { d[j] = -g[j] * scale }
658 slope = dot(&g, &d);
659 }
660 let Some(fnew) = wolfe(search, &x, fx, &d, slope, &mut xn, &mut gn)? else {
661 if history.is_empty() { return Ok(true); }
662 history.clear();
663 continue;
664 };
665 let (mut s, mut y, _) = if history.len() == MEMORY { history.pop_front().unwrap() } else { (vec![F::zero(); n], vec![F::zero(); n], F::zero()) };
666 for j in 0..n { (s[j], y[j]) = (xn[j] - x[j], gn[j] - g[j]) }
667 let sy = dot(&s, &y);
668 if sy > F::epsilon() * dot(&y, &y) { history.push_back((s, y, F::one() / sy)) }
669 let decrease = fx - fnew;
670 (x, xn, g, gn, fx) = (xn, x, gn, g, fnew);
671 if decrease <= tolerance * (fx.abs() + tolerance) { return Ok(true); }
672 }
673}
674
675#[allow(clippy::too_many_arguments)]
677fn wolfe<F: Native, O: Objective<F>>(
678 search: &mut Search<'_, F, O>, x: &[F], fx: F, d: &[F], slope: F, xn: &mut [F], gn: &mut [F]) -> Result<Option<F>, Halt<O::Error>> {
679 const STEPS: usize = 30;
680 let (c1, c2, half, tenth) = (F::narrow(1e-4), F::narrow(0.9), F::narrow(0.5), F::narrow(0.1));
681 let probe = |search: &mut Search<'_, F, O>, alpha: F, xn: &mut [F]| {
682 xn.copy_from_slice(x);
683 axpy(xn, alpha, d);
684 search.value(xn)
685 };
686 let sufficient = |alpha: F, value: F| value <= fx + c1 * alpha * slope;
687 let (mut lo, mut flo, mut slo) = (F::zero(), fx, slope);
688 let mut bracket = None;
689 let mut alpha = F::one();
690 for i in 0..STEPS {
691 let fa = probe(search, alpha, xn)?;
692 if !sufficient(alpha, fa) || (i > 0 && fa >= flo) { bracket = Some((alpha, fa)); break; }
693 search.gradient(xn, gn)?;
694 let sa = dot(gn, d);
695 if sa.abs() <= -c2 * slope { return Ok(Some(fa)); }
696 if sa >= F::zero() {
697 bracket = Some((lo, flo));
698 (lo, flo, slo) = (alpha, fa, sa);
699 break;
700 }
701 (lo, flo, slo) = (alpha, fa, sa);
702 alpha = alpha + alpha;
703 }
704 if let Some((mut hi, mut fhi)) = bracket {
705 for _ in 0..STEPS {
706 let width = hi - lo;
707 if width.abs() <= F::epsilon() * lo.abs() { break; }
708 let curve = fhi - flo - slo * width;
709 let guess = if curve > F::zero() { lo - slo * width * width / (curve + curve) } else { lo + half * width };
710 let (p, q) = (lo + tenth * width, hi - tenth * width);
711 let alpha = guess.max(p.min(q)).min(p.max(q));
712 let fa = probe(search, alpha, xn)?;
713 if !sufficient(alpha, fa) || fa >= flo { (hi, fhi) = (alpha, fa); continue; }
714 search.gradient(xn, gn)?;
715 let sa = dot(gn, d);
716 if sa.abs() <= -c2 * slope { return Ok(Some(fa)); }
717 if sa * width >= F::zero() { (hi, fhi) = (lo, flo) }
718 (lo, flo, slo) = (alpha, fa, sa);
719 }
720 }
721 if lo == F::zero() { return Ok(None); }
722 let flo = probe(search, lo, xn)?;
723 search.gradient(xn, gn)?;
724 Ok(Some(flo))
725}
726
727fn evolution<F: Native, O: Objective<F>>(search: &mut Search<'_, F, O>, population: usize, tolerance: F, seed: u64) -> Result<bool, Halt<O::Error>> {
729 const SETTLED: f64 = 0.01;
730 let Some(Bounds { lower, upper }) = search.bounds else { unreachable!() };
731 let n = search.best.len();
732 let mut rng = Key::seeded(seed).stream(0).at(0);
733 let mut uniform = move || F::narrow(unit(rng.next_u64()));
734 let mut members = Vec::with_capacity(population * n);
735 members.extend_from_slice(&search.best);
736 for _ in 1..population { for j in 0..n { members.push(lower[j] + (upper[j] - lower[j]) * uniform()) } }
737 let mut values = vec![F::zero(); population];
738 search.values(&mut members, &mut values)?;
739 let (mut trials, mut tried) = (members.clone(), values.clone());
740 let (half, settled) = (F::narrow(0.5), F::narrow(SETTLED));
741 let pick = |u: F, below: usize| ((u * F::narrow(below as f64)).to_usize().unwrap_or(0)).min(below - 1);
742 loop {
743 let (least, most) = values.iter().fold((F::infinity(), F::neg_infinity()), |(l, m), &v| (l.min(v), m.max(v)));
744 let gathered = (0..n).all(|j| {
745 let (l, m) = (0..population).fold((F::infinity(), F::neg_infinity()), |(l, m), i| (l.min(members[i * n + j]), m.max(members[i * n + j])));
746 m - l <= settled * (upper[j] - lower[j])
747 });
748 if most - least <= settled * least.abs() || gathered { break; }
749 let factor = half + half * uniform();
750 for i in 0..population {
751 let mut chosen = [i; 4];
752 for c in 1..4 { chosen[c] = loop { let r = pick(uniform(), population); if !chosen[..c].contains(&r) { break r; } }; }
753 let [_, p, q, r] = chosen;
754 let crossed = pick(uniform(), n);
755 for j in 0..n {
756 let parent = members[i * n + j];
757 trials[i * n + j] = if j == crossed || uniform() < F::narrow(0.7) {
758 let v = members[p * n + j] + factor * (members[q * n + j] - members[r * n + j]);
759 if v < lower[j] { half * (parent + lower[j]) } else if v > upper[j] { half * (parent + upper[j]) } else { v }
760 } else { parent };
761 }
762 }
763 search.values(&mut trials, &mut tried)?;
764 for i in 0..population {
765 if tried[i] <= values[i] {
766 values[i] = tried[i];
767 members[i * n..][..n].copy_from_slice(&trials[i * n..][..n]);
768 }
769 }
770 }
771 powell(search, tolerance)
772}
773
774struct Norm<'m, F, M> { mapping: &'m mut M, r: Vec<F> }
776
777impl<F: Native, M: Mapping<F>> Objective<F> for Norm<'_, F, M> {
778 type Error = M::Error;
779 fn value(&mut self, x: &[F]) -> Result<F, M::Error> { self.mapping.value(x, &mut self.r)?; Ok(norm(&self.r)) }
780}
781
782fn norm<F: Native>(x: &[F]) -> F { dot(x, x).sqrt() }
784
785fn at<F: Native, M: Mapping<F>>(search: &mut Search<'_, F, Norm<'_, F, M>>, x: F) -> Result<(F, F), Halt<M::Error>> {
787 let mut p = [x];
788 search.value(&mut p)?;
789 Ok((p[0], search.objective.r[0]))
790}
791
792fn root<F: Native, M: Mapping<F>>(search: &mut Search<'_, F, Norm<'_, F, M>>, start: (F, F), tolerance: F) -> Result<bool, Halt<M::Error>> {
794 let (half, two, three, grow) = (F::narrow(0.5), F::narrow(2.0), F::narrow(3.0), F::narrow(1.6));
795 let differ = |fa: F, fb: F| (fa > F::zero()) != (fb > F::zero());
796 let ends = search.bounds.map(|b| (b.lower[0], b.upper[0])).filter(|(l, u)| l.is_finite() && u.is_finite());
797 let ((mut a, mut fa), (mut b, mut fb)) = match ends {
799 Some((l, u)) => (if l == start.0 { start } else { at(search, l)? }, if u == start.0 { start } else { at(search, u)? }),
800 None => { let from = if search.best[0] == start.0 { start } else { at(search, search.best[0])? }; (from, from) }
801 };
802 let (mut low, mut high) = (ends.is_none(), ends.is_none());
804 while fa != F::zero() && fb != F::zero() && !differ(fa, fb) {
805 if !low && !high { return Ok(false); }
806 let down = low && (!high || fa.abs() < fb.abs());
807 let width = if b > a { b - a } else { first_step(a) };
808 let end = if down { a } else { b };
809 let mut target = if down { a - grow * width } else { b + grow * width };
810 let (x, fx) = loop {
811 let (x, fx) = at(search, target)?;
812 let inward = end + half * (target - end);
813 if (!fx.is_nan() && x.is_finite()) || inward == end || inward == target { break (x, fx); }
814 target = inward;
815 };
816 let undefined = fx.is_nan() || !x.is_finite();
817 if !undefined { if down { (a, fa) = (x, fx) } else { (b, fb) = (x, fx) } }
818 if undefined || x != target { if down { low = false } else { high = false } }
819 }
820 if fa == F::zero() || fb == F::zero() { return Ok(true); }
821 if fa.abs() < fb.abs() { (a, b, fa, fb) = (b, a, fb, fa) }
822 let (mut c, mut fc) = (a, fa);
823 let (mut d, mut e) = (b - a, b - a);
824 loop {
825 if !differ(fb, fc) { (c, fc, d, e) = (a, fa, b - a, b - a) }
826 if fc.abs() < fb.abs() { (a, b, c, fa, fb, fc) = (b, c, b, fb, fc, fb) }
827 let tol1 = half * tolerance * (b.abs() + tolerance);
828 let m = half * (c - b);
829 if m.abs() <= tol1 || fb == F::zero() { return Ok(true); }
830 if e.abs() >= tol1 && fa.abs() > fb.abs() {
831 let s = fb / fa;
832 let (mut p, mut q) = if a == c { (two * m * s, F::one() - s) } else {
833 let (q, r) = (fa / fc, fb / fc);
834 (s * (two * m * q * (q - r) - (b - a) * (r - F::one())), (q - F::one()) * (r - F::one()) * (s - F::one()))
835 };
836 if p > F::zero() { q = -q }
837 else { p = -p }
838 if two * p < (three * m * q - (tol1 * q).abs()).min((e * q).abs()) { (e, d) = (d, p / q) } else { (d, e) = (m, m) }
839 } else { (d, e) = (m, m); }
840 (a, fa) = (b, fb);
841 b = b + if d.abs() > tol1 { d } else { tol1.copysign(m) };
842 fb = at(search, b)?.1;
843 }
844}
845
846fn levenberg_marquardt<F: Native + Factor, M: Mapping<F>>(search: &mut Search<'_, F, Norm<'_, F, M>>, tolerance: F) -> Result<bool, Halt<M::Error>> {
848 let (n, m) = (search.best.len(), search.objective.r.len());
849 let (one, two) = (F::one(), F::narrow(2.0));
850 let mut x = search.best.clone();
851 let mut fx = search.least;
852 let mut r = search.objective.r.clone();
853 let (mut j, mut damped, mut target) = (vec![F::zero(); m * n], vec![F::zero(); (m + n) * n], vec![F::zero(); m + n]);
855 let (mut scale, mut trial, mut fit) = (vec![F::zero(); n], vec![F::zero(); n], vec![F::zero(); m]);
856 let (mut damping, mut growth) = (F::narrow(1e-3), two);
858 loop {
859 if fx == F::zero() { return Ok(true); }
860 jacobian(search, &x, &r, &mut j)?;
861 let mut cosine = F::zero();
862 for c in 0..n {
863 let (mut length, mut product) = (F::zero(), F::zero());
864 for i in 0..m { (length, product) = (length + j[i * n + c] * j[i * n + c], product + j[i * n + c] * r[i]) }
865 let length = length.sqrt();
866 if !(length.is_finite() && product.is_finite()) { return Ok(false); }
868 if length > F::zero() { cosine = cosine.max(product.abs() / (length * fx)) }
869 scale[c] = scale[c].max(length);
870 }
871 if cosine <= tolerance { return Ok(true); }
872 loop {
873 damped[..m * n].copy_from_slice(&j);
874 damped[m * n..].fill(F::zero());
875 for c in 0..n { damped[(m + c) * n + c] = damping.sqrt() * scale[c] }
876 for i in 0..m { target[i] = -r[i] }
877 target[m..].fill(F::zero());
878 let (step, _) = lstsq(&damped, &target, [m + n, n], 1);
879 for c in 0..n { trial[c] = x[c] + step[c] }
880 let ft = search.value(&mut trial)?;
881 let small = norm(&step) <= tolerance * (norm(&x) + tolerance);
882 if ft < fx {
883 for i in 0..m { fit[i] = r[i] + dot(&j[i * n..][..n], &step) }
884 let predicted = fx * fx - dot(&fit, &fit);
885 let ratio = if predicted > F::zero() { (fx * fx - ft * ft) / predicted } else { one };
886 let swing = two * ratio - one;
887 damping = damping * F::narrow(1.0 / 3.0).max(one - swing * swing * swing);
888 growth = two;
889 x.copy_from_slice(&trial);
890 r.copy_from_slice(&search.objective.r);
891 fx = ft;
892 if small { return Ok(true); }
893 break;
894 }
895 if small { return Ok(true); }
896 damping = damping * growth;
897 growth = growth * two;
898 }
899 }
900}
901
902fn jacobian<F: Native, M: Mapping<F>>(search: &mut Search<'_, F, Norm<'_, F, M>>, x: &[F], r: &[F], j: &mut [F]) -> Result<(), Halt<M::Error>> {
904 if search.objective.mapping.jacobian(x, j).map_err(Halt::Error)? { return Ok(()); }
905 let n = x.len();
906 let mut shifted = x.to_vec();
907 for c in 0..n {
908 shifted[c] = x[c] + F::epsilon().sqrt() * x[c].abs().max(F::one());
909 let h = shifted[c] - x[c];
910 search.value(&mut shifted)?;
911 for (i, (&after, &before)) in search.objective.r.iter().zip(r).enumerate() { j[i * n + c] = (after - before) / h }
912 shifted[c] = x[c];
913 }
914 Ok(())
915}
916
917struct Affine<'m, F, M> {
919 f: &'m mut M,
920 f0: Vec<F>,
922 size: F,
924 ratio: Option<F>,
926 scaled: Vec<F>,
928}
929
930impl<F: Native, M: Mapping<F>> Affine<'_, F, M> {
931 fn scale(&self, nv: F, ratio: F) -> F {
933 if self.size == F::zero() { return F::one(); }
934 let t = (F::narrow(16.0) * self.size / (ratio * nv)).log2().round().exp2();
935 if t.is_finite() && t > F::zero() { t } else { F::one() }
936 }
937
938 fn at(&mut self, v: &[F], t: F, out: &mut [F]) -> Result<(), M::Error> {
940 self.scaled.clear();
941 self.scaled.extend(v.iter().map(|&x| x * t));
942 self.f.value(&self.scaled, out)?;
943 for (o, &z) in out.iter_mut().zip(&self.f0) { *o = (*o - z) / t }
944 Ok(())
945 }
946}
947
948impl<F: Native, M: Mapping<F>> Mapping<F> for Affine<'_, F, M> {
949 type Error = M::Error;
950 fn value(&mut self, v: &[F], out: &mut [F]) -> Result<(), M::Error> {
952 let nv = norm(v);
953 if nv == F::zero() { out.fill(F::zero()); return Ok(()); }
954 let t = self.scale(nv, self.ratio.unwrap_or(F::one()));
955 self.at(v, t, out)?;
956 let mut av = norm(out);
957 if av > F::zero() && t * av < self.size {
958 self.at(v, self.scale(nv, av / nv), out)?;
959 av = norm(out);
960 }
961 if av > F::zero() { self.ratio = Some(av / nv) }
962 Ok(())
963 }
964 fn has_vjp(&self) -> bool { self.f.has_vjp() }
965 fn vjp(&mut self, u: &[F], x: &[F], out: &mut [F]) -> Result<(), M::Error> { self.f.vjp(u, x, out) }
966 fn has_preconditioner(&self) -> bool { self.f.has_preconditioner() }
967 fn precondition(&mut self, v: &[F], out: &mut [F]) -> Result<(), M::Error> { self.f.precondition(v, out) }
968}
969
970struct Products<'a, F, M> {
972 a: &'a mut M,
973 at: &'a [F],
975 normal: bool,
976 inner: Vec<F>,
978 products: usize,
979 limit: usize,
980}
981
982impl<F: Native, M: Mapping<F>> Products<'_, F, M> {
983 fn count(&mut self, k: usize) -> Result<(), Halt<M::Error>> {
985 if self.products + k > self.limit { return Err(Halt::Spent); }
986 self.products += k;
987 Ok(())
988 }
989
990 fn apply(&mut self, v: &[F], out: &mut [F]) -> Result<(), Halt<M::Error>> {
992 if !self.normal { self.count(1)?; return self.a.value(v, out).map_err(Halt::Error); }
993 self.count(2)?;
994 self.a.value(v, &mut self.inner).map_err(Halt::Error)?;
995 self.a.vjp(&self.inner, self.at, out).map_err(Halt::Error)
996 }
997
998 fn precondition<'v>(&mut self, v: &'v [F], out: &'v mut [F]) -> Result<&'v [F], Halt<M::Error>> {
1000 if !self.a.has_preconditioner() { return Ok(v); }
1001 self.a.precondition(v, out).map_err(Halt::Error)?;
1002 Ok(out)
1003 }
1004
1005 fn rhs(&mut self, b: &[F]) -> Result<Vec<F>, Halt<M::Error>> {
1007 if !self.normal { return Ok(b.to_vec()); }
1008 self.count(1)?;
1009 let mut v = vec![F::zero(); self.at.len()];
1010 self.a.vjp(b, self.at, &mut v).map_err(Halt::Error)?;
1011 Ok(v)
1012 }
1013
1014 fn residual(&mut self, rhs: &[F], x: &[F], r: &mut [F]) -> Result<(), Halt<M::Error>> {
1016 self.apply(x, r)?;
1017 for (r, &b) in r.iter_mut().zip(rhs) { *r = b - *r }
1018 Ok(())
1019 }
1020}
1021
1022fn cg<F: Native, M: Mapping<F>>(op: &mut Products<'_, F, M>, rhs: &[F], x: &mut [F], tolerance: F) -> Result<bool, Halt<M::Error>> {
1024 let (n, zero, goal) = (x.len(), F::zero(), tolerance * norm(rhs));
1025 let (mut r, mut z, mut q) = (vec![zero; n], vec![zero; n], vec![zero; n]);
1026 op.residual(rhs, x, &mut r)?;
1027 let mut p = op.precondition(&r, &mut z)?.to_vec();
1028 let mut rz = dot(&r, &p);
1029 loop {
1030 let size = norm(&r);
1031 if !(size > goal) { return Ok(size <= goal); }
1032 if !(rz > zero) { return Ok(false); }
1033 op.apply(&p, &mut q)?;
1034 let pq = dot(&p, &q);
1035 if !(pq > zero) { return Ok(false); }
1036 let alpha = rz / pq;
1037 axpy(x, alpha, &p);
1038 axpy(&mut r, -alpha, &q);
1039 let mz = op.precondition(&r, &mut z)?;
1040 let next = dot(&r, mz);
1041 let beta = next / rz;
1042 rz = next;
1043 for i in 0..n { p[i] = mz[i] + beta * p[i] }
1044 }
1045}
1046
1047fn minres<F: Native, M: Mapping<F>>(op: &mut Products<'_, F, M>, rhs: &[F], x: &mut [F], tolerance: F) -> Result<bool, Halt<M::Error>> {
1049 let (n, zero) = (x.len(), F::zero());
1050 let (mut r1, mut y, mut v) = (vec![zero; n], vec![zero; n], vec![zero; n]);
1051 let goal = tolerance * dot(rhs, op.precondition(rhs, &mut v)?).sqrt();
1052 op.residual(rhs, x, &mut r1)?;
1053 let my = op.precondition(&r1, &mut y)?;
1054 let mut beta = dot(&r1, my).sqrt();
1055 if !(beta > goal) { return Ok(beta <= goal); }
1056 for i in 0..n { v[i] = my[i] / beta }
1057 let mut r2 = r1.clone();
1058 let (mut w, mut w1, mut w2) = (vec![zero; n], vec![zero; n], vec![zero; n]);
1059 let (mut oldb, mut dbar, mut epsln, mut phibar, mut cs, mut sn) = (zero, zero, zero, beta, -F::one(), zero);
1060 loop {
1061 op.apply(&v, &mut y)?;
1062 if oldb > zero { axpy(&mut y, -beta / oldb, &r1) }
1063 let alfa = dot(&v, &y);
1064 axpy(&mut y, -alfa / beta, &r2);
1065 std::mem::swap(&mut r1, &mut r2);
1066 r2.copy_from_slice(&y);
1067 let my = op.precondition(&r2, &mut y)?;
1068 (oldb, beta) = (beta, dot(&r2, my).sqrt());
1069 let oldeps = epsln;
1070 let delta = cs * dbar + sn * alfa;
1071 let gbar = sn * dbar - cs * alfa;
1072 (epsln, dbar) = (sn * beta, -cs * beta);
1073 let (c, s, gamma) = givens(gbar, beta);
1074 if gamma == zero { return Ok(false); }
1075 (cs, sn) = (c, s);
1076 let phi = cs * phibar;
1077 phibar = sn * phibar;
1078 std::mem::swap(&mut w1, &mut w2);
1079 std::mem::swap(&mut w2, &mut w);
1080 for i in 0..n { w[i] = (v[i] - oldeps * w1[i] - delta * w2[i]) / gamma }
1081 axpy(x, phi, &w);
1082 if !(phibar > goal) { return Ok(phibar <= goal); }
1083 for i in 0..n { v[i] = my[i] / beta }
1084 }
1085}
1086
1087pub const GMRES_RESTART: usize = 20;
1089
1090fn gmres<F: Native, M: Mapping<F>>(op: &mut Products<'_, F, M>, rhs: &[F], x: &mut [F], tolerance: F) -> Result<bool, Halt<M::Error>> {
1092 let (n, zero, goal) = (x.len(), F::zero(), tolerance * norm(rhs));
1093 let k = GMRES_RESTART.min(n);
1094 let (mut basis, mut h) = (vec![zero; (k + 1) * n], vec![zero; k * k]);
1095 let (mut turns, mut g, mut y) = (vec![(zero, zero); k], vec![zero; k + 1], vec![zero; k]);
1096 let (mut w, mut z) = (vec![zero; n], vec![zero; n]);
1097 loop {
1098 op.residual(rhs, x, &mut basis[..n])?;
1099 let beta = norm(&basis[..n]);
1100 if !(beta > goal) { return Ok(beta <= goal); }
1101 for v in &mut basis[..n] { *v = *v / beta }
1102 g.fill(zero);
1103 g[0] = beta;
1104 let (mut steps, mut ended) = (0, false);
1105 while steps < k && !ended {
1106 let j = steps;
1107 let mv = op.precondition(&basis[j * n..][..n], &mut z)?;
1108 op.apply(mv, &mut w)?;
1109 for i in 0..=j {
1110 let hij = dot(&w, &basis[i * n..][..n]);
1111 h[i * k + j] = hij;
1112 axpy(&mut w, -hij, &basis[i * n..][..n]);
1113 }
1114 let next = norm(&w);
1115 for (i, &(c, s)) in turns[..j].iter().enumerate() {
1116 let (p, q) = (h[i * k + j], h[(i + 1) * k + j]);
1117 (h[i * k + j], h[(i + 1) * k + j]) = (c * p + s * q, c * q - s * p);
1118 }
1119 let (c, s, r) = givens(h[j * k + j], next);
1120 if r == zero { break; }
1121 (turns[j], h[j * k + j]) = ((c, s), r);
1122 (g[j], g[j + 1]) = (c * g[j], -s * g[j]);
1123 steps += 1;
1124 ended = !(g[steps].abs() > goal) || next == zero;
1125 if !ended { for i in 0..n { basis[steps * n + i] = w[i] / next } }
1126 }
1127 for i in (0..steps).rev() {
1128 let t = (i + 1..steps).fold(g[i], |t, l| t - h[i * k + l] * y[l]);
1129 y[i] = t / h[i * k + i];
1130 }
1131 z.fill(zero);
1132 for i in 0..steps { axpy(&mut z, y[i], &basis[i * n..][..n]) }
1133 let step = op.precondition(&z, &mut w)?;
1134 axpy(x, F::one(), step);
1135 if ended || steps < k { return Ok(g[steps].abs() <= goal); }
1136 }
1137}