light_curve_feature/features/
maximum_slope.rs

1use crate::evaluator::*;
2use itertools::Itertools;
3
4macro_const! {
5    const DOC: &'static str = r"
6Maximum slope between two sub-sequential observations
7
8$$
9\mathrm{maximum~slope} \equiv \max_{i=0..N-2}\left|\frac{m_{i+1} - m_i}{t_{i+1} - t_i}\right|
10$$
11
12Note that this feature can have high values and be cadence-dependent in the case of large range of time lags.
13In this case consider to use this feature with [Bins](crate::Bins).
14
15- Depends on: **time**, **magnitude**
16- Minimum number of observations: **2**
17- Number of features: **1**
18
19D’Isanto et al. 2016 [DOI:10.1093/mnras/stw157](https://doi.org/10.1093/mnras/stw157)
20";
21}
22
23#[doc = DOC!()]
24#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
25pub struct MaximumSlope {}
26
27lazy_info!(
28    MAXIMUM_SLOPE_INFO,
29    MaximumSlope,
30    size: 1,
31    min_ts_length: 2,
32    t_required: true,
33    m_required: true,
34    w_required: false,
35    sorting_required: true,
36);
37
38impl MaximumSlope {
39    pub fn new() -> Self {
40        Self {}
41    }
42
43    pub const fn doc() -> &'static str {
44        DOC
45    }
46}
47impl FeatureNamesDescriptionsTrait for MaximumSlope {
48    fn get_names(&self) -> Vec<&str> {
49        vec!["maximum_slope"]
50    }
51
52    fn get_descriptions(&self) -> Vec<&str> {
53        vec!["maximum slope of time-series"]
54    }
55}
56impl<T> FeatureEvaluator<T> for MaximumSlope
57where
58    T: Float,
59{
60    fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
61        self.check_ts_length(ts)?;
62        let result =
63            ts.t.as_slice()
64                .iter()
65                .tuple_windows()
66                .map(|(&t1, &t2)| t2 - t1)
67                .zip(
68                    ts.m.as_slice()
69                        .iter()
70                        .tuple_windows()
71                        .map(|(&m1, &m2)| m2 - m1),
72                )
73                .map(|(dt, dm)| T::abs(dm / dt))
74                .filter(|&x| x.is_finite())
75                .max_by(|a, b| a.partial_cmp(b).unwrap())
76                .expect("All points of the light curve have the same time");
77        Ok(vec![result])
78    }
79}
80
81#[cfg(test)]
82#[allow(clippy::unreadable_literal)]
83#[allow(clippy::excessive_precision)]
84mod tests {
85    use super::*;
86    use crate::tests::*;
87
88    check_feature!(MaximumSlope);
89
90    feature_test!(
91        maximum_slope_positive,
92        [MaximumSlope::new()],
93        [1.0],
94        [0.0_f32, 2.0, 4.0, 5.0, 7.0, 9.0],
95        [0.0_f32, 1.0, 2.0, 3.0, 4.0, 5.0],
96    );
97
98    feature_test!(
99        maximum_slope_negative,
100        [MaximumSlope::new()],
101        [1.0],
102        [0.0_f32, 1.0, 2.0, 3.0, 4.0, 5.0],
103        [0.0_f32, 0.5, 1.0, 0.0, 0.5, 1.0],
104    );
105}