b968551e88c66b0ca0b7700a69ac7dbaf62ee5ba
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_MatrixExp.hpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2008-2008 - 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 //file included in runvisitor.cpp
17 namespace ast {
18
19 /*
20     [1,2;3,4] with/without special character $ and :
21     */
22 template<class T>
23 void RunVisitorT<T>::visitprivate(const MatrixExp &e)
24 {
25     CoverageInstance::invokeAndStartChrono((void*)&e);
26     try
27     {
28         exps_t::const_iterator row;
29         exps_t::const_iterator col;
30         types::InternalType *poResult = NULL;
31         std::list<types::InternalType*> rowList;
32
33         exps_t lines = e.getLines();
34         if (lines.size() == 0)
35         {
36             setResult(types::Double::Empty());
37             CoverageInstance::invokeAndStartChrono((void*)&e);
38             return;
39         }
40
41         //special case for 1x1 matrix
42         if (lines.size() == 1)
43         {
44             exps_t cols = lines[0]->getAs<MatrixLineExp>()->getColumns();
45             if (cols.size() == 1)
46             {
47                 setResult(NULL); // Reset value on loop re-start
48
49                 cols[0]->accept(*this);
50                 //manage evstr('//xxx') for example
51                 if (getResult() == NULL)
52                 {
53                     setResult(types::Double::Empty());
54                 }
55                 CoverageInstance::invokeAndStartChrono((void*)&e);
56                 return;
57             }
58         }
59
60         //do all [x,x]
61         for (row = lines.begin(); row != lines.end(); row++)
62         {
63             types::InternalType* poRow = NULL;
64             exps_t cols = (*row)->getAs<MatrixLineExp>()->getColumns();
65             for (col = cols.begin(); col != cols.end(); col++)
66             {
67                 setResult(NULL); // Reset value on loop re-start
68
69                 try
70                 {
71                     (*col)->accept(*this);
72                 }
73                 catch (const InternalError& error)
74                 {
75                     if (poRow)
76                     {
77                         poRow->killMe();
78                     }
79                     if (poResult)
80                     {
81                         poResult->killMe();
82                     }
83
84                     throw error;
85                 }
86
87                 types::InternalType *pIT = getResult();
88                 if (pIT == NULL)
89                 {
90                     continue;
91                 }
92
93                 //reset result but without delete the value
94                 clearResultButFirst();
95
96                 if (pIT->isImplicitList())
97                 {
98                     types::ImplicitList *pIL = pIT->getAs<types::ImplicitList>();
99                     if (pIL->isComputable())
100                     {
101                         types::InternalType* pIT2 = pIL->extractFullMatrix();
102                         pIT->killMe();
103                         pIT = pIT2;
104                     }
105                     else
106                     {
107                         if (poRow == NULL)
108                         {
109                             //first loop
110                             poRow = pIT;
111                         }
112                         else
113                         {
114                             try
115                             {
116                                 poRow = callOverloadMatrixExp(L"c", poRow, pIT);
117                             }
118                             catch (const InternalError& error)
119                             {
120                                 if (poResult)
121                                 {
122                                     poResult->killMe();
123                                 }
124                                 throw error;
125                             }
126                         }
127
128                         continue;
129                     }
130                 }
131
132                 if (pIT->isGenericType() == false)
133                 {
134                     pIT->killMe();
135                     std::wostringstream os;
136                     os << _W("unable to concatenate\n");
137                     throw ast::InternalError(os.str(), 999, (*col)->getLocation());
138                 }
139
140                 types::GenericType* pGT = pIT->getAs<types::GenericType>();
141
142                 if (poRow == NULL)
143                 {
144                     //first loop
145                     if (poResult == NULL && pGT->isDouble() && pGT->getAs<types::Double>()->isEmpty())
146                     {
147                         pGT->killMe();
148                         continue;
149                     }
150
151                     if (pGT->isDouble() && pGT->getAs<types::Double>()->isEmpty())
152                     {
153                         if (poResult && (poResult->isList() || poResult->isStruct()))
154                         {
155                             //in case of [list(); [], ...]
156
157                             //we don't know what to do with [], keep it as "normal" value and continue process
158                             poRow = pGT;
159                             continue;
160                         }
161
162                         pGT->killMe();
163                         continue;
164                     }
165
166                     poRow = pGT;
167                     continue;
168                 }
169
170                 //manage overload on list/struct/implicitlist and hypermatrix before management of []
171                 if (pGT->isList() || poRow->isList() || pGT->isStruct() || poRow->isStruct() || poRow->isImplicitList() || pGT->getDims() > 2)
172                 {
173                     try
174                     {
175                         poRow = callOverloadMatrixExp(L"c", poRow, pGT);
176                     }
177                     catch (const InternalError& error)
178                     {
179                         if (poResult)
180                         {
181                             poResult->killMe();
182                         }
183                         throw error;
184                     }
185
186                     continue;
187                 }
188
189                 if (pGT->isDouble() && pGT->getAs<types::Double>()->isEmpty())
190                 {
191                     pGT->killMe();
192                     continue;
193                 }
194
195                 types::GenericType* pGTResult = poRow->getAs<types::GenericType>();
196
197                 //check dimension
198                 if (pGT->getDims() != 2 || pGT->getRows() != pGTResult->getRows())
199                 {
200                     poRow->killMe();
201                     if (poRow != pGT)
202                     {
203                         pGT->killMe();
204                     }
205                     std::wostringstream os;
206                     os << _W("inconsistent row/column dimensions\n");
207                     throw ast::InternalError(os.str(), 999, (*row)->getLocation());
208                 }
209
210                 // if we concatenate [Double Sparse], transform the Double to Sparse and perform [Sparse Sparse]
211                 // this avoids to allocate a Double result of size of Double+Sparse and initialize all elements.
212                 if (pGT->isSparse() && pGTResult->isDouble())
213                 {
214                     poRow = new types::Sparse(*pGTResult->getAs<types::Double>());
215                     pGTResult->killMe();
216                     pGTResult = poRow->getAs<types::GenericType>();
217                 }
218                 else if (pGT->isSparseBool() && pGTResult->isBool()) // [Bool SparseBool] => [SparseBool SparseBool]
219                 {
220                     poRow = new types::SparseBool(*pGTResult->getAs<types::Bool>());
221                     pGTResult->killMe();
222                     pGTResult = poRow->getAs<types::GenericType>();
223                 }
224                 else if (pGT->isDollar() && pGTResult->isDouble())
225                 {
226                     int _iRows = pGTResult->getRows();
227                     int _iCols = pGTResult->getCols();
228                     int* piRank = new int[_iRows * _iCols];
229                     memset(piRank, 0x00, _iRows * _iCols * sizeof(int));
230                     poRow = new types::Polynom(pGT->getAs<types::Polynom>()->getVariableName(), _iRows, _iCols, piRank);
231                     types::Polynom* pP = poRow->getAs<types::Polynom>();
232                     types::SinglePoly** pSS = pP->get();
233                     types::Double* pDb = pGTResult->getAs<types::Double>();
234                     double* pdblR = pDb->get();
235                     if (pDb->isComplex())
236                     {
237                         double* pdblI = pDb->getImg();
238                         pP->setComplex(true);
239                         for (int i = 0; i < pDb->getSize(); i++)
240                         {
241                             pSS[i]->setRank(0);
242                             pSS[i]->setCoef(pdblR + i, pdblI + i);
243                         }
244                     }
245                     else
246                     {
247                         for (int i = 0; i < pDb->getSize(); i++)
248                         {
249                             pSS[i]->setRank(0);
250                             pSS[i]->setCoef(pdblR + i, NULL);
251                         }
252                     }
253
254                     delete[] piRank;
255                 }
256
257                 types::InternalType *pNewSize = AddElementToVariable(NULL, poRow, pGTResult->getRows(), pGTResult->getCols() + pGT->getCols());
258                 types::InternalType* p = AddElementToVariable(pNewSize, pGT, 0, pGTResult->getCols());
259                 if (p != pNewSize)
260                 {
261                     pNewSize->killMe();
262                 }
263                 // call overload
264                 if (p == NULL)
265                 {
266                     try
267                     {
268                         poRow = callOverloadMatrixExp(L"c", pGTResult, pGT);
269                     }
270                     catch (const InternalError& error)
271                     {
272                         if (poResult)
273                         {
274                             poResult->killMe();
275                         }
276                         throw error;
277                     }
278                     continue;
279                 }
280
281                 if (poRow != pGT)
282                 {
283                     pGT->killMe();
284                 }
285
286                 if (p != poRow)
287                 {
288                     poRow->killMe();
289                     poRow = p;
290                 }
291             }
292
293             if (poRow == NULL)
294             {
295                 continue;
296             }
297
298             if (poResult == NULL)
299             {
300                 poResult = poRow;
301                 continue;
302             }
303
304             // management of concatenation with 1:$
305             if (poRow->isImplicitList() || poResult->isImplicitList())
306             {
307                 try
308                 {
309                     poResult = callOverloadMatrixExp(L"f", poResult, poRow);
310                 }
311                 catch (const InternalError& error)
312                 {
313                     throw error;
314                 }
315                 continue;
316             }
317
318             types::GenericType* pGT = poRow->getAs<types::GenericType>();
319
320             //check dimension
321             types::GenericType* pGTResult = poResult->getAs<types::GenericType>();
322
323             if (pGT->isList() || pGTResult->isList() || pGT->isStruct() || pGTResult->isStruct() || pGT->getDims() > 2)
324             {
325                 try
326                 {
327                     poResult = callOverloadMatrixExp(L"f", pGTResult, pGT);
328                 }
329                 catch (const InternalError& error)
330                 {
331                     throw error;
332                 }
333
334                 continue;
335             }
336             else
337             {//[]
338                 if (pGT->isDouble() && pGT->getAs<types::Double>()->isEmpty())
339                 {
340                     pGT->killMe();
341                     continue;
342                 }
343             }
344
345             //check dimension
346             if (pGT->getCols() != pGTResult->getCols())
347             {
348                 poRow->killMe();
349                 if (poResult)
350                 {
351                     poResult->killMe();
352                 }
353                 std::wostringstream os;
354                 os << _W("inconsistent row/column dimensions\n");
355                 throw ast::InternalError(os.str(), 999, (*e.getLines().begin())->getLocation());
356             }
357
358             // if we concatenate [Double Sparse], transform the Double to Sparse and perform [Sparse Sparse]
359             // this avoids to allocate a Double result of size of Double+Sparse and initialize all elements.
360             if (pGT->isSparse() && pGTResult->isDouble())
361             {
362                 poResult = new types::Sparse(*pGTResult->getAs<types::Double>());
363                 pGTResult->killMe();
364                 pGTResult = poResult->getAs<types::GenericType>();
365             }
366             else if (pGT->isSparseBool() && pGTResult->isBool()) // [Bool SparseBool] => [SparseBool SparseBool]
367             {
368                 poResult = new types::SparseBool(*pGTResult->getAs<types::Bool>());
369                 pGTResult->killMe();
370                 pGTResult = poResult->getAs<types::GenericType>();
371             }
372
373             types::InternalType* pNewSize = AddElementToVariable(NULL, poResult, pGTResult->getRows() + pGT->getRows(), pGT->getCols());
374             types::InternalType* p = AddElementToVariable(pNewSize, pGT, pGTResult->getRows(), 0);
375             if (p != pNewSize)
376             {
377                 pNewSize->killMe();
378             }
379
380             // call overload
381             if (p == NULL)
382             {
383                 try
384                 {
385                     poResult = callOverloadMatrixExp(L"f", pGTResult, pGT);
386                 }
387                 catch (const InternalError& error)
388                 {
389                     throw error;
390                 }
391                 continue;
392             }
393
394             if (poResult != poRow)
395             {
396                 poRow->killMe();
397             }
398
399             if (p != poResult)
400             {
401                 poResult->killMe();
402                 poResult = p;
403             }
404         }
405
406         if (poResult)
407         {
408             setResult(poResult);
409         }
410         else
411         {
412             setResult(types::Double::Empty());
413         }
414     }
415     catch (const InternalError& error)
416     {
417         setResult(NULL);
418         CoverageInstance::invokeAndStartChrono((void*)&e);
419         throw error;
420     }
421     CoverageInstance::invokeAndStartChrono((void*)&e);
422 }
423
424 template<class T>
425 types::InternalType* RunVisitorT<T>::callOverloadMatrixExp(const std::wstring& strType, types::InternalType* _paramL, types::InternalType* _paramR)
426 {
427     types::typed_list in;
428     types::typed_list out;
429     types::Callable::ReturnValue Ret;
430
431     _paramL->IncreaseRef();
432     _paramR->IncreaseRef();
433
434     in.push_back(_paramL);
435     in.push_back(_paramR);
436
437     try
438     {
439         if (_paramR->isGenericType() && _paramR->getAs<types::GenericType>()->getDims() > 2)
440         {
441             Ret = Overload::call(L"%hm_" + strType + L"_hm", in, 1, out, true);
442         }
443         else
444         {
445             Ret = Overload::call(L"%" + _paramL->getAs<types::List>()->getShortTypeStr() + L"_" + strType + L"_" + _paramR->getAs<types::List>()->getShortTypeStr(), in, 1, out, true);
446         }
447     }
448     catch (const InternalError& error)
449     {
450         cleanInOut(in, out);
451         throw error;
452     }
453
454     if (Ret != types::Callable::OK)
455     {
456         cleanInOut(in, out);
457         throw InternalError(ConfigVariable::getLastErrorMessage());
458     }
459
460     cleanIn(in, out);
461
462     if (out.empty())
463     {
464         // TODO: avoid crash if out is empty but must return an error...
465         return NULL;
466     }
467
468     return out[0];
469 }
470
471 } /* namespace ast */