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