elementary_functions module.
[scilab.git] / scilab / modules / elementary_functions / sci_gateway / cpp / sci_max.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - DIGITEO - Cedric DELAMARRE
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12 /*--------------------------------------------------------------------------*/
13 #include "elem_func_gw.hxx"
14 #include "function.hxx"
15 #include "double.hxx"
16 #include "string.hxx"
17 #include "overload.hxx"
18 #include "execvisitor.hxx"
19 #include "max.hxx"
20
21 extern "C"
22 {
23 #include "Scierror.h"
24 #include "localization.h"
25 }
26
27 /*--------------------------------------------------------------------------*/
28 types::Function::ReturnValue sci_max(types::typed_list &in, int _iRetCount, types::typed_list &out)
29 {
30     int iCountElem   = in.size();
31     int iDims        = 0;
32     int* piDimsArray = NULL;
33     int iOrientation = 0;
34     int iLargerInput = 0; // used to know the larger type of inputs arguments (in interger case). max(int16, int32, int8) return an int32
35     int iSigned      = 0; // if one of input arguments is signed the result is signed.
36
37     types::Double* pDblIndex    = NULL;
38     types::Double* pDblOut      = NULL;
39
40     std::vector<types::InternalType*> inputs;
41     std::vector<types::Double*> vectDouble;
42
43     if (in.size() < 1)
44     {
45         ScierrorW(77, _W("%ls: Wrong number of input argument(s): At least %d expected.\n"), L"max", 1);
46         return types::Function::Error;
47     }
48
49     if (_iRetCount > 2)
50     {
51         ScierrorW(78, _W("%ls: Wrong number of output argument(s): %d to %d expected.\n"), L"max", 1, 2);
52         return types::Function::Error;
53     }
54
55     /***** get data *****/
56     if (in.size() == 1 && in[0]->isList())
57     {
58         types::List* pList = in[0]->getAs<types::List>();
59         iCountElem = pList->getSize();
60
61         if (iCountElem == 0)
62         {
63             ScierrorW(999, _W("%ls: Wrong size for input argument #%d: Non empty list expected.\n"), L"max", 1);
64             return types::Function::Error;
65         }
66
67         for (int i = 0; i < iCountElem; i++)
68         {
69             inputs.push_back(pList->get(i)->getAs<types::InternalType>());
70         }
71     }
72     else
73     {
74         inputs = in;
75     }
76
77     if (inputs[0]->isDouble() == false && inputs[0]->isInt() == false)
78     {
79         std::wstring wstFuncName = L"%"  + in[0]->getShortTypeStr() + L"_max";
80         return Overload::call(wstFuncName, in, _iRetCount, out, new ExecVisitor());
81     }
82
83     types::GenericType* pGT = NULL;
84     // get the size of the first input non scalar
85     for (int i = 0; i < inputs.size(); i++)
86     {
87         pGT = inputs[i]->getAs<types::GenericType>();
88         if (pGT->isScalar() == false)
89         {
90             break;
91         }
92     }
93
94     iDims       = pGT->getDims();
95     piDimsArray = pGT->getDimsArray();
96
97     if (pGT->getSize() == 0)
98     {
99         out.push_back(types::Double::Empty());
100         if (_iRetCount == 2)
101         {
102             out.push_back(types::Double::Empty());
103         }
104         return types::Function::OK;
105     }
106
107     if (in.size() == 2)
108     {
109         if (in[1]->isString())
110         {
111             std::wstring wcsOrientation = in[1]->getAs<types::String>()->get(0);
112             if (wcsOrientation == L"r")
113             {
114                 iOrientation = 1;
115             }
116             else if (wcsOrientation == L"c")
117             {
118                 iOrientation = 2;
119             }
120             else if (wcsOrientation == L"m")
121             {
122                 // old function was "mtlsel"
123                 for (int i = 0; i < iDims; i++)
124                 {
125                     if (piDimsArray[i] > 1)
126                     {
127                         iOrientation = i + 1;
128                         break;
129                     }
130                 }
131             }
132             else if (wcsOrientation == L"*")
133             {
134                 iOrientation = 0;
135             }
136             else
137             {
138                 ScierrorW(999, _W("%ls: Wrong value for input argument #%d: r, c, m or * expected.\n"), L"max", 2);
139                 return types::Function::Error;
140             }
141             iCountElem = 1;
142         }
143         //        else if(in[1]->isDouble())
144         //        {
145         //            types::Double* pDbl = in[1]->getAs<types::Double>();
146         //            if(pDbl->isScalar() && in[0]->getAs<types::Double>()->isScalar() == false)
147         //            {
148         //                iOrientation = pDbl->get(0);
149         //                iCountElem = 1;
150         //            }
151         //        }
152
153         inputs = in;
154     }
155
156     if (iOrientation > iDims)
157     {
158         ScierrorW(999, _W("%ls: Wrong value for input argument #%d: value less than or equal to the number of dimension expected.\n"), L"max", 2);
159         return types::Function::Error;
160     }
161
162     for (int i = 0; i < iCountElem; i++)
163     {
164         if (inputs[i]->isDouble() || inputs[i]->isInt())
165         {
166             types::Double* pDbl = NULL;
167             if (inputs[i]->isDouble())
168             {
169                 pDbl = inputs[i]->getAs<types::Double>();
170                 if (pDbl->isComplex())
171                 {
172                     ScierrorW(999, _W("%ls: Wrong type for input argument #%d: A real matrix expected.\n"), L"max", i + 1);
173                     return types::Function::Error;
174                 }
175
176                 iLargerInput = 1000;
177             }
178             else if (inputs[i]->isUInt8())
179             {
180                 types::UInt8* pIIn = inputs[i]->getAs<types::UInt8>();
181                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
182                 for (int i = 0; i < pIIn->getSize(); i++)
183                 {
184                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
185                 }
186
187                 iLargerInput = max(iLargerInput, 8);
188             }
189             else if (inputs[i]->isInt8())
190             {
191                 types::Int8* pIIn = inputs[i]->getAs<types::Int8>();
192                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
193                 for (int i = 0; i < pIIn->getSize(); i++)
194                 {
195                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
196                 }
197
198                 iSigned = 1;
199                 iLargerInput = max(iLargerInput, 8);
200             }
201             else if (inputs[i]->isUInt16())
202             {
203                 types::UInt16* pIIn = inputs[i]->getAs<types::UInt16>();
204                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
205                 for (int i = 0; i < pIIn->getSize(); i++)
206                 {
207                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
208                 }
209
210                 iLargerInput = max(iLargerInput, 16);
211             }
212             else if (inputs[i]->isInt16())
213             {
214                 types::Int16* pIIn = inputs[i]->getAs<types::Int16>();
215                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
216                 for (int i = 0; i < pIIn->getSize(); i++)
217                 {
218                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
219                 }
220
221                 iSigned = 1;
222                 iLargerInput = max(iLargerInput, 16);
223             }
224             else if (inputs[i]->isUInt32())
225             {
226                 types::UInt32* pIIn = inputs[i]->getAs<types::UInt32>();
227                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
228                 for (int i = 0; i < pIIn->getSize(); i++)
229                 {
230                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
231                 }
232
233                 iLargerInput = max(iLargerInput, 32);
234             }
235             else if (inputs[i]->isInt32())
236             {
237                 types::Int32* pIIn = inputs[i]->getAs<types::Int32>();
238                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
239                 for (int i = 0; i < pIIn->getSize(); i++)
240                 {
241                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
242                 }
243
244                 iSigned = 1;
245                 iLargerInput = max(iLargerInput, 32);
246             }
247             else if (inputs[i]->isUInt64())
248             {
249                 types::UInt64* pIIn = inputs[i]->getAs<types::UInt64>();
250                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
251                 for (int i = 0; i < pIIn->getSize(); i++)
252                 {
253                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
254                 }
255
256                 iLargerInput = max(iLargerInput, 64);
257             }
258             else if (inputs[i]->isInt64())
259             {
260                 types::Int64* pIIn = inputs[i]->getAs<types::Int64>();
261                 pDbl = new types::Double(pIIn->getDims(), pIIn->getDimsArray());
262                 for (int i = 0; i < pIIn->getSize(); i++)
263                 {
264                     pDbl->set(i, static_cast<double>(pIIn->get(i)));
265                 }
266
267                 iSigned = 1;
268                 iLargerInput = max(iLargerInput, 64);
269             }
270
271             if (pDbl->isScalar())
272             {
273                 vectDouble.push_back(pDbl);
274             }
275             else if (iDims != pDbl->getDims())
276             {
277                 ScierrorW(999, _W("%ls: Wrong size for input argument #%d: All arguments must have the same size.\n"), L"max", i + 1);
278                 return types::Function::Error;
279             }
280             else
281             {
282                 int* iCurrentDimsArray = pDbl->getDimsArray();
283                 for (int iterDims = 0; iterDims < iDims; iterDims++)
284                 {
285                     if (iCurrentDimsArray[iterDims] != piDimsArray[iterDims])
286                     {
287                         ScierrorW(999, _W("%ls: Wrong size for input argument #%d: All arguments must have the same size.\n"), L"max", i + 1);
288                         return types::Function::Error;
289                     }
290                 }
291
292                 vectDouble.push_back(pDbl);
293             }
294         }
295         else
296         {
297             ScierrorW(999, _W("%ls: Wrong type for input argument #%d: A matrix expected.\n"), L"max", i + 1);
298             return types::Function::Error;
299         }
300     }
301
302     /***** perform operation and set result *****/
303     int* iSizes = NULL;
304     int iSize   = 2;
305
306     if (iCountElem == 1)
307     {
308         if (iOrientation)
309         {
310             iSize = iDims;
311             iSizes = new int[iDims];
312             memcpy(iSizes, piDimsArray, iDims * sizeof(int));
313             iSizes[iOrientation - 1] = 1;
314         }
315         else
316         {
317             iSizes = new int[2];
318             iSizes[0] = 1;
319             iSizes[1] = 1;
320         }
321     }
322     else
323     {
324         iSize = iDims;
325         iSizes = piDimsArray;
326     }
327
328     if (_iRetCount == 2)
329     {
330         if (iCountElem == 1 && iOrientation == 0)
331         {
332             int iCols = iDims;
333             if (iDims == 2 && (piDimsArray[0] == 1 || piDimsArray[1] == 1)) // vector case, return index in scalar
334             {
335                 iCols = 1;
336             }
337
338             pDblIndex = new types::Double(1, iCols);
339         }
340         else
341         {
342             pDblIndex = new types::Double(iSize, iSizes);
343         }
344     }
345
346     pDblOut = new types::Double(iSize, iSizes);
347     max(vectDouble, iOrientation, pDblIndex, pDblOut);
348     // if all inputs are integers return an integer
349     switch (iLargerInput)
350     {
351         case 8 :
352         {
353             if (iSigned)
354             {
355                 types::Int8* pIIn = new types::Int8(pDblOut->getDims(), pDblOut->getDimsArray());
356                 for (int i = 0; i < pDblOut->getSize(); i++)
357                 {
358                     pIIn->set(i, static_cast<char>(pDblOut->get(i)));
359                 }
360                 out.push_back(pIIn);
361             }
362             else
363             {
364                 types::UInt8* pIIn = new types::UInt8(pDblOut->getDims(), pDblOut->getDimsArray());
365                 for (int i = 0; i < pDblOut->getSize(); i++)
366                 {
367                     pIIn->set(i, static_cast<unsigned char>(pDblOut->get(i)));
368                 }
369                 out.push_back(pIIn);
370             }
371             delete pDblOut;
372             pDblOut = NULL;
373             break;
374         }
375         case 16 :
376         {
377             if (iSigned)
378             {
379                 types::Int16* pIIn = new types::Int16(pDblOut->getDims(), pDblOut->getDimsArray());
380                 for (int i = 0; i < pDblOut->getSize(); i++)
381                 {
382                     pIIn->set(i, static_cast<short>(pDblOut->get(i)));
383                 }
384                 out.push_back(pIIn);
385             }
386             else
387             {
388                 types::UInt16* pIIn = new types::UInt16(pDblOut->getDims(), pDblOut->getDimsArray());
389                 for (int i = 0; i < pDblOut->getSize(); i++)
390                 {
391                     pIIn->set(i, static_cast<unsigned short>(pDblOut->get(i)));
392                 }
393                 out.push_back(pIIn);
394             }
395             delete pDblOut;
396             pDblOut = NULL;
397             break;
398         }
399         case 32 :
400         {
401             if (iSigned)
402             {
403                 types::Int32* pIIn = new types::Int32(pDblOut->getDims(), pDblOut->getDimsArray());
404                 for (int i = 0; i < pDblOut->getSize(); i++)
405                 {
406                     pIIn->set(i, static_cast<int>(pDblOut->get(i)));
407                 }
408                 out.push_back(pIIn);
409             }
410             else
411             {
412                 types::UInt32* pIIn = new types::UInt32(pDblOut->getDims(), pDblOut->getDimsArray());
413                 for (int i = 0; i < pDblOut->getSize(); i++)
414                 {
415                     pIIn->set(i, static_cast<unsigned int>(pDblOut->get(i)));
416                 }
417                 out.push_back(pIIn);
418             }
419             delete pDblOut;
420             pDblOut = NULL;
421             break;
422         }
423         case 64 :
424         {
425             if (iSigned)
426             {
427                 types::Int64* pIIn = new types::Int64(pDblOut->getDims(), pDblOut->getDimsArray());
428                 for (int i = 0; i < pDblOut->getSize(); i++)
429                 {
430                     pIIn->set(i, static_cast<long long>(pDblOut->get(i)));
431                 }
432                 out.push_back(pIIn);
433             }
434             else
435             {
436                 types::UInt64* pIIn = new types::UInt64(pDblOut->getDims(), pDblOut->getDimsArray());
437                 for (int i = 0; i < pDblOut->getSize(); i++)
438                 {
439                     pIIn->set(i, static_cast<unsigned long long>(pDblOut->get(i)));
440                 }
441                 out.push_back(pIIn);
442             }
443             delete pDblOut;
444             pDblOut = NULL;
445             break;
446         }
447         default :
448             out.push_back(pDblOut);
449     }
450
451     if (_iRetCount == 2)
452     {
453         out.push_back(pDblIndex);
454     }
455
456     if (iCountElem == 1)
457     {
458         delete iSizes;
459         iSizes = NULL;
460     }
461
462     return types::Function::OK;
463 }
464 /*--------------------------------------------------------------------------*/