flow_gate_core/transform/
fasinh.rs1use 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}