light_curve_feature/features/
maximum_slope.rs1use 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}