@@ -29,146 +29,54 @@ NumericVector paa(NumericVector ts, int paa_num) {
2929 return wrap (_paa2 (Rcpp::as< std::vector<double > >(ts), paa_num));
3030}
3131
32- std::vector<double > _paa ( std::vector<double > ts, int paa_num) {
32+ std::vector<double > _paa2 ( const std::vector<double >& ts, int paa_num) {
3333
34- // fix the length
3534 int len = ts.size ();
3635
37- // check for the trivial case
38- if (len == paa_num) {
39- std::vector<double > res (ts);
40- return res;
41- }
42- else {
43- // if the number of points in a segment is even
44- if (len % paa_num == 0 ) {
45- std::vector<double > res (paa_num, 0 );
46- int inc = len / paa_num;
47- for (int i = 0 ; i < len; i++) {
48- int idx = i / inc; // the spot
49- res[idx] = res[idx] + ts[i];
50- }
51- double dl = (double ) inc;
52- for (int i = 0 ; i < paa_num; i++) {
53- res[i] = res[i] / dl;
54- }
55- return res;
56- }else {
57- // if the number of points in a segment is odd
58- std::vector<double > res (paa_num);
59- for (int i = 0 ; i < len * paa_num; i++) {
60- int idx = i / len; // the spot
61- int pos = i / paa_num; // the col spot
62- res[idx] = res[idx] + ts[pos];
63- }
64- double dl = (double ) len;
65- for (int i = 0 ; i < paa_num; i++) {
66- res[i] = res[i] / dl;
67- }
68- return res;
69- }
70- }
71- }
72-
73- std::vector<double > _paa2 (std::vector<double > ts, int paa_num) {
74-
75- std::vector<double > tempVector;
76-
77- // fix the length
78- int len = ts.size ();
79- // Rcout << "len " << len << std::endl;
80-
8136 if (len < paa_num){
8237 stop (" 'paa_num' size is invalid" );
8338 }
8439
85- // check for the trivial case
8640 if (len == paa_num) {
87- std::vector<double > res (ts);
88- return res;
41+ return ts;
8942 }
90- else {
9143
92- // Rcpp::Rcout.precision(5 );
93- // Rcout << std::fixed ;
44+ std::vector< double > res (paa_num, 0.0 );
45+ double points_per_segment = ( double ) len / ( double ) paa_num ;
9446
95- std::vector<double > res (paa_num, 0.0 );
96- double points_per_segment = (double ) len / (double ) paa_num;
97- // Rcout << "points per seg " << points_per_segment << std::endl;
47+ std::vector<double > breaks (paa_num + 1 , 0 );
48+ for (int i = 0 ; i < paa_num + 1 ; i++){
49+ breaks[i] = i * points_per_segment;
50+ }
51+ breaks[paa_num] = (double ) len;
9852
99- std::vector<double > breaks (paa_num + 1 , 0 );
100- for (int i = 0 ; i < paa_num + 1 ; i++){
101- breaks[i] = i * points_per_segment;
102- }
103- // The final break is paa_num * (len/paa_num), which should be exactly len
104- // but in IEEE-754 often rounds to len + epsilon (e.g. 7*(29/7) =
105- // 29.000000000000004). That makes floor(seg_end) == len for the last
106- // segment, so frac_end collapses to ~1e-15 and the last sample is dropped
107- // from the segment sum while the divisor stays the same -- corrupting the
108- // final PAA value. Snap it to len so the boundary is handled exactly,
109- // matching the saxpy / Java fractional PAA.
110- breaks[paa_num] = (double ) len;
111- // Rcout << "ts length: " << len << ", breaks: ";
112- // for(auto it=breaks.begin(); it<breaks.end(); ++it){
113- // Rcout << *it << ", ";
114- // }
115- // Rcout << std::endl;
53+ for (int i = 0 ; i < paa_num; i++){
11654
117- for (int i = 0 ; i < paa_num; i++){
55+ double seg_start = breaks[i];
56+ double seg_end = breaks[i+1 ];
11857
119- double seg_start = breaks[i];
120- double seg_end = breaks[i+1 ];
121- // Rcout << " * seg_start " << seg_start << ", end " << seg_end << std::endl;
58+ double frac_begin = ceil (seg_start) - seg_start;
59+ double frac_end = seg_end - floor (seg_end);
12260
123- double frac_begin = ceil (seg_start) - seg_start;
124- double frac_end = seg_end - floor (seg_end);
125- // Rcout << " ** frac_begin " << frac_begin << ", frac_end " << frac_end << std::endl;
61+ int full_begin = (int )floor (seg_start);
62+ int full_end = (int )ceil (seg_end);
63+ if (full_end > len) {
64+ full_end = len;
65+ }
12666
127- int full_begin = floor (seg_start);
128- int full_end = ceil (seg_end);
129- if (full_end > len) {
130- full_end = len;
67+ double sum_of_elems = 0.0 ;
68+ for (int j = full_begin; j < full_end; j++) {
69+ double v = ts[j];
70+ if (j == full_begin && frac_begin > 0 ) {
71+ v *= frac_begin;
13172 }
132- // Rcout << " *** full_begin " << full_begin << ", full_end " << full_end << std::endl;
133-
134- // the following taken from
135- // https://stackoverflow.com/questions/421573/best-way-to-extract-a-subvector-from-a-vector
136- // but it may leak memory?
137- std::vector<double >::const_iterator first = ts.begin () + full_begin;
138- std::vector<double >::const_iterator last = ts.begin () + full_end;
139- std::vector<double > segment (first, last);
140- // std::vector<double> segment(ts.begin() + full_begin, ts.begin() + full_end);
141-
142- // Rcout << "segment ";
143- // for(auto it=segment.begin(); it<segment.end(); ++it){
144- // Rcout << *it << ", ";
145- // }
146- // Rcout << std::endl;
147-
148- if (frac_begin > 0 ){
149- segment[0 ] = segment[0 ] * frac_begin;
73+ if (j == full_end - 1 && frac_end > 0 ) {
74+ v *= frac_end;
15075 }
151-
152- if (frac_end > 0 ){
153- segment[segment.size ()-1 ] = segment[segment.size ()-1 ] * frac_end;
154- }
155- // Rcout << "adj_segment ";
156- // for(auto it=segment.begin(); it<segment.end(); ++it){
157- // Rcout << *it << ", ";
158- // }
159- // Rcout << std::endl;
160-
161- double sum_of_elems = 0.0 ;
162- for (double e : segment)
163- sum_of_elems += e;
164- // Rcout << " **** sum " << sum_of_elems << std::endl;
165-
166- segment.swap (tempVector);
167-
168- res[i] = sum_of_elems / points_per_segment;
169- // Rcout << " **** res[" << i << "] " << res[i] << std::endl;
170-
76+ sum_of_elems += v;
17177 }
172- return res;
78+
79+ res[i] = sum_of_elems / points_per_segment;
17380 }
81+ return res;
17482}
0 commit comments