1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
pub struct AmocParams {
min_size: usize,
alpha: f64,
exact: bool
}
pub fn amoc() -> AmocParams {
AmocParams {
min_size: 30,
alpha: 2.0,
exact: true
}
}
impl AmocParams {
pub fn min_size(&mut self, value: usize) -> &mut Self {
self.min_size = value;
self
}
pub fn exact(&mut self, value: bool) -> &mut Self {
self.exact = value;
self
}
pub fn fit(&self, z: &[f64]) -> Option<usize> {
assert!(self.min_size >= 2, "min_size must be at least 2");
assert!(self.alpha >= 0.0 && self.alpha <= 2.0, "alpha must be between 0 and 2");
if z.len() < self.min_size {
return None;
}
let min = z.iter().min_by(|i, j| i.partial_cmp(j).unwrap()).unwrap();
let max = z.iter().max_by(|i, j| i.partial_cmp(j).unwrap()).unwrap();
let denom = max - min;
if denom == 0.0 {
return None;
}
let zcounts: Vec<f64> = z.iter().map(|x| (x - min) / denom).collect();
let (loc, stat) = if self.exact {
crate::edmx::edmx(&zcounts, self.min_size, self.alpha)
} else {
crate::edm_tail::edm_tail(&zcounts, self.min_size, self.alpha)
};
if stat > 0.0 {
Some(loc)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
fn generate_series() -> Vec<f64> {
vec![
3.0, 1.0, 2.0, 3.0, 2.0, 1.0, 1.0, 2.0, 2.0, 3.0,
6.0, 4.0, 4.0, 5.0, 6.0, 4.0, 4.0, 4.0, 6.0, 5.0,
9.0, 8.0, 7.0, 9.0, 8.0, 9.0, 9.0, 9.0, 7.0, 9.0
]
}
#[test]
fn test_amoc() {
let series = generate_series();
let breakout = crate::amoc().min_size(5).fit(&series);
assert_eq!(breakout, Some(19));
}
#[test]
fn test_tail() {
let series = generate_series();
let breakout = crate::amoc().min_size(5).exact(false).fit(&series);
assert_eq!(breakout, Some(20));
}
#[test]
fn test_empty() {
let series = Vec::new();
let breakout = crate::amoc().fit(&series);
assert_eq!(breakout, None);
}
#[test]
fn test_constant() {
let series = vec![1.0; 100];
let breakout = crate::amoc().fit(&series);
assert_eq!(breakout, None);
}
#[test]
fn test_almost_constant() {
let mut series = vec![1.0; 100];
series[50] = 2.0;
let breakout = crate::amoc().fit(&series);
assert_eq!(breakout, None);
}
#[test]
fn test_simple() {
let series = vec![
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
];
let breakout = crate::amoc().min_size(5).fit(&series);
assert_eq!(breakout, Some(10));
}
}