Merge remote-tracking branch 'origin/master' into windows
[scilab.git] / scilab / modules / boolean / sci_gateway / cpp / sci_find.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - DIGITEO - Antoine ELIAS
4 *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13 *
14 */
15 /*--------------------------------------------------------------------------*/
16
17 #include "boolean_gw.hxx"
18 #include "function.hxx"
19 #include "double.hxx"
20 #include "string.hxx"
21 #include "bool.hxx"
22 #include "sparse.hxx"
23 #include "overload.hxx"
24
25 extern "C"
26 {
27 #include "localization.h"
28 #include "Scierror.h"
29 }
30
31 static void getCoordFromIndex(int _iIndex, int* _piIndexes, int* _piDims, int _iDims);
32 /*--------------------------------------------------------------------------*/
33 types::Function::ReturnValue sci_find(types::typed_list &in, int _iRetCount, types::typed_list &out)
34 {
35     int iMax = -1;
36
37     if (in.size() == 0 || in.size() > 2)
38     {
39         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "find", 1, 2);
40         return types::Function::Error;
41     }
42
43     if (in.size() == 2)
44     {
45         if (in[1]->isDouble() == false || in[1]->getAs<types::Double>()->isScalar() == false)
46         {
47             Scierror(999, _("%s:  Wrong type for input argument #%d: Scalar positive integer expected.\n"), "find", 2);
48             return types::Function::Error;
49         }
50
51         iMax = (int)in[1]->getAs<types::Double>()->get()[0];
52         if (iMax <= 0 && iMax != -1)
53         {
54             Scierror(999, _("%s:  Wrong type for input argument #%d: Scalar positive integer expected.\n"), "find", 2);
55             return types::Function::Error;
56         }
57
58     }
59
60     int* piIndex = 0;
61     int iValues = 0;
62
63     if (in[0]->isGenericType() == false)
64     {
65         //call overload for other types
66         std::string stFuncName = "%" + in[0]->getShortTypeStr() + "_find";
67         return Overload::call(stFuncName, in, _iRetCount, out);
68     }
69
70     types::GenericType* pGT = in[0]->getAs<types::GenericType>();
71     piIndex = new int[pGT->getSize()];
72
73     if (in[0]->isBool())
74     {
75         types::Bool* pB = in[0]->getAs<types::Bool>();
76         int size = pB->getSize();
77         int* p = pB->get();
78         iMax = iMax == -1 ? size : std::min(iMax, size);
79         for (int i = 0 ; i < size && iValues < iMax ; i++)
80         {
81             if (p[i])
82             {
83                 piIndex[iValues] = i;
84                 iValues++;
85             }
86         }
87     }
88     else if (in[0]->isDouble())
89     {
90         types::Double* pD = in[0]->getAs<types::Double>();
91         int size = pD->getSize();
92         double* p = pD->get();
93         iMax = iMax == -1 ? size : std::min(iMax, size);
94         for (int i = 0; i < size && iValues < iMax; i++)
95         {
96             if (p[i])
97             {
98                 piIndex[iValues] = i;
99                 iValues++;
100             }
101         }
102     }
103     else if (in[0]->isSparse())
104     {
105         types::Sparse* pSP = in[0]->getAs<types::Sparse>();
106         int iNNZ = (int)pSP->nonZeros();
107         int iRows = pSP->getRows();
108         int* pRows = new int[iNNZ * 2];
109         pSP->outputRowCol(pRows);
110         int *pCols = pRows + iNNZ;
111         iMax = iMax == -1 ? iNNZ : std::min(iMax, iNNZ);
112
113         for (int i = 0; i < iNNZ && iValues < iMax; i++)
114         {
115             piIndex[iValues] = (pCols[i] - 1) * iRows + (pRows[i] - 1);
116             iValues++;
117         }
118
119         delete[] pRows;
120     }
121     else if (in[0]->isSparseBool())
122     {
123         types::SparseBool* pSB = in[0]->getAs<types::SparseBool>();
124         int iNNZ = (int)pSB->nbTrue();
125         int iRows = pSB->getRows();
126
127         int* pRows = new int[iNNZ * 2];
128         pSB->outputRowCol(pRows);
129         int* pCols = pRows + iNNZ;
130
131         iMax = iMax == -1 ? iNNZ : std::min(iMax, iNNZ);
132         for (int i = 0; i < iNNZ && iValues < iMax; i++)
133         {
134             piIndex[iValues] = (pCols[i] - 1) * iRows + (pRows[i] - 1);
135             iValues++;
136         }
137
138         delete[] pRows;
139     }
140     else
141     {
142         delete[] piIndex;
143
144         //call overload for other types
145         std::string stFuncName = "%" + in[0]->getShortTypeStr() + "_find";
146         return Overload::call(stFuncName, in, _iRetCount, out);
147     }
148
149     if (iValues == 0)
150     {
151         for (int i = 0 ; i < _iRetCount ; i++)
152         {
153             out.push_back(types::Double::Empty());
154         }
155     }
156     else
157     {
158         if (_iRetCount == 1)
159         {
160             types::Double* dbl = new types::Double(1, iValues);
161             double* p = dbl->get();
162
163             for (int i = 0; i < iValues; ++i)
164             {
165                 p[i] = static_cast<double>(piIndex[i]) + 1;
166             }
167
168             delete[] piIndex;
169             out.push_back(dbl);
170             return types::Function::OK;
171         }
172
173         int* piRefDims = pGT->getDimsArray();
174         int iRefDims = pGT->getDims();
175
176         int* piDims = new int[_iRetCount];
177         int iDims = _iRetCount;
178
179         if (iDims == iRefDims)
180         {
181             for (int i = 0 ; i < iRefDims ; i++)
182             {
183                 piDims[i] = piRefDims[i];
184             }
185         }
186         else if (iDims > iRefDims)
187         {
188             for (int i = 0 ; i < iRefDims ; i++)
189             {
190                 piDims[i] = piRefDims[i];
191             }
192
193             for (int i = iRefDims ; i < iDims ; i++)
194             {
195                 piDims[i] = 1;
196             }
197         }
198         else //iDims < iRefDims
199         {
200             for (int i = 0 ; i < iDims - 1 ; i++)
201             {
202                 piDims[i] = piRefDims[i];
203             }
204
205             piDims[iDims - 1] = 1;
206             for (int i = iDims - 1 ; i < iRefDims ; i++)
207             {
208                 piDims[iDims - 1] *= piRefDims[i];
209             }
210         }
211
212         int** piCoord = new int*[iValues];
213         for (int i = 0 ; i < iValues ; i++)
214         {
215             piCoord[i] = new int[_iRetCount];
216         }
217
218         for (int i = 0 ; i < iValues ; i++)
219         {
220             getCoordFromIndex(piIndex[i], piCoord[i], piDims, iDims);
221         }
222
223         for (int i = 0 ; i < _iRetCount ; i++)
224         {
225             types::Double* pOut = new types::Double(1, iValues);
226             for (int j = 0 ; j < iValues ; j++)
227             {
228                 pOut->set(j, piCoord[j][i] + 1);
229             }
230             out.push_back(pOut);
231         }
232
233         delete[] piDims;
234         for (int i = 0 ; i < iValues ; i++)
235         {
236             delete[] piCoord[i];
237         }
238         delete[] piCoord;
239     }
240
241     delete[] piIndex;
242     return types::Function::OK;
243 }
244
245 static void getCoordFromIndex(int _iIndex, int* _piIndexes, int* _piDims, int _iDims)
246 {
247     int iMul = 1;
248     for (int i = 0 ; i < _iDims ; i++)
249     {
250         _piIndexes[i] = (int)(_iIndex / iMul) % _piDims[i];
251         iMul *= _piDims[i];
252     }
253 }
254 /*--------------------------------------------------------------------------*/