somatize_study/pruner/
patience.rs1use super::judging::{latest, not_a_number};
4use super::{Pruner, Reason, Verdict};
5use crate::Goal;
6use std::fmt;
7use std::num::NonZeroUsize;
8
9#[derive(Debug, Clone, PartialEq)]
14pub struct Patience {
15 pub steps: NonZeroUsize,
20 pub min_delta: f64,
23 pub goal: Goal,
25}
26
27impl Patience {
28 pub fn verdict(&self, mine: &[f64], _others: &[Vec<f64>]) -> Verdict {
30 let Some((at, value)) = latest(mine) else {
31 return Verdict::Continue;
32 };
33 if let Some(why) = not_a_number(at, value) {
34 return Verdict::Prune(why);
35 }
36
37 let mut best = f64::NAN;
38 let mut since = 0;
39 for (step, &value) in mine.iter().enumerate() {
40 if best.is_nan() || self.goal.better(value, best + self.moved()) {
42 best = value;
43 since = step;
44 }
45 }
46 if at - since >= self.steps.get() {
47 Verdict::Prune(Reason::NotImproving {
48 since,
49 steps: self.steps.get(),
50 })
51 } else {
52 Verdict::Continue
53 }
54 }
55
56 fn moved(&self) -> f64 {
58 match self.goal {
59 Goal::Minimize => -self.min_delta,
60 Goal::Maximize => self.min_delta,
61 }
62 }
63}
64
65impl fmt::Display for Patience {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(
68 f,
69 "patience:{}:delta:{}:{}",
70 self.steps, self.min_delta, self.goal
71 )
72 }
73}
74
75impl From<Patience> for Pruner {
76 fn from(rule: Patience) -> Self {
77 Self::Patience(rule)
78 }
79}