Skip to main content

flow_gate_core/transform/
fasinh.rs

1use crate::error::FlowGateError;
2use crate::traits::Transform;
3
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct FASinhTransform {
6    pub t: f64,
7    pub m: f64,
8    pub a: f64,
9    scale: f64,
10    offset: f64,
11    divisor: f64,
12    sinh_m: f64,
13}
14
15impl FASinhTransform {
16    pub fn new(t: f64, m: f64, a: f64) -> Result<Self, FlowGateError> {
17        if !t.is_finite() || t <= 0.0 {
18            return Err(FlowGateError::InvalidTransformParam(
19                "FASinh parameter T must be finite and > 0".to_string(),
20            ));
21        }
22        if !m.is_finite() || m <= 0.0 {
23            return Err(FlowGateError::InvalidTransformParam(
24                "FASinh parameter M must be finite and > 0".to_string(),
25            ));
26        }
27        if !a.is_finite() || a < 0.0 {
28            return Err(FlowGateError::InvalidTransformParam(
29                "FASinh parameter A must be finite and >= 0".to_string(),
30            ));
31        }
32        let ln10 = 10.0_f64.ln();
33        let sinh_m = (m * ln10).sinh();
34        let divisor = (m + a) * ln10;
35        if divisor <= 0.0 || !divisor.is_finite() {
36            return Err(FlowGateError::InvalidTransformParam(
37                "FASinh divisor is non-positive or non-finite".to_string(),
38            ));
39        }
40        let scale = sinh_m / t;
41        let offset = a * ln10;
42        Ok(Self {
43            t,
44            m,
45            a,
46            scale,
47            offset,
48            divisor,
49            sinh_m,
50        })
51    }
52}
53
54impl Transform for FASinhTransform {
55    fn apply(&self, value: f64) -> f64 {
56        if !value.is_finite() {
57            return f64::NAN;
58        }
59        ((value * self.scale).asinh() + self.offset) / self.divisor
60    }
61
62    fn invert(&self, scaled: f64) -> f64 {
63        if !scaled.is_finite() {
64            return f64::NAN;
65        }
66        let x = self.t * (scaled * self.divisor - self.offset).sinh() / self.sinh_m;
67        if x.is_finite() {
68            x
69        } else {
70            f64::NAN
71        }
72    }
73
74    fn transform_id(&self) -> &str {
75        "fasinh"
76    }
77}