@@ -31,34 +31,146 @@ struct sort_intervals {
3131// length, the longer is first PAA-reduced (_paa2) to the shorter length. The
3232// result is euclidean(znorm(a), znorm(b)) / count, divided by the number of
3333// compared points so spans of different lengths stay comparable.
34+ namespace {
35+
36+ double slice_mean (const std::vector<double >& ts, int start, int end) {
37+ double sum = 0.0 ;
38+ for (int i = start; i < end; i++) {
39+ sum += ts[i];
40+ }
41+ return sum / (end - start);
42+ }
43+
44+ double slice_stdev_pop (const std::vector<double >& ts, int start, int end, double mean) {
45+ double sq_sum = 0.0 ;
46+ for (int i = start; i < end; i++) {
47+ double d = ts[i] - mean;
48+ sq_sum += d * d;
49+ }
50+ return std::sqrt (sq_sum / (end - start));
51+ }
52+
53+ double vec_mean (const std::vector<double >& v) {
54+ double sum = 0.0 ;
55+ for (double x : v) {
56+ sum += x;
57+ }
58+ return sum / v.size ();
59+ }
60+
61+ double vec_stdev_pop (const std::vector<double >& v, double mean) {
62+ double sq_sum = 0.0 ;
63+ for (double x : v) {
64+ double d = x - mean;
65+ sq_sum += d * d;
66+ }
67+ return std::sqrt (sq_sum / v.size ());
68+ }
69+
70+ double znormed_rms_dist_equal (
71+ const std::vector<double >& ts, int s1, int e1 , int s2, int e2 ,
72+ double n_threshold) {
73+ int n = e1 - s1;
74+ double m1 = slice_mean (ts, s1, e1 );
75+ double m2 = slice_mean (ts, s2, e2 );
76+ double sd1 = slice_stdev_pop (ts, s1, e1 , m1);
77+ double sd2 = slice_stdev_pop (ts, s2, e2 , m2);
78+ bool raw1 = sd1 < n_threshold;
79+ bool raw2 = sd2 < n_threshold;
80+
81+ double res = 0.0 ;
82+ for (int i = 0 ; i < n; i++) {
83+ double a = raw1 ? ts[s1 + i] : (ts[s1 + i] - m1) / sd1;
84+ double b = raw2 ? ts[s2 + i] : (ts[s2 + i] - m2) / sd2;
85+ double d = a - b;
86+ res += d * d;
87+ }
88+ return std::sqrt (res) / n;
89+ }
90+
91+ double znormed_rms_dist_slice_vec (
92+ const std::vector<double >& ts, int s1, int e1 ,
93+ const std::vector<double >& b, double n_threshold) {
94+ int n = e1 - s1;
95+ double m1 = slice_mean (ts, s1, e1 );
96+ double m2 = vec_mean (b);
97+ double sd1 = slice_stdev_pop (ts, s1, e1 , m1);
98+ double sd2 = vec_stdev_pop (b, m2);
99+ bool raw1 = sd1 < n_threshold;
100+ bool raw2 = sd2 < n_threshold;
101+
102+ double res = 0.0 ;
103+ for (int i = 0 ; i < n; i++) {
104+ double a = raw1 ? ts[s1 + i] : (ts[s1 + i] - m1) / sd1;
105+ double bv = raw2 ? b[i] : (b[i] - m2) / sd2;
106+ double d = a - bv;
107+ res += d * d;
108+ }
109+ return std::sqrt (res) / n;
110+ }
111+
112+ double znormed_rms_dist_vec_slice (
113+ const std::vector<double >& a,
114+ const std::vector<double >& ts, int s2, int e2 ,
115+ double n_threshold) {
116+ int n = a.size ();
117+ double m1 = vec_mean (a);
118+ double m2 = slice_mean (ts, s2, e2 );
119+ double sd1 = vec_stdev_pop (a, m1);
120+ double sd2 = slice_stdev_pop (ts, s2, e2 , m2);
121+ bool raw1 = sd1 < n_threshold;
122+ bool raw2 = sd2 < n_threshold;
123+
124+ double res = 0.0 ;
125+ for (int i = 0 ; i < n; i++) {
126+ double av = raw1 ? a[i] : (a[i] - m1) / sd1;
127+ double b = raw2 ? ts[s2 + i] : (ts[s2 + i] - m2) / sd2;
128+ double d = av - b;
129+ res += d * d;
130+ }
131+ return std::sqrt (res) / n;
132+ }
133+
134+ double znormed_rms_dist_precomputed (
135+ const std::vector<double >& za, const std::vector<double >& zb) {
136+ double res = 0.0 ;
137+ int n = za.size ();
138+ for (int i = 0 ; i < n; i++) {
139+ double d = za[i] - zb[i];
140+ res += d * d;
141+ }
142+ return std::sqrt (res) / n;
143+ }
144+
145+ } // namespace
146+
34147double _normalized_distance (int start1, int end1, int start2, int end2,
35- std::vector<double > *series, double n_threshold){
148+ const std::vector<double >& series, double n_threshold,
149+ int w_size,
150+ const std::vector<std::vector<double >>* znorm_windows) {
36151
37- double res = 0 ;
38152 int len1 = end1 - start1;
39153 int len2 = end2 - start2;
40- int count = std::min (len1, len2);
41-
42- std::vector<double > a, b;
43- if (len1 == len2){
44- a.assign (series->begin () + start1, series->begin () + end1);
45- b.assign (series->begin () + start2, series->begin () + end2);
46- } else if (len1 < len2){
47- a.assign (series->begin () + start1, series->begin () + end1);
48- std::vector<double > longer (series->begin () + start2, series->begin () + end2);
49- b = _paa2 (longer, len1);
50- } else {
51- b.assign (series->begin () + start2, series->begin () + end2);
52- std::vector<double > longer (series->begin () + start1, series->begin () + end1);
53- a = _paa2 (longer, len2);
154+
155+ if (znorm_windows != nullptr && len1 == w_size && len2 == w_size &&
156+ start1 >= 0 && start2 >= 0 &&
157+ start1 < (int )znorm_windows->size () &&
158+ start2 < (int )znorm_windows->size ()) {
159+ return znormed_rms_dist_precomputed (
160+ znorm_windows->at (start1), znorm_windows->at (start2));
54161 }
55162
56- std::vector<double > za = _znorm (a, n_threshold);
57- std::vector<double > zb = _znorm (b, n_threshold);
58- for (int i=0 ; i<count; i++){
59- res = res + (za[i] - zb[i]) * (za[i] - zb[i]);
163+ static thread_local std::vector<double > paa_buf;
164+
165+ if (len1 == len2) {
166+ return znormed_rms_dist_equal (series, start1, end1, start2, end2, n_threshold);
167+ }
168+ if (len1 < len2) {
169+ _paa2_range (series, start2, end2, len1, paa_buf);
170+ return znormed_rms_dist_slice_vec (series, start1, end1, paa_buf, n_threshold);
60171 }
61- return sqrt (res) / (double ) count;
172+ _paa2_range (series, start1, end1, len2, paa_buf);
173+ return znormed_rms_dist_vec_slice (paa_buf, series, start2, end2, n_threshold);
62174}
63175
64176double _shrinked_distance (int start1, int end1, int start2, int end2, std::vector<double > *series){
@@ -98,6 +210,7 @@ rra_discord_record find_best_rra_discord(std::vector<double> *ts, int w_size,
98210 std::unordered_map<int , rule_record> *grammar, std::vector<int > *indexes,
99211 std::vector<rule_interval> *intervals,
100212 std::unordered_set<int > *global_visited_positions, double n_threshold,
213+ const std::vector<std::vector<double >>* znorm_windows,
101214 int seed = -1 ){
102215
103216 // *****
@@ -174,7 +287,8 @@ rra_discord_record find_best_rra_discord(std::vector<double> *ts, int w_size,
174287 // end << std::endl;
175288 distance_calls_counter++;
176289 double dist = _normalized_distance (c_interval.start , c_interval.end ,
177- start, end, ts, n_threshold);
290+ start, end, *ts, n_threshold,
291+ w_size, znorm_windows);
178292 // keep track of best so far distance
179293 if (dist < nn_distance) {
180294 // Rcout << " better nn distance found " << dist << std::endl;
@@ -255,7 +369,8 @@ rra_discord_record find_best_rra_discord(std::vector<double> *ts, int w_size,
255369 distance_calls_counter++;
256370 double dist = _normalized_distance (
257371 c_interval.start , c_interval.end ,
258- randomInterval.start , randomInterval.end , ts, n_threshold
372+ randomInterval.start , randomInterval.end , *ts, n_threshold,
373+ w_size, znorm_windows
259374 );
260375
261376 if (dist < bestSoFarDistance) {
@@ -608,14 +723,21 @@ Rcpp::DataFrame find_discords_rra(NumericVector series, int w_size, int paa_size
608723 std::unordered_set<int > global_visited_positions;
609724 // global_visited_positions.reserve(ts.size());
610725
726+ int n_windows = (int )ts.size () - w_size + 1 ;
727+ std::vector<std::vector<double >> znorm_windows (n_windows);
728+ for (int wi = 0 ; wi < n_windows; wi++) {
729+ _znorm_slice (ts, wi, wi + w_size, n_threshold, znorm_windows[wi]);
730+ }
731+
611732 std::vector<rra_discord_record> discords;
612733
613734 while ((int ) discords.size () < discords_num){
614735
615736 // tstart = std::chrono::system_clock::now();
616737
617738 rra_discord_record d = find_best_rra_discord (&ts, w_size, &grammar,
618- &indexes, &intervals, &global_visited_positions, n_threshold, seed);
739+ &indexes, &intervals, &global_visited_positions, n_threshold,
740+ &znorm_windows, seed);
619741 // Rcout << d.nn_distance;
620742
621743 if (d.nn_distance <0 ){
0 commit comments