1use crate::float::Float;
2use crate::value::Value01;
3use core::marker::PhantomData;
4use witnessed::Witnessed;
5
6pub fn metric(name: &'static str) -> MetricName {
12 MetricName { name }
13}
14
15pub struct MetricName {
17 name: &'static str,
18}
19
20impl MetricName {
21 pub fn measure(self) -> MeasureStage {
23 MeasureStage { name: self.name }
24 }
25}
26
27pub struct MeasureStage {
29 name: &'static str,
30}
31
32impl MeasureStage {
33 pub fn by<I, Raw, M>(self, measure: M) -> MeasureSet<I, Raw, M> {
35 MeasureSet {
36 name: self.name,
37 measure,
38 _phantom: PhantomData,
39 }
40 }
41}
42
43pub struct MeasureSet<I, Raw, M> {
45 name: &'static str,
46 measure: M,
47 _phantom: PhantomData<(I, Raw)>,
48}
49
50impl<I, Raw, M> MeasureSet<I, Raw, M> {
51 pub fn map01(self) -> Map01Stage<I, Raw, M> {
53 Map01Stage {
54 name: self.name,
55 measure: self.measure,
56 _phantom: PhantomData,
57 }
58 }
59}
60
61pub struct Map01Stage<I, Raw, M> {
63 name: &'static str,
64 measure: M,
65 _phantom: PhantomData<(I, Raw)>,
66}
67
68impl<I, Raw, M> Map01Stage<I, Raw, M> {
69 pub fn by<T: Float, F>(self, map01: F) -> Metric<T, I, Raw, M, F> {
73 Metric {
74 name: self.name,
75 measure: self.measure,
76 map01,
77 _phantom: PhantomData,
78 }
79 }
80}
81
82impl<I, T: Float, M> Map01Stage<I, T, M> {
85 pub fn identity(self) -> Metric<T, I, T, M, impl Fn(&T, &I) -> Witnessed<T, Value01>> {
87 self.by(|raw: &T, _: &I| Value01::witness(raw.min(T::one()).max(T::zero())).unwrap())
88 }
89
90 pub fn linear(self, max: T) -> Metric<T, I, T, M, impl Fn(&T, &I) -> Witnessed<T, Value01>> {
92 self.by(move |raw: &T, _: &I| {
93 Value01::witness((*raw / max).min(T::one()).max(T::zero())).unwrap()
94 })
95 }
96
97 pub fn sigmoid(
103 self,
104 low: T,
105 high: T,
106 ) -> Metric<T, I, T, M, impl Fn(&T, &I) -> Witnessed<T, Value01>> {
107 let two = T::from_f64(2.0);
108 let eps = T::from_f64(10.0) * T::epsilon();
109 let x0 = (low + high) / two;
110 let k = two * (T::one() / eps - T::one()).ln() / (high - low);
111 self.by(move |raw: &T, _: &I| {
112 let v = T::one() / (T::one() + (-k * (*raw - x0)).exp());
113 Value01::witness(v).unwrap()
114 })
115 }
116
117 pub fn cauchy(
120 self,
121 left: T,
122 right: T,
123 ) -> Metric<T, I, T, M, impl Fn(&T, &I) -> Witnessed<T, Value01>> {
124 self.by(move |raw: &T, _: &I| {
125 let h = if *raw < T::zero() { left } else { right };
126 let v = T::one() / (T::one() + (*raw / h) * (*raw / h));
127 Value01::witness(v).unwrap()
128 })
129 }
130}
131
132pub struct Metric<T, I, Raw, M, F> {
145 pub(crate) name: &'static str,
146 pub(crate) measure: M,
147 pub(crate) map01: F,
148 _phantom: PhantomData<(T, I, Raw)>,
149}
150
151impl<T: Float, I, Raw, M, F> Metric<T, I, Raw, M, F>
152where
153 M: Fn(&I) -> Raw,
154 F: Fn(&Raw, &I) -> Witnessed<T, Value01>,
155{
156 #[inline]
158 pub fn eval(&self, input: &I) -> Witnessed<T, Value01> {
159 let raw = (self.measure)(input);
160 (self.map01)(&raw, input)
161 }
162
163 #[inline]
165 pub fn name(&self) -> &str {
166 self.name
167 }
168}
169
170impl<T: Float, I: 'static, Raw: 'static, M: 'static, F: 'static> Metric<T, I, Raw, M, F>
172where
173 M: Fn(&I) -> Raw,
174 F: Fn(&Raw, &I) -> Witnessed<T, Value01>,
175{
176 #[inline]
182 pub fn boxed(self) -> Box<dyn crate::Scorable<T, I>> {
183 Box::new(self)
184 }
185}
186
187impl<T, I, Raw, M: Clone, F: Clone> Clone for Metric<T, I, Raw, M, F> {
189 fn clone(&self) -> Self {
190 Self {
191 name: self.name,
192 measure: self.measure.clone(),
193 map01: self.map01.clone(),
194 _phantom: PhantomData,
195 }
196 }
197}
198
199#[cfg(test)]
200mod tests_for_metric;