1 /*
2 * R : A Computer Language for Statistical Data Analysis
3 * Copyright (C) 1998--2020 The R Core Team
4 * Copyright (C) 1995--1997 Robert Gentleman and Ross Ihaka
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, a copy is available at
18 * https://www.R-project.org/Licenses/
19 */
20
21 /* These are the R interface routines to the plain FFT code
22 fft_factor() & fft_work() in fft.c. */
23
24 #include <inttypes.h>
25 // for PRIu64
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <Defn.h>
32
33 #undef _
34 #ifdef ENABLE_NLS
35 #include <libintl.h>
36 #define _(String) dgettext ("stats", String)
37 #else
38 #define _(String) (String)
39 #endif
40
41
42 // workhorse routines from fft.c
43 void fft_factor(int n, int *pmaxf, int *pmaxp);
44 Rboolean fft_work(double *a, double *b, int nseg, int n, int nspn,
45 int isn, double *work, int *iwork);
46
47 #include "statsR.h"
48
49 /* Fourier Transform for Univariate Spatial and Time Series */
50
fft(SEXP z,SEXP inverse)51 SEXP fft(SEXP z, SEXP inverse)
52 {
53 SEXP d;
54 int i, inv, maxf, maxmaxf, maxmaxp, maxp, n, ndims, nseg, nspn;
55 double *work;
56 int *iwork;
57 size_t smaxf;
58 size_t maxsize = ((size_t) -1) / 4;
59
60 switch (TYPEOF(z)) {
61 case INTSXP:
62 case LGLSXP:
63 case REALSXP:
64 z = coerceVector(z, CPLXSXP);
65 break;
66 case CPLXSXP:
67 if (MAYBE_REFERENCED(z)) z = duplicate(z);
68 break;
69 default:
70 error(_("non-numeric argument"));
71 }
72 PROTECT(z);
73
74 /* -2 for forward transform, complex values */
75 /* +2 for backward transform, complex values */
76
77 inv = asLogical(inverse);
78 if (inv == NA_INTEGER || inv == 0)
79 inv = -2;
80 else
81 inv = 2;
82
83 if (LENGTH(z) > 1) {
84 if (isNull(d = getAttrib(z, R_DimSymbol))) { /* temporal transform */
85 n = length(z);
86 fft_factor(n, &maxf, &maxp);
87 if (maxf == 0)
88 error(_("fft factorization error"));
89 smaxf = maxf;
90 if (smaxf > maxsize)
91 error("fft too large");
92 work = (double*)R_alloc(4 * smaxf, sizeof(double));
93 iwork = (int*)R_alloc(maxp, sizeof(int));
94 fft_work(&(COMPLEX(z)[0].r), &(COMPLEX(z)[0].i),
95 1, n, 1, inv, work, iwork);
96 }
97 else { /* spatial transform */
98 maxmaxf = 1;
99 maxmaxp = 1;
100 ndims = LENGTH(d);
101 /* do whole loop just for error checking and maxmax[fp] .. */
102 for (i = 0; i < ndims; i++) {
103 if (INTEGER(d)[i] > 1) {
104 fft_factor(INTEGER(d)[i], &maxf, &maxp);
105 if (maxf == 0)
106 error(_("fft factorization error"));
107 if (maxf > maxmaxf)
108 maxmaxf = maxf;
109 if (maxp > maxmaxp)
110 maxmaxp = maxp;
111 }
112 }
113 smaxf = maxmaxf;
114 if (smaxf > maxsize)
115 error("fft too large");
116 work = (double*)R_alloc(4 * smaxf, sizeof(double));
117 iwork = (int*)R_alloc(maxmaxp, sizeof(int));
118 nseg = LENGTH(z);
119 n = 1;
120 nspn = 1;
121 for (i = 0; i < ndims; i++) {
122 if (INTEGER(d)[i] > 1) {
123 nspn *= n;
124 n = INTEGER(d)[i];
125 nseg /= n;
126 fft_factor(n, &maxf, &maxp);
127 fft_work(&(COMPLEX(z)[0].r), &(COMPLEX(z)[0].i),
128 nseg, n, nspn, inv, work, iwork);
129 }
130 }
131 }
132 }
133 UNPROTECT(1);
134 return z;
135 }
136
137 /* Fourier Transform for Vector-Valued ("multivariate") Series */
138 /* Not to be confused with the spatial case (in do_fft). */
139
mvfft(SEXP z,SEXP inverse)140 SEXP mvfft(SEXP z, SEXP inverse)
141 {
142 SEXP d;
143 int i, inv, maxf, maxp, n, p;
144 double *work;
145 int *iwork;
146 size_t smaxf;
147 size_t maxsize = ((size_t) -1) / 4;
148
149 d = getAttrib(z, R_DimSymbol);
150 if (d == R_NilValue || length(d) > 2)
151 error(_("vector-valued (multivariate) series required"));
152 n = INTEGER(d)[0];
153 p = INTEGER(d)[1];
154
155 switch(TYPEOF(z)) {
156 case INTSXP:
157 case LGLSXP:
158 case REALSXP:
159 z = coerceVector(z, CPLXSXP);
160 break;
161 case CPLXSXP:
162 if (MAYBE_REFERENCED(z)) z = duplicate(z);
163 break;
164 default:
165 error(_("non-numeric argument"));
166 }
167 PROTECT(z);
168
169 /* -2 for forward transform, complex values */
170 /* +2 for backward transform, complex values */
171
172 inv = asLogical(inverse);
173 if (inv == NA_INTEGER || inv == 0) inv = -2;
174 else inv = 2;
175
176 if (n > 1) {
177 fft_factor(n, &maxf, &maxp);
178 if (maxf == 0)
179 error(_("fft factorization error"));
180 smaxf = maxf;
181 if (smaxf > maxsize)
182 error("fft too large");
183 work = (double*)R_alloc(4 * smaxf, sizeof(double));
184 iwork = (int*)R_alloc(maxp, sizeof(int));
185 for (i = 0; i < p; i++) {
186 fft_factor(n, &maxf, &maxp);
187 fft_work(&(COMPLEX(z)[i*n].r), &(COMPLEX(z)[i*n].i),
188 1, n, 1, inv, work, iwork);
189 }
190 }
191 UNPROTECT(1);
192 return z;
193 }
194
ok_n(int n,const int f[],int nf)195 static Rboolean ok_n(int n, const int f[], int nf)
196 {
197 for (int i = 0; i < nf; i++) {
198 while(n % f[i] == 0) {
199 if ((n = n / f[i]) == 1)
200 return TRUE;
201 }
202 }
203 return n == 1;
204 }
ok_n_64(uint64_t n,const int f[],int nf)205 static Rboolean ok_n_64(uint64_t n, const int f[], int nf)
206 {
207 for (int i = 0; i < nf; i++) {
208 while(n % f[i] == 0) {
209 if ((n = n / f[i]) == 1)
210 return TRUE;
211 }
212 }
213 return n == 1;
214 }
215
nextn0(int n,const int f[],int nf)216 static int nextn0(int n, const int f[], int nf)
217 {
218 while(!ok_n(n, f, nf) && n < INT_MAX)
219 n++;
220 if(n >= INT_MAX) {
221 warning(_("nextn() found no solution < %d = INT_MAX (the maximal integer);"
222 " pass '0+ n' instead of 'n'"), // i.e. pass "double" type
223 INT_MAX);
224 return NA_INTEGER;
225 } else
226 return n;
227 }
nextn0_64(uint64_t n,const int f[],int nf)228 static uint64_t nextn0_64(uint64_t n, const int f[], int nf)
229 {
230 while(!ok_n_64(n, f, nf) && n < UINT64_MAX)
231 n++;
232 if(n >= UINT64_MAX) { // or give an error? previously was much more problematic
233 warning(_("nextn<64>() found no solution < %ld = UINT64_MAX (the maximal integer)"),
234 UINT64_MAX);
235 return 0; // no NA for this type
236 } else // FIXME: R has no 64 int --> The caller may *not* be able to coerce to REALSXP
237 return n;
238 }
239
240
nextn(SEXP n,SEXP f)241 SEXP nextn(SEXP n, SEXP f)
242 {
243 if(TYPEOF(n) == NILSXP) // NULL <==> integer(0) :
244 return allocVector(INTSXP, 0);
245 int nprot = 0;
246 if(TYPEOF(f) != INTSXP) { PROTECT(f = coerceVector(f, INTSXP)); nprot++; }
247 int nf = LENGTH(f), *f_ = INTEGER(f);
248 /* check the factors */
249 if (nf == 0) error(_("no factors"));
250 if (nf < 0) error(_("too many factors")); // < 0 : from integer overflow
251 for (int i = 0; i < nf; i++)
252 if (f_[i] == NA_INTEGER || f_[i] <= 1)
253 error(_("invalid factors"));
254
255 Rboolean use_int = TYPEOF(n) == INTSXP;
256 if(!use_int && TYPEOF(n) != REALSXP)
257 error(_("'n' must have typeof(.) \"integer\" or \"double\""));
258 R_xlen_t nn = XLENGTH(n);
259 if(!use_int && nn) {
260 double *d_n = REAL(n), n_max = -1; // := max_i n[i]
261 for (R_xlen_t i = 0; i < nn; i++) {
262 if (!ISNAN(d_n[i]) && d_n[i] > n_max) n_max = d_n[i];
263 }
264 if(n_max <= INT_MAX / f_[0]) { // maximal n[] should not be too large to find "next n"
265 use_int = TRUE;
266 n = PROTECT(n = coerceVector(n, INTSXP)); nprot++;
267 }
268 }
269 SEXP ans = PROTECT(allocVector(use_int ? INTSXP : REALSXP, nn)); nprot++;
270 if(nn == 0) {
271 UNPROTECT(nprot);
272 return(ans);
273 }
274 if(use_int) {
275 int *n_ = INTEGER(n),
276 *r = INTEGER(ans);
277 for (R_xlen_t i = 0; i < nn; i++) {
278 if (n_[i] == NA_INTEGER)
279 r[i] = NA_INTEGER;
280 else if (n_[i] <= 1)
281 r[i] = 1;
282 else
283 r[i] = nextn0(n_[i], f_, nf);
284 }
285 } else { // use "double" (as R has no int64 ..)
286 double
287 *n_ = REAL(n),
288 *r = REAL(ans);
289 for (R_xlen_t i = 0; i < nn; i++) {
290 if (ISNAN(n_[i]))
291 r[i] = NA_REAL;
292 else if (n_[i] <= 1)
293 r[i] = 1;
294 else {
295 const uint64_t max_dbl_int = 9007199254740992L; // = 2^53
296 uint64_t n_n = nextn0_64((uint64_t)n_[i], f_, nf);
297 if(n_n > max_dbl_int)
298 warning(_("nextn() = %" PRIu64
299 " > 2^53 may not be exactly representable in R (as \"double\")"),
300 n_n);
301 r[i] = (double) n_n;
302 }
303 }
304 }
305 UNPROTECT(nprot);
306 return ans;
307 }
308