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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use crate::optimizer::OptimizerResult;
use crate::{ModelSelectionResult, Segmentation};
pub struct BinarySegmentationTree {
pub start: usize,
pub stop: usize,
pub n: usize,
pub model_selection_result: ModelSelectionResult,
pub left: Option<Box<BinarySegmentationTree>>,
pub right: Option<Box<BinarySegmentationTree>>,
pub optimizer_result: Option<OptimizerResult>,
}
impl BinarySegmentationTree {
pub fn new(X: &ndarray::ArrayView2<'_, f64>) -> BinarySegmentationTree {
BinarySegmentationTree {
start: 0,
stop: X.nrows(),
n: X.nrows(),
model_selection_result: ModelSelectionResult::default(),
left: None,
right: None,
optimizer_result: None,
}
}
fn new_left(&self, split: usize) -> Box<BinarySegmentationTree> {
Box::new(BinarySegmentationTree {
start: self.start,
stop: split,
n: self.n,
model_selection_result: ModelSelectionResult::default(),
left: None,
right: None,
optimizer_result: None,
})
}
fn new_right(&self, split: usize) -> Box<BinarySegmentationTree> {
Box::new(BinarySegmentationTree {
start: split,
stop: self.stop,
n: self.n,
model_selection_result: ModelSelectionResult::default(),
left: None,
right: None,
optimizer_result: None,
})
}
pub fn grow(&mut self, segmentation: &mut Segmentation) {
if let Ok(optimizer_result) = segmentation.find_best_split(self.start, self.stop) {
self.model_selection_result = segmentation.model_selection(&optimizer_result);
if self.model_selection_result.is_significant {
let mut left = self.new_left(optimizer_result.best_split);
left.grow(segmentation);
self.left = Some(left);
let mut right = self.new_right(optimizer_result.best_split);
right.grow(segmentation);
self.right = Some(right);
}
self.optimizer_result = Some(optimizer_result);
}
}
}
#[derive(Clone, Debug)]
pub struct BinarySegmentationResult {
pub start: usize,
pub stop: usize,
pub model_selection_result: ModelSelectionResult,
pub optimizer_result: Option<OptimizerResult>,
pub left: Option<Box<BinarySegmentationResult>>,
pub right: Option<Box<BinarySegmentationResult>>,
pub segments: Option<Vec<OptimizerResult>>,
}
impl BinarySegmentationResult {
pub fn from_tree(tree: BinarySegmentationTree) -> Self {
let left = tree
.left
.map(|tree| Box::new(BinarySegmentationResult::from_tree(*tree)));
let right = tree
.right
.map(|tree| Box::new(BinarySegmentationResult::from_tree(*tree)));
BinarySegmentationResult {
start: tree.start,
stop: tree.stop,
model_selection_result: tree.model_selection_result,
optimizer_result: tree.optimizer_result,
left,
right,
segments: None,
}
}
pub fn split_points(&self) -> Vec<usize> {
let mut split_points = vec![];
if let Some(left_boxed) = &self.left {
split_points.append(&mut left_boxed.split_points());
}
if let Some(result) = self.optimizer_result.as_ref() {
if self.model_selection_result.is_significant {
split_points.push(result.best_split);
}
}
if let Some(right_boxed) = &self.right {
split_points.append(&mut right_boxed.split_points());
}
split_points
}
pub fn with_segments(mut self, segmentation: Segmentation) -> Self {
self.segments = Some(segmentation.segments);
self
}
}
#[cfg(test)]
mod tests {
use super::super::control::Control;
use super::*;
use crate::optimizer::GridSearch;
use crate::segmentation::{Segmentation, SegmentationType};
use crate::testing;
#[test]
fn test_binary_segmentation_change_in_mean() {
let X = testing::array();
let X_view = X.view();
assert_eq!(X_view.shape(), &[100, 5]);
let control = Control::default();
let gain = testing::ChangeInMean::new(&X_view, &control);
let optimizer = GridSearch { gain };
let mut segmentation = Segmentation::new(SegmentationType::BS, &optimizer);
let mut binary_segmentation = BinarySegmentationTree::new(&X_view);
binary_segmentation.grow(&mut segmentation);
let optimizer_result = binary_segmentation.optimizer_result.as_ref().unwrap();
assert_eq!(optimizer_result.best_split, 25);
assert_eq!(optimizer_result.start, 0);
assert_eq!(optimizer_result.stop, 100);
}
#[test]
fn test_binary_segmentation_result() {
let X = testing::array();
let X_view = X.view();
assert_eq!(X_view.shape(), &[100, 5]);
let control = Control::default();
let gain = testing::ChangeInMean::new(&X_view, &control);
let optimizer = GridSearch { gain };
let mut segmentation = Segmentation::new(SegmentationType::SBS, &optimizer);
let mut tree = BinarySegmentationTree::new(&X_view);
tree.grow(&mut segmentation);
let result = BinarySegmentationResult::from_tree(tree);
assert_eq!(result.split_points(), vec![25, 40, 80]);
assert_eq!(result.start, 0);
assert_eq!(result.stop, 100);
assert_eq!(result.optimizer_result.as_ref().unwrap().best_split, 25);
assert!(result.model_selection_result.is_significant);
assert!(result.optimizer_result.is_some());
let right = result.right.as_ref().unwrap();
assert_eq!(right.split_points(), vec![40, 80]);
assert_eq!(right.start, 25);
assert_eq!(right.stop, 100);
assert_eq!(right.optimizer_result.as_ref().unwrap().best_split, 40);
assert!(right.model_selection_result.is_significant);
assert!(right.optimizer_result.is_some());
let left = result.left.as_ref().unwrap();
assert_eq!(left.split_points(), vec![]);
assert_eq!(left.start, 0);
assert_eq!(left.stop, 25);
assert_eq!(left.optimizer_result.as_ref().unwrap().best_split, 10);
assert!(!left.model_selection_result.is_significant);
assert!(left.optimizer_result.is_some());
let result = result.with_segments(segmentation);
assert!(!result.segments.as_ref().unwrap().is_empty());
}
}