2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006/2007 - INRIA - Alan LAYEC
4 * Copyright (C) 2007 - INRIA - Allan CORNET
5 * Copyright (C) 2012 - DIGITEO - Allan CORNET
6 * Copyright (C) 2012 - INRIA - Serge STEER
8 * This file must be used under the terms of the CeCILL.
9 * This source file is licensed as described in the file COPYING, which
10 * you should have received as part of this distribution. The terms
11 * are also available at
12 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
15 /*--------------------------------------------------------------------------*/
17 #include "fftw_utilities.h"
21 #include "api_scilab.h"
22 #include "localization.h"
25 /*--------------------------------------------------------------------------*/
32 /*--------------------------------------------------------------------------*/
33 extern void C2F(dscal)(int *n, double *da, double *dx, int *incx); /* blas routine */
34 extern void C2F(dset)(int *n, double *da, double *dx, int *incx); /* blas routine */
35 /*--------------------------------------------------------------------------*/
36 static int getArrayOfDouble(void* pvApiCtx, int *piAddr, int *ndims, int **dims, double **Ar, double **Ai);
37 static SciErr allocArrayOfDouble(void* _pvCtx, int _iVar, int ndims, int *dims, double **Ar);
38 static SciErr allocComplexArrayOfDouble(void* _pvCtx, int _iVar, int ndims, int *dims, double **Ar, double **Ai);
39 static SciErr getScalarIntArg(void* _pvCtx, int _iVar, char *fname, int *value);
40 static SciErr getVectorIntArg(void* _pvCtx, int _iVar, char *fname, int *pndims, int **pDim);
41 static BOOL isHyperMatrixMlist(void* _pvCtx, int *piAddressVar);
42 static int sci_fft_gen(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt, guru_dim_struct gdim);
43 static int sci_fft_2args(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt);
44 static int sci_fft_3args(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt);
45 static int sci_fft_4args(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt);
46 /*--------------------------------------------------------------------------*/
51 * Scilab Calling sequence :
53 * fftw(A,sign [,option])
54 * fftw(A,sel,sign [,option])
55 * fftw(A,sign,dim,incr [,option])
57 * Input : A : a scilab double complex or real vector, matrix or hypermatrix
59 * sign : a scilab double or integer scalar (-1 or 1): the sign
60 * in the exponential component
62 * sel : a scilab double or integer vector, the selection of dimensions
64 * dim : a scilab double or integer vector: the dimensions
65 * of the Fast Fourier Transform to perform
67 * incr : a scilab double or integer vector: the increments
68 * of the Fast Fourier Transform to perform
70 * Output : a scilab double complex or real array with same shape as A that
71 * gives the result of the transform.
74 int sci_fftw(char *fname, unsigned long fname_len)
79 int iopt = 0; /* automatic r2c or c2r transform use decision */
85 double *Ar = NULL, *Ai = NULL;
87 int isn = FFTW_FORWARD;
89 /****************************************
90 * Basic constraints on rhs arguments *
91 ****************************************/
93 /* check min/max lhs/rhs arguments of scilab function */
97 sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
100 printError(&sciErr, 0);
101 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, 1);
105 sciErr = getVarType(pvApiCtx, piAddr, &iTypeOne);
108 printError(&sciErr, 0);
109 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, 1);
113 if ((iTypeOne == sci_list) ||
114 (iTypeOne == sci_tlist))
120 if (iTypeOne == sci_mlist)
122 /* We allow overload for not hypermatrix type */
123 if (!isHyperMatrixMlist(pvApiCtx, piAddr))
130 /* checking if last argument is a potential option argument (character string) */
131 sciErr = getVarAddressFromPosition(pvApiCtx, Rhs, &piAddr);
134 printError(&sciErr, 0);
135 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, Rhs);
139 if (isStringType(pvApiCtx, piAddr)) /* fftw(...,option); */
141 if (isScalar(pvApiCtx, piAddr))
143 if (getAllocatedSingleString(pvApiCtx, piAddr, &option) == 0)
145 if (strcmp("symmetric", option) == 0) iopt = 1; /*user assumes symmetry */
146 else if (strcmp("nonsymmetric", option) == 0) iopt = 2; /*user claims full transform */
149 Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"),
150 fname, Rhs, "\"symmetric\"", "\"nonsymmetric\"");
151 freeAllocatedSingleString(option);
155 freeAllocatedSingleString(option);
161 Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"),
162 fname, Rhs, "\"full\", \"same\"", "\"valid\"");
169 /******************** Checking if isn is given ************************************************/
170 if (rhs == 1) /*only one rhs argument: forward fft*/
172 isn = FFTW_FORWARD; /* default value */
174 else /*get isn out of second argument*/
176 sciErr = getScalarIntArg(pvApiCtx, 2, fname, &isn);
179 Scierror(sciErr.iErr, getErrorMessage(sciErr));
182 /* check value of second rhs argument */
183 if ((isn != FFTW_FORWARD) && (isn != FFTW_BACKWARD))
185 Scierror(53, _("%s: Wrong value for input argument #%d: %d or %d expected.\n"),
186 fname, 2, FFTW_FORWARD, FFTW_BACKWARD);
191 /******************** getting the array A ************************************************/
192 getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
193 if (!getArrayOfDouble(pvApiCtx, piAddr, &ndimsA, &dimsA, &Ar, &Ai))
195 Scierror(999, _("%s: Wrong type for argument #%d: Array of floating point numbers expected.\n"),
201 /******************** Select proper method ************************************************/
204 /* fftw(A ,sign [,option])*/
205 sci_fft_2args(pvApiCtx, fname, ndimsA, dimsA, Ar, Ai, isn, iopt);
209 /* fftw(A ,sign ,sel [,option])*/
210 sci_fft_3args(pvApiCtx, fname, ndimsA, dimsA, Ar, Ai, isn, iopt);
214 /* fftw(A ,sign ,dim,incr [option])*/
215 sci_fft_4args(pvApiCtx, fname, ndimsA, dimsA, Ar, Ai, isn, iopt);
221 /*--------------------------------------------------------------------------*/
222 int getArrayOfDouble(void* _pvCtx, int *piAddr, int *ndims, int **dims, double **Ar, double **Ai)
225 int *piAddrChild = NULL;
226 int *piOffset = NULL;
233 sciErr = getVarType(_pvCtx, piAddr, &iType);
234 if (iType == sci_matrix)
237 *dims = &(piAddr[1]);
238 if (isVarComplex(_pvCtx, piAddr))
240 getComplexMatrixOfDouble(_pvCtx, piAddr, &iRows, &iCols, Ar, Ai);
244 getMatrixOfDouble(_pvCtx, piAddr, &iRows, &iCols, Ar);
249 else if (iType == sci_mlist)
251 sciErr = getListItemNumber(_pvCtx, piAddr, &nItems);
252 if (nItems != 3) return 0;
253 /*Check if first item is ["hm","dims","entries"] */
254 sciErr = getListItemAddress(_pvCtx, piAddr, 1, &piAddrChild);
255 sciErr = getVarType(_pvCtx, piAddrChild, &iType);
256 if (iType != sci_strings) return 0;
257 sciErr = getVarDimension(_pvCtx, piAddrChild, &iRows, &iCols);
258 if (iRows*iCols != 3) return 0;
259 /* Check if first entry of the first item is "hm" */
260 piOffset = piAddrChild + 4;
261 if (piOffset[1] - piOffset[0] != 2) return 0;
262 piData = piOffset + iRows * iCols + 1;
263 if (piData[0] != 17 || piData[1] != 22) return 0; /* check "hm" */
264 /* Get second item dims */
265 sciErr = getListItemAddress(_pvCtx, piAddr, 2, &piAddrChild);
266 sciErr = getVarType(_pvCtx, piAddrChild, &iType);
267 if (iType != sci_ints) return 0;
268 sciErr = getMatrixOfInteger32(_pvCtx, piAddrChild, &iRows, &iCols, dims);
269 if (sciErr.iErr) return 0;
270 *ndims = iRows * iCols;
271 /* Get thirds item entries */
272 sciErr = getListItemAddress(_pvCtx, piAddr, 3, &piAddrChild);
273 sciErr = getVarType(_pvCtx, piAddrChild, &iType);
274 if (iType != sci_matrix) return 0;
275 if (isVarComplex(_pvCtx, piAddrChild))
277 getComplexMatrixOfDouble(_pvCtx, piAddrChild, &iRows, &iCols, Ar, Ai);
281 getMatrixOfDouble(_pvCtx, piAddrChild, &iRows, &iCols, Ar);
292 SciErr allocComplexArrayOfDouble(void* _pvCtx, int _iVar, int ndims, int *dims, double **Ar, double **Ai)
299 sciErr = allocComplexMatrixOfDouble( _pvCtx, _iVar, dims[0], dims[1], Ar, Ai);
300 if (sciErr.iErr) return sciErr;
306 const char * hmType[] = {"hm", "dims", "entries"};
308 for (i = 0; i < ndims; i++) n *= dims[i];
310 sciErr = createMList(_pvCtx, _iVar, 3, &piAddr);
311 if (sciErr.iErr) return sciErr;
313 sciErr = createMatrixOfStringInList(_pvCtx, _iVar, piAddr, 1, 1, 3, hmType);
314 if (sciErr.iErr) return sciErr;
315 sciErr = createMatrixOfInteger32InList(_pvCtx, _iVar, piAddr, 2, 1, ndims, dims);
316 if (sciErr.iErr) return sciErr;
318 sciErr = allocComplexMatrixOfDoubleInList(_pvCtx, _iVar, piAddr, 3, n, 1, Ar, Ai);
319 if (sciErr.iErr) return sciErr;
324 SciErr allocArrayOfDouble(void* _pvCtx, int _iVar, int ndims, int *dims, double **Ar)
332 sciErr = allocMatrixOfDouble( _pvCtx, _iVar, dims[0], dims[1], Ar);
333 if (sciErr.iErr) return sciErr;
339 const char * hmType[] = {"hm", "dims", "entries"};
341 for (i = 0; i < ndims; i++) n *= dims[i];
343 sciErr = createMList(_pvCtx, _iVar, 3, &piAddr);
344 if (sciErr.iErr) return sciErr;
345 sciErr = createMatrixOfStringInList(_pvCtx, _iVar, piAddr, 1, 1, 3, hmType);
346 if (sciErr.iErr) return sciErr;
347 sciErr = createMatrixOfInteger32InList(_pvCtx, _iVar, piAddr, 2, 1, ndims, dims);
348 if (sciErr.iErr) return sciErr;
350 sciErr = allocMatrixOfDoubleInList(_pvCtx, _iVar, piAddr, 3, n, 1, Ar);
351 if (sciErr.iErr) return sciErr;
356 SciErr getScalarIntArg(void* _pvCtx, int _iVar, char *fname, int *value)
364 unsigned char t_uc = 0;
366 unsigned short t_us = 0;
368 unsigned int t_ui = 0;
370 sciErr.iMsgCount = 0;
372 sciErr = getVarAddressFromPosition(_pvCtx, _iVar, &piAddr);
375 addErrorMessage(&sciErr, API_ERROR_GET_STRING, _("%s: Can not read input argument #%d.\n"), fname, _iVar);
380 sciErr = getVarType(_pvCtx, piAddr, &iType);
383 addErrorMessage(&sciErr, API_ERROR_GET_INT, _("%s: Can not read input argument #%d.\n"), fname, _iVar);
387 if (!isScalar(_pvCtx, piAddr))
389 addErrorMessage(&sciErr, API_ERROR_GET_INT, _("%s: Wrong size for input argument #%d: A scalar expected.\n"), fname, _iVar);
393 if (iType == sci_matrix)
395 getScalarDouble(_pvCtx, piAddr, &t_d);
398 else if (iType == sci_ints)
400 sciErr = getMatrixOfIntegerPrecision(_pvCtx, piAddr, &iPrec);
403 addErrorMessage(&sciErr, API_ERROR_GET_INT, _("%s: Can not read input argument #%d.\n"), fname, _iVar);
411 getScalarInteger8(_pvCtx, piAddr, &t_c);
416 getScalarInteger16(_pvCtx, piAddr, &t_s);
421 getScalarInteger32(_pvCtx, piAddr, &t_i);
426 getScalarUnsignedInteger8(_pvCtx, piAddr, &t_uc);
431 getScalarUnsignedInteger16(_pvCtx, piAddr, &t_us);
436 getScalarUnsignedInteger32(_pvCtx, piAddr, &t_ui);
443 addErrorMessage(&sciErr, API_ERROR_GET_INT,
444 _("%s: Wrong type for argument #%d: An integer or a floating point number expected.\n"),
451 SciErr getVectorIntArg(void* _pvCtx, int _iVar, char *fname, int *pndims, int **pDim)
464 unsigned char* p_uc = NULL;
466 unsigned short* p_us = NULL;
468 unsigned int* p_ui = NULL;
472 sciErr.iMsgCount = 0;
474 getVarAddressFromPosition(_pvCtx, _iVar, &piAddr);
477 getVarType(_pvCtx, piAddr, &iType);
479 if (isVarMatrixType(_pvCtx, piAddr) == 0)
481 addErrorMessage(&sciErr, API_ERROR_GET_INT, _("%s: Wrong type for input argument #%d.\n"), fname, _iVar);
485 getVarDimension(_pvCtx, piAddr, &mDim, &nDim);
491 addErrorMessage(&sciErr, API_ERROR_GET_INT,
492 _("%s: Wrong size for input argument #%d.\n"), fname, _iVar);
495 if ((Dim = (int *)MALLOC(ndims * sizeof(int))) == NULL)
497 addErrorMessage(&sciErr, API_ERROR_GET_INT,
498 _("%s: Cannot allocate more memory.\n"), fname);
502 if (iType == sci_matrix)
504 sciErr = getMatrixOfDouble(_pvCtx, piAddr, &mDim, &nDim, &p_d);
505 for (i = 0; i < ndims; i++) Dim[i] = (int)(p_d[i]);
507 else if (iType == sci_ints)
509 getMatrixOfIntegerPrecision(_pvCtx, piAddr, &iPrec);
513 getMatrixOfInteger8(_pvCtx, piAddr, &mDim, &nDim, &p_c);
514 for (i = 0; i < ndims; i++) Dim[i] = (int)(p_c[i]);
517 getMatrixOfInteger16(_pvCtx, piAddr, &mDim, &nDim, &p_s);
518 for (i = 0; i < ndims; i++) Dim[i] = (int)(p_s[i]);
521 getMatrixOfInteger32(_pvCtx, piAddr, &mDim, &nDim, &p_i);
522 for (i = 0; i < ndims; i++) Dim[i] = (int)(p_i[i]);
525 getMatrixOfUnsignedInteger8(_pvCtx, piAddr, &mDim, &nDim, &p_uc);
526 for (i = 0; i < ndims; i++) Dim[i] = (int)(p_uc[i]);
529 getMatrixOfUnsignedInteger16(_pvCtx, piAddr, &mDim, &nDim, &p_us);
530 for (i = 0; i < ndims; i++) Dim[i] = (int) p_us[i];
533 getMatrixOfUnsignedInteger32(_pvCtx, piAddr, &mDim, &nDim, &p_ui);
534 for (i = 0; i < ndims; i++) Dim[i] = (int)(p_ui[i]);
542 addErrorMessage(&sciErr, API_ERROR_GET_INT,
543 _("%s: Wrong type for argument #%d: An array of floating point or integer numbers expected.\n"), fname, _iVar);
549 int sci_fft_2args(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt)
551 /*FFTW specific library variable */
552 guru_dim_struct gdim = {0, NULL, 0, NULL};
555 int ndims = 0; /* number of non singleton dimensions */
556 int first_nonsingleton = -1;
560 /* ignore singleton dimensions */
561 first_nonsingleton = -1;
563 for (i = 0; i < ndimsA; i++)
568 if (first_nonsingleton < 0) first_nonsingleton = i;
572 /* void or scalar input gives void output or scalar*/
575 AssignOutputVariable(_pvCtx, 1) = 1;
576 ReturnArguments(_pvCtx);
581 if ((gdim.dims = (fftw_iodim *)MALLOC(sizeof(fftw_iodim) * gdim.rank)) == NULL)
583 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
589 for (i = (first_nonsingleton); i < ndimsA; i++)
593 gdim.dims[j].n = dimsA[i];
594 gdim.dims[j].is = prd;
595 gdim.dims[j].os = prd;
600 gdim.howmany_rank = 0;
601 gdim.howmany_dims = NULL;
604 if (!sci_fft_gen(_pvCtx, fname, ndimsA, dimsA, Ar, Ai, isn, iopt, gdim)) goto ERR;
607 /***********************************
608 * Return results in lhs argument *
609 ***********************************/
611 ReturnArguments(_pvCtx);
614 FREE(gdim.howmany_dims);
619 int sci_fft_3args(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt)
628 /*FFTW specific library variable */
629 guru_dim_struct gdim = {0, NULL, 0, NULL};
632 int first_nonsingleton = -1;
634 int pd = 1; /* used to store prod(Dims(1:sel(k-1)))*/
635 int pds = 1; /* used to store prod(Dims(sel(k-1):sel(k)))*/
638 /* ignore singleton dimensions */
639 first_nonsingleton = -1;
641 for (i = 0; i < ndimsA; i++)
646 if (first_nonsingleton < 0) first_nonsingleton = i;
650 /* void or scalar input gives void output or scalar*/
653 AssignOutputVariable(_pvCtx, 1) = 1;
654 ReturnArguments(_pvCtx);
659 /******************** get and check third argument (sel) ****************************************/
660 getVarAddressFromPosition(pvApiCtx, 3, &piAddr);
661 if (isVarMatrixType(pvApiCtx, piAddr) == 0)
663 Scierror(999, _("%s: Wrong type for input argument #%d.\n"), fname, 3);
666 sciErr = getVectorIntArg(pvApiCtx, 3, fname, &rank, &Sel);
669 Scierror(sciErr.iErr, getErrorMessage(sciErr));
672 /* size of Sel must be less than ndimsA */
673 if (rank <= 0 || rank >= ndimsA)
675 Scierror(999, _("%s: Wrong size for input argument #%d: Must be between %d and %d.\n"), fname, 3, 1, ndimsA - 1);
678 /* check values of Sel[i] */
679 for (i = 0; i < rank; i++)
683 Scierror(999, _("%s: Wrong values for input argument #%d: Positive integers expected.\n"), fname, 3);
688 Scierror(999, _("%s: Wrong values for input argument #%d: Elements must be less than %d.\n"), fname, 3, ndimsA);
691 if (i > 0 && Sel[i] <= Sel[i - 1])
693 Scierror(999, _("%s: Wrong values for input argument #%d: Elements must be in increasing order.\n"), fname, 3);
698 /* Create gdim struct */
700 if ((gdim.dims = (fftw_iodim *)MALLOC(sizeof(fftw_iodim) * gdim.rank)) == NULL)
702 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
706 pd = 1; /* used to store prod(Dims(1:sel(k-1)))*/
707 pds = 1; /* used to store prod(Dims(sel(k-1):sel(k)))*/
709 for (i = 0; i < ndimsA; i++)
711 if (j >= gdim.rank) break;
714 gdim.dims[j].n = dimsA[i];
715 gdim.dims[j].is = pd;
716 gdim.dims[j].os = pd;
721 /* Compute howmany_rank based on jumps in the Sel sequence */
722 gdim.howmany_rank = 0;
723 if ((Sel[0] != 1) && (Sel[0] != ndimsA)) gdim.howmany_rank++;
725 for (i = 1; i <= rank - 1; i++)
726 if (Sel[i] != Sel[i - 1] + 1) gdim.howmany_rank++;
728 if ((Sel[rank - 1] != ndimsA) || (rank == 1)) gdim.howmany_rank++;
730 /* Fill the howmany_dims struct */
731 if (gdim.howmany_rank > 0)
733 /* it must be the case */
734 if ((gdim.howmany_dims = (fftw_iodim *)MALLOC(gdim.howmany_rank * sizeof(fftw_iodim))) == NULL)
736 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
740 for (j = 1; j <= (Sel[0] - 1); j++) pd *= dimsA[j - 1]; /*prod(Dims(1:(sel(1)-1)))*/
742 if ((Sel[0] != 1) && (Sel[0] != ndimsA))
744 /* First seleted dimension */
745 gdim.howmany_dims[ih].is = 1;
746 gdim.howmany_dims[ih].os = 1;
747 gdim.howmany_dims[ih].n = pd;
750 pd *= dimsA[Sel[0] - 1]; /*prod(Dims(1:sel(1)))*/
751 for (i = 2; i <= rank; i++)
753 /* intermediate selected dimensions */
754 if (Sel[i - 1] != Sel[i - 2] + 1)
757 for (j = (Sel[i - 2] + 1); j <= (Sel[i - 1] - 1); j++) pds *= dimsA[j - 1]; /*prod(Dims(sel(i-1)+1:(sel(i)-1)))*/
758 gdim.howmany_dims[ih].is = pd;
759 gdim.howmany_dims[ih].os = pd;
760 gdim.howmany_dims[ih].n = pds;
763 pd *= pds * dimsA[Sel[i - 1] - 1]; /*prod(Dims(1:sel(i)))*/
766 if (Sel[rank - 1] != ndimsA)
768 /* last selected dimension*/
770 for (j = (Sel[rank - 1] + 1); j <= ndimsA; j++) pds *= dimsA[j - 1]; /*prod(Dims(sel(i-1)+1:(sel(i)-1)))*/
771 gdim.howmany_dims[ih].is = pd;
772 gdim.howmany_dims[ih].os = pd;
773 gdim.howmany_dims[ih].n = pds;
778 /* the only selected dimension is the last one */
779 gdim.howmany_dims[ih].is = 1;
780 gdim.howmany_dims[ih].os = 1;
781 gdim.howmany_dims[ih].n = pd / dimsA[Sel[0] - 1];
786 if (!sci_fft_gen(_pvCtx, fname, ndimsA, dimsA, Ar, Ai, isn, iopt, gdim)) goto ERR;
787 /***********************************
788 * Return results in lhs argument *
789 ***********************************/
791 ReturnArguments(_pvCtx);
794 FREE(gdim.howmany_dims);
798 int sci_fft_4args(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt)
804 /* Input array variables */
810 /*FFTW specific library variable */
811 guru_dim_struct gdim = {0, NULL, 0, NULL};
812 /* input/output address for transform variables */
815 int *Dim = NULL, *Sel = NULL;
820 int i = 0, j = 0, k = 0, lA = 1;
822 for (i = 0; i < ndimsA; i++)
827 /* void or scalar input gives void output or scalar*/
830 AssignOutputVariable(_pvCtx, 1) = 1;
831 ReturnArguments(_pvCtx);
835 /******************** get and check third argument (dim) ****************************************/
836 getVarAddressFromPosition(pvApiCtx, 3, &piAddr);
837 if (isVarMatrixType(pvApiCtx, piAddr) == 0)
839 Scierror(999, _("%s: Wrong type for input argument #%d.\n"), fname, 3);
842 sciErr = getVectorIntArg(pvApiCtx, 3, fname, &ndims, &Dim1);
845 Scierror(sciErr.iErr, getErrorMessage(sciErr));
848 /* check values of Dim1[i} */
850 for (i = 0; i < ndims; i++)
854 Scierror(999, _("%s: Wrong values for input argument #%d: Elements must be greater than %d.\n"), fname, 3, 1);
861 Scierror(999, _("%s: Wrong values for input argument #%d: Must be less than %d.\n"), fname, 3, lA);
866 Scierror(999, _("%s: Wrong values for input argument #%d: Must be a divisor of %d.\n"), fname, 3, lA);
869 /******************** get and check fourth argument (incr) ****************************************/
870 sciErr = getVectorIntArg(pvApiCtx, 4, fname, &nincr, &Incr);
873 Scierror(sciErr.iErr, getErrorMessage(sciErr));
878 Scierror(999, _("%s: Incompatible input arguments #%d and #%d: Same sizes expected.\n"), fname, 3, 4);
882 /* check values of Incr[i] */
885 Scierror(999, _("%s: Wrong values for input argument #%d: Positive integers expected.\n"), fname, 4);
888 for (i = 0; i < ndims; i++)
892 Scierror(999, _("%s: Wrong values for input argument #%d: Elements must be divisors of %d.\n"), fname, 3, lA);
895 if (i > 0 && (Incr[i] <= Incr[i - 1]))
897 Scierror(999, _("%s: Wrong values for input argument #%d: Elements must be in increasing ""order.\n"), fname, 4);
901 if ((Dim = (int *)MALLOC((2 * ndims + 1) * sizeof(int))) == NULL)
903 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
906 if ((Sel = (int *)MALLOC((ndims) * sizeof(int))) == NULL)
908 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
913 /*Transform Dim1 and Incr into Dim and Sel and check validity*/
926 for (k = 1; k < ndims; k++)
928 if (Incr[k] % pd != 0)
930 Scierror(999, _("%s: Incompatible input arguments #%d and #%d.\n"), fname, 3, 4);
935 Dim[nd++] = (int)(Incr[k] / pd);
946 Scierror(999, _("%s: Incompatible input arguments #%d and #%d.\n"), fname, 3, 4);
949 Dim[nd++] = (int)(lA / pd);
955 /* now one same algorithm than sci_fft_3args applies */
956 /* Create gdim struct */
958 if ((gdim.dims = (fftw_iodim *)MALLOC(sizeof(fftw_iodim) * gdim.rank)) == NULL)
960 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
964 pd = 1; /* used to store prod(Dims(1:sel(k-1)))*/
965 pds = 1; /* used to store prod(Dims(sel(k-1):sel(k)))*/
967 for (i = 0; i < ndims; i++)
969 if (j >= gdim.rank) break;
972 gdim.dims[j].n = Dim[i];
973 gdim.dims[j].is = pd;
974 gdim.dims[j].os = pd;
979 /* Compute howmany_rank based on jumps in the Sel sequence */
980 gdim.howmany_rank = 0;
981 if ((Sel[0] != 1) && (Sel[0] != ndims)) gdim.howmany_rank++;
983 for (i = 1; i <= rank - 1; i++)
985 if (Sel[i] != Sel[i - 1] + 1) gdim.howmany_rank++;
987 if ((Sel[rank - 1] != ndims) || (rank == 1)) gdim.howmany_rank++;
988 /* Fill the howmany_dims struct */
989 if (gdim.howmany_rank > 0)
991 /* it must be the case */
994 if ((gdim.howmany_dims = (fftw_iodim *)MALLOC(gdim.howmany_rank * sizeof(fftw_iodim))) == NULL)
996 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1000 for (j = 1; j <= (Sel[0] - 1); j++) pd *= Dim[j - 1]; /*prod(Dims(1:(sel(1)-1)))*/
1002 if ((Sel[0] != 1) && (Sel[0] != ndims))
1004 /* First seleted dimension */
1005 gdim.howmany_dims[ih].is = 1;
1006 gdim.howmany_dims[ih].os = 1;
1007 gdim.howmany_dims[ih].n = pd;
1010 pd *= Dim[Sel[0] - 1]; /*prod(Dims(1:sel(1)))*/
1011 for (i = 2; i <= rank; i++)
1013 /* intermediate selected dimensions */
1014 if (Sel[i - 1] != Sel[i - 2] + 1)
1017 for (j = (Sel[i - 2] + 1); j <= (Sel[i - 1] - 1); j++) pds *= Dim[j - 1]; /*prod(Dims(sel(i-1)+1:(sel(i)-1)))*/
1018 gdim.howmany_dims[ih].is = pd;
1019 gdim.howmany_dims[ih].os = pd;
1020 gdim.howmany_dims[ih].n = pds;
1023 pd *= pds * Dim[Sel[i - 1] - 1]; /*prod(Dims(1:sel(i)))*/
1026 if (Sel[rank - 1] != ndims)
1028 /* last selected dimension*/
1030 for (j = (Sel[rank - 1] + 1); j <= ndims; j++) pds *= Dim[j - 1]; /*prod(Dims(sel(i-1)+1:(sel(i)-1)))*/
1031 gdim.howmany_dims[ih].is = pd;
1032 gdim.howmany_dims[ih].os = pd;
1033 gdim.howmany_dims[ih].n = pds;
1036 else if (rank == 1) /* the only selected dimension is the last one */
1038 gdim.howmany_dims[ih].is = 1;
1039 gdim.howmany_dims[ih].os = 1;
1040 gdim.howmany_dims[ih].n = pd / Dim[Sel[0] - 1];
1044 if (!sci_fft_gen(_pvCtx, fname, ndimsA, dimsA, Ar, Ai, isn, iopt, gdim)) goto ERR;
1046 /***********************************
1047 * Return results in lhs argument *
1048 ***********************************/
1050 ReturnArguments(_pvCtx);
1057 FREE(gdim.howmany_dims);
1060 /*--------------------------------------------------------------------------*/
1061 BOOL isHyperMatrixMlist(void* _pvCtx, int *piAddressVar)
1063 char **fields = NULL;
1068 if (piAddressVar == NULL)
1073 sciErr = getVarType(_pvCtx, piAddressVar, &iType);
1079 if (iType == sci_mlist)
1081 int* piAddrChild = NULL;
1084 sciErr = getListItemNumber(pvApiCtx, piAddressVar, &iItem);
1090 sciErr = getListItemAddress(pvApiCtx, piAddressVar, 1, &piAddrChild);
1096 if (!isStringType(_pvCtx, piAddrChild))
1101 if (getAllocatedMatrixOfString(_pvCtx, piAddrChild, &m, &n , &fields) == 0)
1103 if (strcmp(fields[0], "hm") != 0)
1105 freeAllocatedMatrixOfString(m, n, fields);
1109 freeAllocatedMatrixOfString(m, n, fields);
1120 /*--------------------------------------------------------------------------*/
1121 int sci_fft_gen(void* _pvCtx, char *fname, int ndimsA, int *dimsA, double *Ar, double *Ai, int isn, int iopt, guru_dim_struct gdim)
1126 /* Input array variables */
1127 int isrealA = (Ai == NULL), issymA = 1, lA = 1;
1129 int isrealA_save = isrealA ;
1131 /*FFTW specific library variable */
1132 enum Scaling scale = None;
1133 enum Plan_Type type;
1136 /* input/output address for transform variables */
1137 double *ri = NULL, *ii = NULL, *ro = NULL, *io = NULL;
1140 /* local variable */
1145 for (i = 0; i < ndimsA; i++)
1153 /* automatically selected algorithm*/
1154 issymA = check_array_symmetry(Ar, Ai, gdim);
1157 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1164 issymA = 1; /* user forces symmetry */
1171 AssignOutputVariable(_pvCtx, 1) = 1;/* assume inplace transform*/
1178 /*MKL does not implement the r2c nor r2r guru split methods, make A complex */
1181 /* result will be real, the imaginary part of A can be allocated alone */
1182 sciErr = allocMatrixOfDouble(pvApiCtx, *getNbInputArgument(_pvCtx) + 1, 1, lA, &Ai);
1185 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1188 C2F(dset)(&lA, &dzero, Ai, &one);
1192 /* result will be complex, realloc A for inplace computation */
1193 sciErr = allocComplexArrayOfDouble(pvApiCtx, *getNbInputArgument(_pvCtx) + 1, ndimsA, dimsA, &ri, &Ai);
1196 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1199 C2F(dcopy)(&lA, Ar, &one, ri, &one);
1201 C2F(dset)(&lA, &dzero, Ai, &one);
1202 AssignOutputVariable(_pvCtx, 1) = nbInputArgument(_pvCtx) + 1;
1208 if (!isrealA && issymA) /* A is complex but result is real */
1210 /* result will be complex, realloc real part of A for real part inplace computation */
1211 sciErr = allocArrayOfDouble(pvApiCtx, *getNbInputArgument(_pvCtx) + 1, ndimsA, dimsA, &ri);
1214 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1217 C2F(dcopy)(&lA, Ar, &one, ri, &one);
1219 AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(_pvCtx) + 1;
1222 /* Set pointers on real and imaginary part of the input */
1226 scale = None; /*no scaling needed */
1227 if (isn == FFTW_BACKWARD) scale = Divide;
1228 if (isrealA & !WITHMKL) /* To have type = C2C_PLAN*/
1233 /*r2r = isrealA && issymA*/
1234 /* there is no general plan able to compute r2r transform so it is tranformed into
1235 a R2c plan. The computed imaginary part will be zero*/
1236 sciErr = allocMatrixOfDouble(pvApiCtx, *getNbInputArgument(_pvCtx) + 1, 1, lA, &io);
1239 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1247 /*r2c = isrealA && ~issymA;*/
1248 /* transform cannot be done in place */
1249 sciErr = allocComplexArrayOfDouble(pvApiCtx, *getNbInputArgument(_pvCtx) + 1, ndimsA, dimsA, &ro, &io);
1252 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1255 AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(_pvCtx) + 1;
1256 type = R2C_PLAN; /* fftw_plan_guru_split_dft_r2c plans for an FFTW_FORWARD transform*/
1257 if (isn == FFTW_BACKWARD)
1259 /*transform problem into a FORWARD fft*/
1260 /*ifft(A)=conj(fft(A/N)) cas vect*/
1261 /* pre traitement A must be divided by N cas vect*/
1262 /* post treatment result must conjugated */
1269 if (!WITHMKL && issymA) /*result is real*/
1271 /*c2r = ~isrealA && issymA*/
1275 type = C2R_PLAN; /*fftw_plan_guru_split_dft_c2r plans for an FFTW_BACKWARD transform*/
1276 if (isn == FFTW_FORWARD)
1278 /*transform problem into a BACKWARD fft : fft(A)=ifft(conj(A))*/
1279 double minusone = -1.0;
1280 C2F(dscal)(&lA, &minusone, ii, &one);
1285 /*c2c = ~isrealA && ~issymA;*/
1286 /* use inplace transform*/
1288 type = C2C_PLAN; /* fftw_plan_guru_split_dft plans for an FFTW_FORWARD transform*/
1289 if (isn == FFTW_BACKWARD)
1291 /*transform problem into a FORWARD fft*/
1292 /* ifft(A) = %i*conj(fft(%i*conj(A)/N) */
1296 /* reverse output */
1308 p = GetFFTWPlan(type, &gdim, ri, ii, ro, io, getCurrentFftwFlags(), isn);
1311 Scierror(999, _("%s: No more memory.\n"), fname);
1318 for (i = 0; i < gdim.rank; i++) ak = ak * ((double)(gdim.dims[i].n));
1319 if (scale == Divide) ak = 1.0 / ak;
1320 C2F(dscal)(&lA, &ak, ri, &one);
1321 if (isrealA == 0) C2F(dscal)(&lA, &ak, ii, &one);
1323 /* execute FFTW plan */
1324 ExecuteFFTWPlan(type, p, ri, ii, ro, io);
1325 /* Post treatment */
1329 if (complete_array(ro, NULL, gdim) == -1)
1331 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1340 /*R2C has been used to solve an r2r problem*/
1341 if (complete_array(ro, NULL, gdim) == -1)
1343 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1349 if (complete_array(ro, io, gdim) == -1)
1351 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1354 if (isn == FFTW_BACKWARD)
1356 /*conjugate result */
1358 C2F(dscal)(&lA, &ak, io, &one);
1363 if (WITHMKL && isrealA_save)
1365 if (isn == FFTW_FORWARD)
1367 if (complete_array(ro, io, gdim) == -1)
1369 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
1375 if (complete_array(io, ro, gdim) == -1)
1377 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);