1use std::ops::Sub;
9
10pub trait Diff<T> {
12 fn diff(&self) -> Vec<T>;
14}
15
16impl<T> Diff<T> for [T]
17where
18 T: Copy + Sub<Output = T>,
19{
20 fn diff(&self) -> Vec<T> {
21 let n = self.len();
22 self.iter()
23 .take(n - 1)
24 .enumerate()
25 .map(|(idx, x)| self[idx + 1] - *x)
26 .collect()
27 }
28}
29
30pub trait Monotonic {
32 fn is_increasing(&self) -> bool;
34 fn is_decreasing(&self) -> bool;
36 fn is_strictly_increasing(&self) -> bool;
38 fn is_strictly_decreasing(&self) -> bool;
40}
41
42impl<T> Monotonic for [T]
43where
44 T: PartialOrd,
45{
46 fn is_increasing(&self) -> bool {
47 self.as_ref().iter().is_sorted()
48 }
49
50 fn is_decreasing(&self) -> bool {
51 self.as_ref().iter().is_sorted_by(|a, b| a >= b)
52 }
53
54 fn is_strictly_increasing(&self) -> bool {
55 self.as_ref().iter().is_sorted_by(|a, b| a < b)
56 }
57
58 fn is_strictly_decreasing(&self) -> bool {
59 self.as_ref().iter().is_sorted_by(|a, b| a > b)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_diff() {
69 let x: Vec<f64> = vec![1.0, 2.0, 3.0];
70 let exp: Vec<f64> = vec![1.0, 1.0];
71 assert_eq!(x.diff(), exp);
72 }
73
74 #[test]
75 fn test_monotonic() {
76 let x1: Vec<f64> = vec![1.0, 1.0, 3.0];
77 let x2: Vec<f64> = vec![1.0, 2.0, 3.0];
78 let x3: Vec<f64> = vec![3.0, 2.0, 2.0];
79 let x4: Vec<f64> = vec![3.0, 2.0, 1.0];
80 assert!(x1.is_increasing());
81 assert!(!x1.is_strictly_increasing());
82 assert!(x2.is_increasing());
83 assert!(x2.is_strictly_increasing());
84 assert!(x3.is_decreasing());
85 assert!(!x3.is_strictly_decreasing());
86 assert!(x4.is_decreasing());
87 assert!(x4.is_strictly_decreasing());
88 }
89}