Skip to main content

gamlss_transform/transforms/
identity_positive.rs

1use crate::{TargetTransform, TransformError, map_slice_into, validate_positive};
2
3/// Identity transform that validates strictly positive targets.
4#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
5pub struct IdentityPositive;
6
7/// State for [`IdentityPositive`].
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
9pub struct IdentityPositiveState;
10
11impl TargetTransform for IdentityPositive {
12    type State = IdentityPositiveState;
13
14    fn fit(y: &[f64]) -> Result<Self::State, TransformError> {
15        validate_positive(y)?;
16        Ok(IdentityPositiveState)
17    }
18
19    fn transform(_: &Self::State, y: f64) -> f64 {
20        y
21    }
22
23    fn inverse(_: &Self::State, value: f64) -> f64 {
24        value
25    }
26
27    fn transform_slice(state: &Self::State, y: &[f64]) -> Result<Vec<f64>, TransformError> {
28        let mut out = vec![0.0; y.len()];
29        Self::transform_into(state, y, &mut out)?;
30        Ok(out)
31    }
32
33    fn transform_into(
34        state: &Self::State,
35        y: &[f64],
36        out: &mut [f64],
37    ) -> Result<(), TransformError> {
38        map_slice_into(y, out, validate_positive, |value| {
39            Self::transform(state, value)
40        })
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use crate::{IdentityPositive, TargetTransform, TransformError};
47
48    #[test]
49    fn rejects_non_positive_values() {
50        assert_eq!(
51            IdentityPositive::fit(&[-1.0]).unwrap_err(),
52            TransformError::NonPositiveValue
53        );
54    }
55
56    #[test]
57    fn leaves_positive_values_unchanged() {
58        let y = [1.0, 2.0];
59        let (state, transformed) = IdentityPositive::fit_transform(&y).unwrap();
60
61        assert_eq!(transformed, y);
62        assert_eq!(
63            IdentityPositive::inverse_slice(&state, &transformed).unwrap(),
64            y
65        );
66    }
67}