@@ -27,19 +27,18 @@ class CSeasonalTime;
27
27
28
28
// ! \brief Represents the result of running the periodicity
29
29
// ! hypothesis tests.
30
- // clang-format off
31
- class MATHS_EXPORT CPeriodicityHypothesisTestsResult : boost::equality_comparable<CPeriodicityHypothesisTestsResult,
32
- boost::addable<CPeriodicityHypothesisTestsResult> > {
33
- // clang-format on
30
+ class MATHS_EXPORT CPeriodicityHypothesisTestsResult
31
+ : boost::equality_comparable<CPeriodicityHypothesisTestsResult> {
34
32
public:
35
33
using TTimeTimePr = std::pair<core_t ::TTime, core_t ::TTime>;
34
+ using TSizeVec = std::vector<std::size_t >;
36
35
37
- public:
38
36
// ! \brief Component data.
39
37
struct MATHS_EXPORT SComponent {
40
- SComponent ();
38
+ SComponent () = default ;
41
39
SComponent (const std::string& description,
42
40
bool diurnal,
41
+ bool piecewiseScaled,
43
42
core_t ::TTime startOfPartition,
44
43
core_t ::TTime period,
45
44
const TTimeTimePr& window,
@@ -56,41 +55,45 @@ class MATHS_EXPORT CPeriodicityHypothesisTestsResult : boost::equality_comparabl
56
55
// ! An identifier for the component used by the test.
57
56
std::string s_Description;
58
57
// ! True if this is a diurnal component false otherwise.
59
- bool s_Diurnal;
58
+ bool s_Diurnal = false ;
59
+ // ! The segmentation of the window into intervals of constant
60
+ // ! scaling.
61
+ bool s_PiecewiseScaled = false ;
60
62
// ! The start of the partition.
61
- core_t ::TTime s_StartOfPartition;
63
+ core_t ::TTime s_StartOfPartition = 0 ;
62
64
// ! The period of the component.
63
- core_t ::TTime s_Period;
65
+ core_t ::TTime s_Period = 0 ;
64
66
// ! The component window.
65
67
TTimeTimePr s_Window;
66
- // ! The precedence to apply to this component when
67
- // ! deciding which to keep.
68
- double s_Precedence;
68
+ // ! The precedence to apply to this component when deciding
69
+ // ! which to keep.
70
+ double s_Precedence = 0.0 ;
69
71
};
70
72
71
73
using TComponent5Vec = core::CSmallVector<SComponent, 5 >;
74
+ using TRemoveCondition = std::function<bool (const SComponent&)>;
72
75
73
76
public:
74
77
// ! Check if this is equal to \p other.
75
78
bool operator ==(const CPeriodicityHypothesisTestsResult& other) const ;
76
79
77
- // ! Sets to the union of the periodic components present.
78
- // !
79
- // ! \warning This only makes sense if the this and the
80
- // ! other result share the start of the partition time.
81
- const CPeriodicityHypothesisTestsResult&
82
- operator +=(const CPeriodicityHypothesisTestsResult& other);
83
-
84
80
// ! Add a component.
85
81
void add (const std::string& description,
86
82
bool diurnal,
83
+ bool piecewiseScaled,
87
84
core_t ::TTime startOfWeek,
88
85
core_t ::TTime period,
89
86
const TTimeTimePr& window,
90
87
double precedence = 1.0 );
91
88
92
89
// ! Remove the component with \p description.
93
- void remove (const std::string& description);
90
+ void remove (const TRemoveCondition& condition);
91
+
92
+ // ! Set if this is a piecewise linear trend.
93
+ void piecewiseLinearTrend (bool value);
94
+
95
+ // ! Check if this is a piecewise linear trend.
96
+ bool piecewiseLinearTrend () const ;
94
97
95
98
// ! Check if there are any periodic components.
96
99
bool periodic () const ;
@@ -102,6 +105,9 @@ class MATHS_EXPORT CPeriodicityHypothesisTestsResult : boost::equality_comparabl
102
105
std::string print () const ;
103
106
104
107
private:
108
+ // ! If true then the hypothesis used a piecewise linear trend.
109
+ bool m_PiecewiseLinearTrend = false ;
110
+
105
111
// ! The periodic components.
106
112
TComponent5Vec m_Components;
107
113
};
@@ -174,14 +180,17 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
174
180
using TComponent = CPeriodicityHypothesisTestsResult::SComponent;
175
181
176
182
public:
177
- CPeriodicityHypothesisTests ();
183
+ CPeriodicityHypothesisTests () = default ;
178
184
explicit CPeriodicityHypothesisTests (const CPeriodicityHypothesisTestsConfig& config);
179
185
180
186
// ! Check if the test is initialized.
181
187
bool initialized () const ;
182
188
183
189
// ! Initialize the bucket values.
184
- void initialize (core_t ::TTime bucketLength, core_t ::TTime window, core_t ::TTime period);
190
+ void initialize (core_t ::TTime startTime,
191
+ core_t ::TTime bucketLength,
192
+ core_t ::TTime window,
193
+ core_t ::TTime period);
185
194
186
195
// ! Add \p value at \p time.
187
196
void add (core_t ::TTime time, double value, double weight = 1.0 );
@@ -193,34 +202,39 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
193
202
private:
194
203
using TDoubleVec = std::vector<double >;
195
204
using TDoubleVec2Vec = core::CSmallVector<TDoubleVec, 2 >;
205
+ using TSizeVec = std::vector<std::size_t >;
196
206
using TFloatMeanAccumulatorCRng = core::CVectorRange<const TFloatMeanAccumulatorVec>;
197
207
using TMinMaxAccumulator = maths::CBasicStatistics::CMinMax<core_t ::TTime>;
198
208
199
209
// ! \brief A collection of statistics used during testing.
200
210
struct STestStats {
201
- STestStats ();
211
+ explicit STestStats (double meanMagnitude );
202
212
// ! Set the various test thresholds.
203
213
void setThresholds (double vt, double at, double Rt);
204
214
// ! Check if the null hypothesis is good enough to not need an
205
215
// ! alternative.
206
216
bool nullHypothesisGoodEnough () const ;
217
+ // ! The number of segments in the trend.
218
+ double s_TrendSegments;
207
219
// ! True if a known periodic component is tested.
208
220
bool s_HasPeriod;
209
221
// ! True if a known repeating partition is tested.
210
222
bool s_HasPartition;
211
223
// ! The maximum variance to accept the alternative hypothesis.
212
- double s_Vt ;
224
+ double s_VarianceThreshold ;
213
225
// ! The minimum amplitude to accept the alternative hypothesis.
214
- double s_At ;
226
+ double s_AmplitudeThreshold ;
215
227
// ! The minimum autocorrelation to accept the alternative
216
228
// ! hypothesis.
217
- double s_Rt ;
229
+ double s_AutocorrelationThreshold ;
218
230
// ! The data range.
219
231
double s_Range;
220
232
// ! The number of buckets with at least one measurement.
221
- double s_B ;
233
+ double s_NonEmptyBuckets ;
222
234
// ! The average number of measurements per bucket value.
223
- double s_M;
235
+ double s_MeasurementsPerBucket;
236
+ // ! The mean magnitude of the bucket values.
237
+ double s_MeanMagnitude;
224
238
// ! The null hypothesis periodic components.
225
239
CPeriodicityHypothesisTestsResult s_H0;
226
240
// ! The variance estimate of H0.
@@ -231,10 +245,14 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
231
245
double s_DF0;
232
246
// ! The trend for the null hypothesis.
233
247
TDoubleVec2Vec s_T0;
248
+ // ! The linear scales if any.
249
+ TDoubleVec s_Scales;
234
250
// ! The partition for the null hypothesis.
235
251
TTimeTimePr2Vec s_Partition;
236
252
// ! The start of the repeating partition.
237
253
core_t ::TTime s_StartOfPartition;
254
+ // ! The segmentation of the interval if any.
255
+ TSizeVec s_Segmentation;
238
256
};
239
257
240
258
// ! \brief Manages the testing of a set of nested hypotheses.
@@ -268,13 +286,19 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
268
286
CNestedHypotheses& addNested (TTestFunc test);
269
287
// ! Test the hypotheses.
270
288
CPeriodicityHypothesisTestsResult test (STestStats& stats) const ;
289
+ // ! Set if the hypothesis uses a piecewise linear trend.
290
+ void trendSegments (std::size_t segments);
291
+ // ! Check if the hypothesis uses a piecewise linear trend.
292
+ std::size_t trendSegments () const ;
271
293
272
294
private:
273
295
using THypothesisVec = std::vector<CNestedHypotheses>;
274
296
275
297
private:
276
298
// ! The test.
277
299
TTestFunc m_Test;
300
+ // ! The number of segments in the trend.
301
+ std::size_t m_TrendSegments;
278
302
// ! If true always test the nested hypotheses.
279
303
bool m_AlwaysTestNested;
280
304
// ! The nested hypotheses to test.
@@ -314,11 +338,13 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
314
338
// ! Test for a daily periodic component.
315
339
CPeriodicityHypothesisTestsResult testForDaily (const TTimeTimePr2Vec& window,
316
340
const TFloatMeanAccumulatorCRng& buckets,
341
+ bool scaling,
317
342
STestStats& stats) const ;
318
343
319
344
// ! Test for a weekly periodic component.
320
345
CPeriodicityHypothesisTestsResult testForWeekly (const TTimeTimePr2Vec& window,
321
346
const TFloatMeanAccumulatorCRng& buckets,
347
+ bool scaling,
322
348
STestStats& stats) const ;
323
349
324
350
// ! Test for a weekday/end partition.
@@ -336,6 +362,7 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
336
362
// ! periodicity.
337
363
CPeriodicityHypothesisTestsResult testForPeriod (const TTimeTimePr2Vec& window,
338
364
const TFloatMeanAccumulatorCRng& buckets,
365
+ bool scaling,
339
366
STestStats& stats) const ;
340
367
341
368
// ! Check we've seen sufficient data to test accurately.
@@ -344,7 +371,8 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
344
371
345
372
// ! Check if there are enough non-empty buckets which are repeated
346
373
// ! at at least one \p period in \p buckets.
347
- bool seenSufficientPeriodicallyPopulatedBucketsToTest (const TFloatMeanAccumulatorCRng& buckets,
374
+ template <typename CONTAINER>
375
+ bool seenSufficientPeriodicallyPopulatedBucketsToTest (const CONTAINER& buckets,
348
376
std::size_t period) const ;
349
377
350
378
// ! Compute various ancillary statistics for testing.
@@ -373,6 +401,13 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
373
401
core_t ::TTime period,
374
402
STestStats& stats) const ;
375
403
404
+ // ! Test to see if there is significant evidence for a component
405
+ // ! with period \p period which is piecewise linearly scaled.
406
+ bool testPeriodWithScaling (const TTimeTimePr2Vec& windows,
407
+ const TFloatMeanAccumulatorCRng& buckets,
408
+ core_t ::TTime period,
409
+ STestStats& stats) const ;
410
+
376
411
// ! Test to see if there is significant evidence for a repeating
377
412
// ! partition of the data into windows defined by \p partition.
378
413
bool testPartition (const TTimeTimePr2Vec& partition,
@@ -381,6 +416,29 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
381
416
double correction,
382
417
STestStats& stats) const ;
383
418
419
+ // ! Run the explained variance test on an alternative hypothesis.
420
+ bool testVariance (const TTimeTimePr2Vec& window,
421
+ const TFloatMeanAccumulatorVec& buckets,
422
+ core_t ::TTime period,
423
+ double df1,
424
+ double v1,
425
+ STestStats& stats,
426
+ double & R,
427
+ double & meanRepeats,
428
+ double & pVariance,
429
+ const TSizeVec& segmentation = TSizeVec{}) const ;
430
+
431
+ // ! Run the component amplitude test on the alternative hypothesis.
432
+ bool testAmplitude (const TTimeTimePr2Vec& window,
433
+ const TFloatMeanAccumulatorVec& buckets,
434
+ core_t ::TTime period,
435
+ double b,
436
+ double v,
437
+ double R,
438
+ double meanRepeats,
439
+ double pVariance,
440
+ STestStats& stats) const ;
441
+
384
442
private:
385
443
// ! The minimum proportion of populated buckets for which
386
444
// ! the test is accurate.
@@ -393,14 +451,17 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
393
451
// ! Configures the tests to run.
394
452
CPeriodicityHypothesisTestsConfig m_Config;
395
453
454
+ // ! The start time of the window.
455
+ core_t ::TTime m_StartTime = 0 ;
456
+
396
457
// ! The bucketing interval.
397
- core_t ::TTime m_BucketLength;
458
+ core_t ::TTime m_BucketLength = 0 ;
398
459
399
460
// ! The window length for which to maintain bucket values.
400
- core_t ::TTime m_WindowLength;
461
+ core_t ::TTime m_WindowLength = 0 ;
401
462
402
463
// ! The specified period to test.
403
- core_t ::TTime m_Period;
464
+ core_t ::TTime m_Period = 0 ;
404
465
405
466
// ! The time range of values added to the test.
406
467
TMinMaxAccumulator m_TimeRange;
@@ -409,16 +470,13 @@ class MATHS_EXPORT CPeriodicityHypothesisTests {
409
470
TFloatMeanAccumulatorVec m_BucketValues;
410
471
};
411
472
412
- using TFloatMeanAccumulator = CBasicStatistics::SSampleMean<CFloatStorage>::TAccumulator;
413
- using TFloatMeanAccumulatorVec = std::vector<TFloatMeanAccumulator>;
414
-
415
473
// ! Test for periodic components in \p values.
416
474
MATHS_EXPORT
417
475
CPeriodicityHypothesisTestsResult
418
476
testForPeriods (const CPeriodicityHypothesisTestsConfig& config,
419
477
core_t ::TTime startTime,
420
478
core_t ::TTime bucketLength,
421
- const TFloatMeanAccumulatorVec & values);
479
+ const std::vector<CBasicStatistics::SSampleMean<CFloatStorage>::TAccumulator> & values);
422
480
}
423
481
}
424
482
0 commit comments