1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2018- Stéphane MOTTELET
4  *
5  * This file is hereby licensed under the terms of the GNU GPL v2.0,
6  * For more information, see the COPYING file which you should have received
7  * along with this program.
8  *
9  */
10 
11 #include "double.hxx"
12 #include "function.hxx"
13 #include "int.hxx"
14 #include "overload.hxx"
15 
16 extern "C"
17 {
18 #include "Scierror.h"
19 #include "localization.h"
20 }
21 
22 template<typename T>
convertTypeToInt32(T * pVal)23 int convertTypeToInt32(T* pVal)
24 {
25     typename T::type TVal = pVal->get(0);
26     if (TVal >= INT_MAX)
27     {
28         return INT_MAX;
29     }
30     else
31     {
32         return TVal < 0 ? 0 :  (static_cast<int> (TVal));
33     }
34 }
35 
36 int convertToSize(types::InternalType *pIT);
37 
38 bool fillRange(double* pdblOut, double* pdblMin, double* pdblMax, int iRows, int iCols);
39 
40 /* ==================================================================== */
sci_linspace(types::typed_list & in,int _iRetCount,types::typed_list & out)41 types::Function::ReturnValue sci_linspace(types::typed_list &in, int _iRetCount, types::typed_list &out)
42 {
43     int iCols = 100;
44     types::Double* pDblOut;
45 
46     if (in.size() != 2 && in.size() != 3)
47     {
48         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "linspace", 2, 3);
49         return types::Function::Error;
50     }
51 
52     if (_iRetCount > 1)
53     {
54         Scierror(78, _("%s: Wrong number of output argument(s): %d expected."), "linspace", 1);
55         return types::Function::Error;
56     }
57 
58     types::Double* pDbl[2];
59     for (int i = 0; i < 2; i++)
60     {
61         if (in[i]->isDouble())
62         {
63             pDbl[i] = in[i]->getAs<types::Double>();
64         }
65         else
66         {
67             // other types -> overload
68             std::wstring wstFuncName = L"%" + in[i]->getShortTypeStr() + L"_linspace";
69             return Overload::call(wstFuncName, in, _iRetCount, out);
70         }
71     }
72 
73     // Check dimensions are the same
74     int  iDims0  = pDbl[0]->getDims();
75     int* piDims0 = pDbl[0]->getDimsArray();
76     int  iDims1  = pDbl[1]->getDims();
77     int* piDims1 = pDbl[1]->getDimsArray();
78     if (iDims0 != iDims1)
79     {
80         Scierror(999, _("%s: Arguments %d and %d must have same dimensions.\n"), "linspace", 1, 2);
81         return types::Function::Error;
82     }
83     for (int i = 0; i < iDims0; i++)
84     {
85         if (piDims0[i] != piDims1[i])
86         {
87             Scierror(999, _("%s: Arguments %d and %d must have same dimensions.\n"), "linspace", 1, 2);
88             return types::Function::Error;
89         }
90     }
91 
92     if (in.size() == 3)
93     {
94         if (in[2]->isGenericType() && in[2]->getAs<types::GenericType>()->isScalar() &&
95             (in[2]->isInt() || (in[2]->isDouble() && in[2]->getAs<types::Double>()->isComplex() == false) ))
96         {
97             if (in[2]->isDouble())
98             {
99                 double dblCols = in[2]->getAs<types::Double>()->get(0);
100                 if (std::floor(dblCols) != dblCols)
101                 {
102                     Scierror(999, _("%s: Argument #%d: An integer value expected.\n"), "linspace",3);
103                     return types::Function::Error;
104                 }
105             }
106             iCols = convertToSize(in[2]);
107         }
108         else
109         {
110             Scierror(999, _("%s: Argument #%d: An integer value expected.\n"), "linspace", 3);
111             return types::Function::Error;
112         }
113     }
114 
115     if (iCols == INT_MAX)
116     {
117          Scierror(999, _("%s: Wrong values for input argument #%d: Must be less than %d.\n"),"linspace",3,INT_MAX);
118          return types::Function::Error;
119     }
120 
121     if (iCols == 0 || (pDbl[0]->getSize() == 0))
122     {
123         // empty matrix case
124         out.push_back(types::Double::Empty());
125         return types::Function::OK;
126     }
127 
128     // generation is done by considering array as a column vector
129     int iRows =  pDbl[0]->getSize();
130     // pDblOut is resized later
131     pDblOut = new types::Double(iRows, iCols);
132 
133     if (!fillRange(pDblOut->get(), pDbl[0]->get(), pDbl[1]->get(), iRows, iCols))
134     {
135         // if Infs or NaNs
136         pDblOut->killMe();
137         return types::Function::Error;
138     }
139 
140     if (pDbl[0]->isComplex() || pDbl[1]->isComplex())
141     {
142         int iReal;
143         for (iReal = 0; iReal < 2; iReal++)
144         {
145             if (!pDbl[iReal]->isComplex())
146             {
147                 pDbl[iReal] = pDbl[iReal]->clone();
148                 pDbl[iReal]->setComplex(true);
149                 break;
150             }
151         }
152         // Complexify pDblOut
153         pDblOut->setComplex(true);
154         bool status = fillRange(pDblOut->getImg(), pDbl[0]->getImg(), pDbl[1]->getImg(), iRows, iCols);
155         if (iReal < 2)
156         {
157             pDbl[iReal]->killMe();
158         }
159         if (status != true) // if Infs or NaNs
160         {
161             pDblOut->killMe();
162             return types::Function::Error;
163         }
164     }
165 
166     int *piNewDims = new int[iDims0 + 1];
167     // keep the first dimension unchanged
168     piNewDims[0] = piDims0[0];
169     int iDim = 1;
170     for (int i = 1; i < iDims0; i++)
171     {
172         // squeeze subsequent single dimensions
173         if (piDims0[i] > 1)
174         {
175             piNewDims[iDim++] = piDims0[i];
176         }
177     }
178     // add the suplementary dimension
179     piNewDims[iDim++] = iCols;
180     // reshape the matrix:
181     pDblOut->reshape(piNewDims, iDim);
182     out.push_back(pDblOut);
183 
184     delete[] piNewDims;
185     return types::Function::OK;
186 }
187 
fillRange(double * pdblOut,double * pdblMin,double * pdblMax,int iRows,int iCols)188 bool fillRange(double* pdblOut, double* pdblMin, double* pdblMax, int iRows, int iCols)
189 {
190     double* step = new double[iRows];
191     for (int j = 0, k = (iCols - 1) * iRows; j < iRows; j++)
192     {
193         step[j] = (pdblMax[j] - pdblMin[j]) / (iCols - 1);
194         // checking Infs and NaNs
195         int indInfOrNan = std::isinf(pdblMin[j]) || std::isnan(pdblMin[j]) ? 1 : 0;
196         indInfOrNan = indInfOrNan == 0 ? (std::isinf(pdblMax[j]) || std::isnan(pdblMax[j]) ? 2 : 0) : indInfOrNan;
197         if (indInfOrNan > 0)
198         {
199             delete[] step;
200             Scierror(999, _("%s: Argument #%d: %%nan and %%inf values are forbidden.\n"), "linspace", indInfOrNan);
201             return false;
202         }
203         // last column is enforced (http://bugzilla.scilab.org/10966)
204         pdblOut[k++] = pdblMax[j];
205     }
206     // doing the linear range generation
207     for (int i = 0; i < iCols - 1; i++)
208     {
209         for (int j = 0; j < iRows; j++)
210         {
211             *(pdblOut++) = pdblMin[j] + i * step[j];
212         }
213     }
214     delete[] step;
215 
216     return true;
217 }
218 
convertToSize(types::InternalType * pIT)219 int convertToSize(types::InternalType *pIT)
220 {
221     switch (pIT->getType())
222     {
223         case types::InternalType::ScilabDouble:
224         {
225             return convertTypeToInt32(pIT->getAs<types::Double>());
226         }
227         case types::InternalType::ScilabInt8:
228         {
229             return convertTypeToInt32(pIT->getAs<types::Int8>());
230         }
231         case types::InternalType::ScilabInt16:
232         {
233             return convertTypeToInt32(pIT->getAs<types::Int16>());
234         }
235         case types::InternalType::ScilabInt32:
236         {
237             return convertTypeToInt32(pIT->getAs<types::Int32>());
238         }
239         case types::InternalType::ScilabInt64:
240         {
241             return convertTypeToInt32(pIT->getAs<types::Int64>());
242         }
243         case types::InternalType::ScilabUInt8:
244         {
245             return convertTypeToInt32(pIT->getAs<types::UInt8>());
246         }
247         case types::InternalType::ScilabUInt16:
248         {
249             return convertTypeToInt32(pIT->getAs<types::UInt16>());
250         }
251         case types::InternalType::ScilabUInt32:
252         {
253             return convertTypeToInt32(pIT->getAs<types::UInt32>());
254         }
255         case types::InternalType::ScilabUInt64:
256         {
257             return convertTypeToInt32(pIT->getAs<types::UInt64>());
258         }
259         default:
260             return 0;
261     }
262 }
263 
264