master
cc 110 lines 3.93 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "ml_config.h"
4 #include "ml_features.h"
5
6 static inline size_t ml_effective_smooth_n(const ml_features_t *features)
7 {
8 // smooth_n == 0 is normalized to an effective window of 1, preserving the
9 // existing feature-extraction shape without introducing a separate no-op path.
10 return features->smooth_n == 0 ? 1 : features->smooth_n;
11 }
12
13 static inline void ml_validate_features_input(const ml_features_t *features, bool prediction_path)
14 {
15 size_t smooth_n = ml_effective_smooth_n(features);
16 size_t min_required_samples = features->diff_n + smooth_n + features->lag_n;
17
18 fatal_assert(features->dst_n >= features->src_n &&
19 "ml_features: dst buffer must be at least as large as src buffer");
20 if (prediction_path) {
21 fatal_assert(features->src_n >= min_required_samples &&
22 "ml_features_preprocess_predict: src buffer is smaller than diff_n + effective_smooth_n + lag_n");
23 } else {
24 fatal_assert(features->src_n >= min_required_samples &&
25 "ml_features_preprocess: src buffer is smaller than diff_n + effective_smooth_n + lag_n");
26 }
27 }
28
29 static void ml_features_diff(ml_features_t *features)
30 {
31 if (features->diff_n == 0)
32 return;
33
34 for (size_t idx = 0; idx != (features->src_n - features->diff_n); idx++) {
35 size_t high = (features->src_n - 1) - idx;
36 size_t low = high - features->diff_n;
37
38 features->dst[low] = features->src[high] - features->src[low];
39 }
40
41 size_t n = features->src_n - features->diff_n;
42 memcpy(features->src, features->dst, n * sizeof(calculated_number_t));
43
44 for (size_t idx = features->src_n - features->diff_n; idx != features->src_n; idx++)
45 features->src[idx] = 0.0;
46 }
47
48 static void ml_features_smooth(ml_features_t *features)
49 {
50 size_t smooth_n = ml_effective_smooth_n(features);
51 calculated_number_t sum = 0.0;
52
53 size_t idx = 0;
54 for (; idx != smooth_n - 1; idx++)
55 sum += features->src[idx];
56
57 for (; idx != (features->src_n - features->diff_n); idx++) {
58 sum += features->src[idx];
59 calculated_number_t prev_cn = features->src[idx - (smooth_n - 1)];
60 features->src[idx - (smooth_n - 1)] = sum / smooth_n;
61 sum -= prev_cn;
62 }
63
64 for (idx = 0; idx != smooth_n; idx++)
65 features->src[(features->src_n - 1) - idx] = 0.0;
66 }
67
68 static void ml_features_lag(ml_features_t *features, std::vector<DSample> &preprocessed_features, double sampling_ratio)
69 {
70 size_t n = features->src_n - features->diff_n - ml_effective_smooth_n(features) + 1 - features->lag_n;
71 preprocessed_features.clear();
72 preprocessed_features.reserve(n);
73
74 uint32_t max_mt = std::numeric_limits<uint32_t>::max();
75 uint32_t cutoff = static_cast<double>(max_mt) * sampling_ratio;
76
77 size_t sample_idx = 0;
78
79 for (size_t idx = 0; idx != n; idx++) {
80 if (Cfg.random_nums[idx % Cfg.random_nums.size()] > cutoff) {
81 continue;
82 }
83
84 preprocessed_features.emplace_back();
85 DSample &DS = preprocessed_features[sample_idx++];
86 DS.set_size(features->lag_n + 1);
87
88 for (size_t feature_idx = 0; feature_idx != features->lag_n + 1; feature_idx++)
89 DS(feature_idx) = features->src[idx + feature_idx];
90 }
91 }
92
93 void ml_features_preprocess(ml_features_t *features, std::vector<DSample> &preprocessed_features, double sampling_ratio)
94 {
95 ml_validate_features_input(features, false);
96 ml_features_diff(features);
97 ml_features_smooth(features);
98 ml_features_lag(features, preprocessed_features, sampling_ratio);
99 }
100
101 void ml_features_preprocess_predict(ml_features_t *features, DSample &sample)
102 {
103 ml_validate_features_input(features, true);
104 ml_features_diff(features);
105 ml_features_smooth(features);
106
107 sample.set_size(features->lag_n + 1);
108 for (size_t feature_idx = 0; feature_idx != features->lag_n + 1; feature_idx++)
109 sample(feature_idx) = features->src[feature_idx];
110 }