1use std::fmt;
9use std::str::FromStr;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum Goal {
14 Minimize,
16 Maximize,
18}
19
20impl Goal {
21 pub fn better(&self, one: f64, than: f64) -> bool {
24 match self {
25 Self::Minimize => one < than,
26 Self::Maximize => one > than,
27 }
28 }
29
30 pub fn best_of(&self, values: &[f64]) -> Option<f64> {
33 values
34 .iter()
35 .copied()
36 .filter(|v| !v.is_nan())
37 .reduce(|best, v| if self.better(v, best) { v } else { best })
38 }
39}
40
41impl FromStr for Goal {
42 type Err = GoalError;
43
44 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 match s {
48 "min" => Ok(Self::Minimize),
49 "max" => Ok(Self::Maximize),
50 _ => Err(GoalError::Unknown(s.to_string())),
51 }
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
57pub enum GoalError {
58 Unknown(String),
60}
61
62impl fmt::Display for GoalError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match self {
65 Self::Unknown(said) => write!(
66 f,
67 "`{said}` does not say which way is better: write `min` for a loss or `max` for an accuracy"
68 ),
69 }
70 }
71}
72
73impl std::error::Error for GoalError {}
74
75impl fmt::Display for Goal {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 match self {
78 Self::Minimize => f.write_str("min"),
79 Self::Maximize => f.write_str("max"),
80 }
81 }
82}