@@ -27,7 +27,6 @@ pub mod timestamps;
27
27
use std:: mem;
28
28
29
29
use arrow:: array:: ArrayBuilder ;
30
- use modelardb_common:: errors:: ModelarDbError ;
31
30
use modelardb_common:: types:: {
32
31
Timestamp , TimestampBuilder , UnivariateId , UnivariateIdBuilder , Value , ValueBuilder ,
33
32
} ;
@@ -99,6 +98,7 @@ pub fn len(start_time: Timestamp, end_time: Timestamp, timestamps: &[u8]) -> usi
99
98
}
100
99
101
100
/// Compute the sum of the values for a time series segment whose values are represented by a model.
101
+ #[ allow( clippy:: too_many_arguments) ]
102
102
pub fn sum (
103
103
model_type_id : u8 ,
104
104
start_time : Timestamp ,
@@ -107,15 +107,52 @@ pub fn sum(
107
107
min_value : Value ,
108
108
max_value : Value ,
109
109
values : & [ u8 ] ,
110
+ residuals : & [ u8 ] ,
110
111
) -> Value {
111
- match model_type_id {
112
- PMC_MEAN_ID => pmc_mean:: sum ( start_time, end_time, timestamps, min_value) ,
113
- SWING_ID => swing:: sum (
114
- start_time, end_time, timestamps, min_value, max_value, values,
112
+ // Extract the number of residuals stored.
113
+ let residuals_length = if residuals. is_empty ( ) {
114
+ 0
115
+ } else {
116
+ // The number of residuals are stored as the last byte.
117
+ residuals[ residuals. len ( ) - 1 ] as usize
118
+ } ;
119
+
120
+ let model_length = len ( start_time, end_time, timestamps) - residuals_length;
121
+
122
+ // Computes the sum from the model.
123
+ let ( model_last_value, model_sum) = match model_type_id {
124
+ PMC_MEAN_ID => {
125
+ let value =
126
+ CompressedSegmentBuilder :: decode_values_for_pmc_mean ( min_value, max_value, values) ;
127
+ ( value, pmc_mean:: sum ( model_length, value) )
128
+ }
129
+ SWING_ID => {
130
+ let ( first_value, last_value) =
131
+ CompressedSegmentBuilder :: decode_values_for_swing ( min_value, max_value, values) ;
132
+ (
133
+ last_value,
134
+ swing:: sum (
135
+ start_time,
136
+ end_time,
137
+ timestamps,
138
+ first_value,
139
+ last_value,
140
+ residuals_length,
141
+ ) ,
142
+ )
143
+ }
144
+ GORILLA_ID => (
145
+ f32:: NAN , // A segment with values compressed by Gorilla never has residuals.
146
+ gorilla:: sum ( model_length, values, None ) ,
115
147
) ,
116
- // TODO: take residuals stored as part of the segment into account when refactoring optimizer.
117
- GORILLA_ID => gorilla:: sum ( start_time, end_time, timestamps, values, None ) ,
118
148
_ => panic ! ( "Unknown model type." ) ,
149
+ } ;
150
+
151
+ // Compute the sum from the residuals.
152
+ if residuals. is_empty ( ) {
153
+ model_sum
154
+ } else {
155
+ model_sum + gorilla:: sum ( residuals_length, residuals, Some ( model_last_value) )
119
156
}
120
157
}
121
158
@@ -137,21 +174,15 @@ pub fn grid(
137
174
timestamp_builder : & mut TimestampBuilder ,
138
175
value_builder : & mut ValueBuilder ,
139
176
) {
140
- // Extract the number of residuals stored.
141
- let residuals_length = if residuals. is_empty ( ) {
142
- 0
143
- } else {
144
- // The number of residuals are stored as the last byte.
145
- residuals[ residuals. len ( ) - 1 ]
146
- } ;
147
-
148
- // Decompress all of the timestamps and create a slice for the model's timestamps.
149
- let model_timestamps_start_index = timestamp_builder. values_slice ( ) . len ( ) ;
150
- timestamps:: decompress_all_timestamps ( start_time, end_time, timestamps, timestamp_builder) ;
151
- let model_timestamps_end_index =
152
- timestamp_builder. values_slice ( ) . len ( ) - residuals_length as usize ;
153
- let model_timestamps =
154
- & timestamp_builder. values_slice ( ) [ model_timestamps_start_index..model_timestamps_end_index] ;
177
+ // Decompress the timestamps.
178
+ let ( model_timestamps, residuals_timestamps) =
179
+ decompress_all_timestamps_and_split_into_models_and_residuals (
180
+ start_time,
181
+ end_time,
182
+ timestamps,
183
+ residuals,
184
+ timestamp_builder,
185
+ ) ;
155
186
156
187
// Reconstruct the values from the model.
157
188
match model_type_id {
@@ -192,21 +223,49 @@ pub fn grid(
192
223
}
193
224
194
225
// Reconstruct the values from the residuals.
195
- if residuals_length > 0 {
196
- // The first value in residuals are compressed against models last value.
226
+ if !residuals. is_empty ( ) {
197
227
let model_last_value = value_builder. values_slice ( ) [ value_builder. len ( ) - 1 ] ;
198
228
199
229
gorilla:: grid (
200
230
univariate_id,
201
231
& residuals[ ..residuals. len ( ) - 1 ] ,
202
232
univariate_id_builder,
203
- & timestamp_builder . values_slice ( ) [ model_timestamps_end_index.. ] ,
233
+ residuals_timestamps ,
204
234
value_builder,
205
235
Some ( model_last_value) ,
206
236
) ;
207
237
}
208
238
}
209
239
240
+ /// Decompress the timestamps stored as `start_time`, `end_time`, and `timestamps`, add them to
241
+ /// `timestamp_builder`, and return slices to the model's timestamps and the residual's timestamps.
242
+ fn decompress_all_timestamps_and_split_into_models_and_residuals < ' a > (
243
+ start_time : Timestamp ,
244
+ end_time : Timestamp ,
245
+ timestamps : & ' a [ u8 ] ,
246
+ residuals : & ' a [ u8 ] ,
247
+ timestamp_builder : & ' a mut TimestampBuilder ,
248
+ ) -> ( & ' a [ Timestamp ] , & ' a [ Timestamp ] ) {
249
+ // Extract the number of residuals stored.
250
+ let residuals_length = if residuals. is_empty ( ) {
251
+ 0
252
+ } else {
253
+ // The number of residuals are stored as the last byte.
254
+ residuals[ residuals. len ( ) - 1 ]
255
+ } ;
256
+
257
+ let model_timestamps_start_index = timestamp_builder. values_slice ( ) . len ( ) ;
258
+ timestamps:: decompress_all_timestamps ( start_time, end_time, timestamps, timestamp_builder) ;
259
+ let model_timestamps_end_index =
260
+ timestamp_builder. values_slice ( ) . len ( ) - residuals_length as usize ;
261
+
262
+ let model_timestamps =
263
+ & timestamp_builder. values_slice ( ) [ model_timestamps_start_index..model_timestamps_end_index] ;
264
+ let residuals_timestamps = & timestamp_builder. values_slice ( ) [ model_timestamps_end_index..] ;
265
+
266
+ ( model_timestamps, residuals_timestamps)
267
+ }
268
+
210
269
#[ cfg( test) ]
211
270
mod tests {
212
271
use super :: * ;
@@ -298,4 +357,41 @@ mod tests {
298
357
prop_assert!( !equal_or_nan( v1, v2) ) ;
299
358
}
300
359
}
360
+
361
+ // Test for decompress_all_timestamps_and_split_into_models_and_residuals().
362
+ #[ test]
363
+ fn test_decompress_all_timestamps_and_split_into_models_and_residuals_no_residuals ( ) {
364
+ let mut timestamp_builder = TimestampBuilder :: new ( ) ;
365
+
366
+ let ( model_timestamps, residuals_timestamps) =
367
+ decompress_all_timestamps_and_split_into_models_and_residuals (
368
+ 100 ,
369
+ 500 ,
370
+ & [ 5 ] ,
371
+ & [ ] ,
372
+ & mut timestamp_builder,
373
+ ) ;
374
+
375
+ // Type aliases cannot be used when constructor, so &[Timestamp] is not possible.
376
+ let expected_residuals_timestamps: & [ Timestamp ] = & [ ] ;
377
+ assert_eq ! ( model_timestamps, & [ 100 , 200 , 300 , 400 , 500 ] ) ;
378
+ assert_eq ! ( residuals_timestamps, expected_residuals_timestamps) ;
379
+ }
380
+
381
+ #[ test]
382
+ fn test_decompress_all_timestamps_and_split_into_models_and_residuals_with_residuals ( ) {
383
+ let mut timestamp_builder = TimestampBuilder :: new ( ) ;
384
+
385
+ let ( model_timestamps, residuals_timestamps) =
386
+ decompress_all_timestamps_and_split_into_models_and_residuals (
387
+ 100 ,
388
+ 500 ,
389
+ & [ 5 ] ,
390
+ & [ 2 ] ,
391
+ & mut timestamp_builder,
392
+ ) ;
393
+
394
+ assert_eq ! ( model_timestamps, & [ 100 , 200 , 300 ] ) ;
395
+ assert_eq ! ( residuals_timestamps, & [ 400 , 500 ] ) ;
396
+ }
301
397
}
0 commit comments