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