elementary_functions: fix invalid uninit error
[scilab.git] / scilab / modules / elementary_functions / sci_gateway / cpp / sci_permute.cpp
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 <numeric>
12 #include "double.hxx"
13 #include "int.hxx"
14 #include "polynom.hxx"
15 #include "cell.hxx"
16 #include "struct.hxx"
17 #include "function.hxx"
18 #include "overload.hxx"
19
20 extern "C"
21 {
22 #include "Scierror.h"
23 #include "localization.h"
24 }
25
26 void computeOffsets(int iDims, const int* piDimsArray, const std::vector<int>& dimsVect, int* piOffset, int* piMaxOffset)
27 {
28     int iOffset = 1;
29     for (int i = 0; i < iDims; ++i)
30     {
31         int j = dimsVect[i] - 1;
32         piOffset[j] = iOffset;
33         piMaxOffset[j] = iOffset * piDimsArray[j];
34         iOffset *= piDimsArray[dimsVect[i] - 1];
35     }
36 }
37
38 template <typename T>
39 T *doNativePermute(T *pIn, const std::vector<int>& dimsVect)
40 {
41     int iDims = pIn->getDims();
42     int* piDimsArray = pIn->getDimsArray();
43     int* piIndex = new int[iDims]();
44     int* piOffset = new int[iDims];
45     int* piMaxOffset = new int[iDims];
46
47     computeOffsets(iDims, piDimsArray, dimsVect, piOffset, piMaxOffset);
48
49     T* pOut = pIn->clone();
50     typename T::type* pout = pOut->get();
51
52     if (pIn->isComplex())
53     {
54         typename T::type* poutImg = pOut->getImg();
55         for (typename T::type *pin = pIn->get(), *pinImg = pIn->getImg(); pin < pIn->get() + pIn->getSize(); pin++, pinImg++)
56         {
57             *pout = *pin;
58             *poutImg = *pinImg;
59             for (int j = 0; j < iDims; j++)
60             {
61                 ++piIndex[j];
62                 pout += piOffset[j];
63                 poutImg += piOffset[j];
64                 if (piIndex[j] < piDimsArray[j])
65                 {
66                     break;
67                 }
68
69                 pout -= piMaxOffset[j];
70                 poutImg -= piMaxOffset[j];
71                 piIndex[j] = 0;
72             }
73         }
74     }
75     else
76     {
77         for (typename T::type *pin = pIn->get(); pin < pIn->get() + pIn->getSize(); pin++)
78         {
79             *pout = *pin;
80             for (int j = 0; j < iDims; j++)
81             {
82                 ++piIndex[j];
83                 pout += piOffset[j];
84                 if (piIndex[j] < piDimsArray[j])
85                 {
86                     break;
87                 }
88
89                 pout -= piMaxOffset[j];
90                 piIndex[j] = 0;
91             }
92         }
93     }
94
95     delete[] piIndex;
96     delete[] piOffset;
97     delete[] piMaxOffset;
98
99     return pOut;
100 }
101
102 template <typename T>
103 T* doPermute(T* pIn, const std::vector<int>& dimsVect)
104 {
105     int iDims = pIn->getDims();
106     int* piDimsArray = pIn->getDimsArray();
107     int* piOffset = new int[iDims];
108     int* piMaxOffset = new int[iDims];
109     int* piIndex = new int[iDims]();
110
111     computeOffsets(iDims, piDimsArray, dimsVect, piOffset, piMaxOffset);
112
113     T* pOut = pIn->clone();
114
115     for (int iSource = 0, iDest = 0; iSource < pIn->getSize(); iSource++)
116     {
117         pOut->set(iDest, pIn->get(iSource));
118         for (int j = 0; j < iDims; j++)
119         {
120             ++piIndex[j];
121             iDest += piOffset[j];
122             if (piIndex[j] < piDimsArray[j])
123             {
124                 break;
125             }
126
127             iDest -= piMaxOffset[j];
128             piIndex[j] = 0;
129         }
130     }
131
132     delete[] piIndex;
133     delete[] piOffset;
134     delete[] piMaxOffset;
135
136     return pOut;
137 }
138
139 types::Function::ReturnValue sci_permute(types::typed_list& in, int _iRetCount, types::typed_list& out)
140 {
141     if (in.size() != 2)
142     {
143         Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "permute", 2);
144         return types::Function::Error;
145     }
146
147     if (_iRetCount > 1)
148     {
149         Scierror(78, _("%s: Wrong number of output argument(s): %d expected."), "permute", 1);
150         return types::Function::Error;
151     }
152
153     if (in[0]->isArrayOf() == false)
154     {
155         std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_permute";
156         return Overload::call(wstFuncName, in, _iRetCount, out);
157     }
158
159     types::GenericType* pIn = in[0]->getAs<types::GenericType>();
160     types::GenericType* pDims = in[1]->getAs<types::GenericType>();
161
162     int iDims = pIn->getDims();
163     int* piDimsArray = pIn->getDimsArray();
164     int iNewDims = pDims->getSize();
165     int* piNewDimsArray = NULL;
166     std::vector<int> dimsVect;
167
168     if ((iNewDims >= iDims) & pDims->isDouble() & !pDims->getAs<types::Double>()->isComplex())
169     {
170         // Check if 2nd argument is a permutation of [1..iNewDims]
171         types::Double* pDbl = pDims->getAs<types::Double>();
172         std::vector<double> sortedNewDimsVect(pDbl->get(), pDbl->get() + iNewDims);
173         std::sort(sortedNewDimsVect.begin(), sortedNewDimsVect.end());
174         std::vector<double> rangeVect(iNewDims);
175         std::iota(rangeVect.begin(), rangeVect.end(), 1.0);
176
177         if (sortedNewDimsVect == rangeVect)
178         {
179             piNewDimsArray = new int[iNewDims];
180             for (int i = 0; i < iNewDims; i++)
181             {
182                 int j = (int)pDbl->get(i);
183                 piNewDimsArray[i] = 1;
184                 if (j <= iDims)
185                 {
186                     piNewDimsArray[i] = piDimsArray[j - 1];
187                     dimsVect.push_back(j);
188                 }
189             }
190         }
191     }
192
193     if (dimsVect.empty())
194     {
195         delete[] piNewDimsArray;
196         Scierror(78, _("%s: Wrong value for input argument #%d: Must be a valid permutation of [1..n>%d] integers.\n"), "permute", 2, iDims - 1);
197         return types::Function::Error;
198     }
199
200     types::GenericType *pOut;
201
202     switch (in[0]->getType())
203     {
204         case types::InternalType::ScilabDouble:
205         {
206             pOut = doNativePermute(in[0]->getAs<types::Double>(), dimsVect);
207             break;
208         }
209         case types::InternalType::ScilabUInt64:
210         {
211             pOut = doNativePermute(in[0]->getAs<types::UInt64>(), dimsVect);
212             break;
213         }
214         case types::InternalType::ScilabInt64:
215         {
216             pOut = doNativePermute(in[0]->getAs<types::Int64>(), dimsVect);
217             break;
218         }
219         case types::InternalType::ScilabUInt32:
220         {
221             pOut = doNativePermute(in[0]->getAs<types::UInt32>(), dimsVect);
222             break;
223         }
224         case types::InternalType::ScilabInt32:
225         {
226             pOut = doNativePermute(in[0]->getAs<types::Int32>(), dimsVect);
227             break;
228         }
229         case types::InternalType::ScilabUInt16:
230         {
231             pOut = doNativePermute(in[0]->getAs<types::UInt16>(), dimsVect);
232             break;
233         }
234         case types::InternalType::ScilabInt16:
235         {
236             pOut = doNativePermute(in[0]->getAs<types::Int16>(), dimsVect);
237             break;
238         }
239         case types::InternalType::ScilabUInt8:
240         {
241             pOut = doNativePermute(in[0]->getAs<types::UInt8>(), dimsVect);
242             break;
243         }
244         case types::InternalType::ScilabInt8:
245         {
246             pOut = doNativePermute(in[0]->getAs<types::Int8>(), dimsVect);
247             break;
248         }
249         case types::InternalType::ScilabBool:
250         {
251             pOut = doNativePermute(in[0]->getAs<types::Bool>(), dimsVect);
252             break;
253         }
254         case types::InternalType::ScilabString:
255         {
256             pOut = doPermute(in[0]->getAs<types::String>(), dimsVect);
257             break;
258         }
259         case types::InternalType::ScilabPolynom:
260         {
261             pOut = doPermute(in[0]->getAs<types::Polynom>(), dimsVect);
262             break;
263         }
264         case types::InternalType::ScilabStruct:
265         {
266             pOut = doPermute(in[0]->getAs<types::Struct>(), dimsVect);
267             break;
268         }
269         case types::InternalType::ScilabCell:
270         {
271             pOut = doPermute(in[0]->getAs<types::Cell>(), dimsVect);
272             break;
273         }
274         default:
275         {
276             delete[] piNewDimsArray;
277             std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_permute";
278             return Overload::call(wstFuncName, in, _iRetCount, out);
279         }
280     }
281
282     pOut->reshape(piNewDimsArray, iNewDims);
283
284     delete[] piNewDimsArray;
285
286     out.push_back(pOut);
287
288     return types::Function::OK;
289 }