7707eb3919e197a393327047fc84acd3f1b1e41d
[scilab.git] / scilab / modules / ast / src / cpp / analysis / IndexAnalyzer.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Calixte DENIZET
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 "AnalysisVisitor.hxx"
14
15 namespace analysis
16 {
17
18 bool AnalysisVisitor::analyzeIndices(TIType & type, ast::CallExp & ce)
19 {
20     const ast::exps_t args = ce.getArgs();
21     const unsigned int size = args.size();
22
23     if (size >= 3)
24     {
25         // Not handle yet...
26         // TODO
27         return false;
28     }
29
30     if (size == 0)
31     {
32         Result & res = ce.getDecorator().setResult(type);
33         setResult(res);
34         return true;
35     }
36
37     SymbolicDimension first, second;
38     bool safe, ret;
39
40     if (size == 1)
41     {
42         // when there is one argument, a(?) is equivalent to A(?,1)
43         // where A = matrix(a, r_a * c_a, 1)
44
45         SymbolicDimension rows(type.rows);
46         second = SymbolicDimension(getGVN(), 1.);
47         if (type.cols != 1)
48         {
49             rows *= type.cols;
50         }
51
52         ret = getDimension(rows, *args.front(), safe, first);
53     }
54     else
55     {
56         bool _safe;
57         ret = getDimension(type.rows, *args.front(), _safe, first);
58         if (ret)
59         {
60             ret = getDimension(type.cols, *args.back(), safe, second);
61             safe = safe && _safe;
62         }
63         else
64         {
65             safe = _safe;
66         }
67     }
68
69     if (ret)
70     {
71         TIType typ(getGVN(), type.type, first, second);
72         Result & _res = ce.getDecorator().setResult(typ);
73         setResult(_res);
74         ce.getDecorator().safe = safe;
75     }
76
77     return ret;
78 }
79
80
81 bool AnalysisVisitor::getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out)
82 {
83     switch (arg.getType())
84     {
85         case ast::Exp::COLONVAR :
86         {
87             out = dim;
88             safe = true;
89             return true;
90         }
91         case ast::Exp::DOLLARVAR : // a($)
92         {
93             out = SymbolicDimension(getGVN(), 1.);
94             safe = true;
95             return true;
96         }
97         case ast::Exp::DOUBLEEXP : // a(12) or a([1 2])
98         {
99             ast::DoubleExp & de = static_cast<ast::DoubleExp &>(arg);
100             if (types::InternalType * const pIT = de.getConstant())
101             {
102                 if (pIT->isDouble())
103                 {
104                     types::Double * const pDbl = static_cast<types::Double *>(pIT);
105                     if (pDbl->isEmpty())
106                     {
107                         out = SymbolicDimension(getGVN(), 0.);
108                         safe = true;
109                         return true;
110                     }
111
112                     const double * real = pDbl->getReal();
113                     const int size = pDbl->getSize();
114                     int64_t max;
115                     if (tools::asInteger(real[0], max))
116                     {
117                         int64_t min = max;
118                         if (!pDbl->isComplex())
119                         {
120                             for (int i = 0; i < size; ++i)
121                             {
122                                 int64_t _real;
123                                 if (tools::asInteger(real[i], _real))
124                                 {
125                                     if (_real < min)
126                                     {
127                                         min = _real;
128                                     }
129                                     else if (_real > max)
130                                     {
131                                         max = _real;
132                                     }
133                                 }
134                                 else
135                                 {
136                                     return false;
137                                 }
138                             }
139
140                             out = SymbolicDimension(getGVN(), size);
141                             safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
142                             return true;
143                         }
144                         else
145                         {
146                             const double * imag = pDbl->getImg();
147                             int i;
148                             for (i = 0; i < size; ++i)
149                             {
150                                 if (imag[i])
151                                 {
152                                     break;
153                                 }
154                                 int64_t _real;
155                                 if (tools::asInteger(real[i], _real))
156                                 {
157                                     if (_real < min)
158                                     {
159                                         min = _real;
160                                     }
161                                     else if (_real > max)
162                                     {
163                                         max = _real;
164                                     }
165                                 }
166                             }
167
168                             if (i == size)
169                             {
170                                 out = SymbolicDimension(getGVN(), size);
171                                 safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
172                                 return true;
173                             }
174                             else
175                             {
176                                 return false;
177                             }
178                         }
179                     }
180                     else
181                     {
182                         return false;
183                     }
184                 }
185                 else if (pIT->isImplicitList())
186                 {
187                     types::ImplicitList * const pIL = static_cast<types::ImplicitList *>(pIT);
188                     double start, step, end;
189                     if (AnalysisVisitor::asDouble(pIL->getStart(), start) && AnalysisVisitor::asDouble(pIL->getStep(), step) && AnalysisVisitor::asDouble(pIL->getEnd(), end))
190                     {
191                         double single;
192                         const int type = ForList64::checkList(start, end, step, single);
193
194                         switch (type)
195                         {
196                             case 0 :
197                             {
198                                 out = SymbolicDimension(getGVN(), 0.);
199                                 safe = true;
200                                 return true;
201                             }
202                             case 1 :
203                             {
204                                 out = SymbolicDimension(getGVN(), 1.);
205                                 safe = false;
206                                 return true;
207                             }
208                             case 2 :
209                             {
210                                 const uint64_t N = ForList64::size(start, end, step);
211                                 uint64_t max, min;
212                                 if (step > 0)
213                                 {
214                                     min = start;
215                                     max = (uint64_t)(start + (N - 1) * step);
216                                 }
217                                 else
218                                 {
219                                     max = start;
220                                     min = (uint64_t)(start + (N - 1) * step);
221                                 }
222
223                                 out = SymbolicDimension(getGVN(), N);
224                                 safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue((int64_t)max));
225                                 return true;
226                             }
227                         }
228                     }
229                 }
230             }
231             else
232             {
233                 out = SymbolicDimension(getGVN(), 1.);
234                 safe = (de.getValue() >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(de.getValue()));
235                 return true;
236             }
237             return false;
238         }
239         case ast::Exp::BOOLEXP : // a(a > 1) => a([%f %t %t]) => a([2 3])
240         {
241             ast::BoolExp & be = static_cast<ast::BoolExp &>(arg);
242             if (types::InternalType * const pIT = be.getConstant())
243             {
244                 if (pIT->isBool())
245                 {
246                     types::Bool * const pBool = static_cast<types::Bool *>(pIT);
247                     const int size = pBool->getSize();
248                     const int * data = pBool->get();
249                     int max = -1;
250                     int count = 0;
251                     for (int i = 0; i < size; ++i)
252                     {
253                         if (data[i])
254                         {
255                             ++count;
256                             max = i;
257                         }
258                     }
259
260                     out = SymbolicDimension(getGVN(), count);
261                     safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
262                     return true;
263                 }
264             }
265             else
266             {
267                 if (be.getValue())
268                 {
269                     out = SymbolicDimension(getGVN(), 1.);
270                 }
271                 else
272                 {
273                     out = SymbolicDimension(getGVN(), 0.);
274                 }
275                 safe = true;
276                 return true;
277             }
278             return false;
279         }
280         case ast::Exp::LISTEXP :
281         {
282             ast::ListExp & le = static_cast<ast::ListExp &>(arg);
283             SymbolicList sl;
284             if (SymbolicList::get(*this, le, sl))
285             {
286                 if (sl.isSymbolic())
287                 {
288                     sl.evalDollar(getGVN(), dim.getValue());
289                 }
290                 TIType typ;
291                 if (sl.getType(getGVN(), typ))
292                 {
293                     out = SymbolicDimension(getGVN(), typ.cols.getValue());
294                     safe = false;//getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
295                     return true;
296                 }
297             }
298             return false;
299         }
300         default :
301         {
302             arg.accept(*this);
303             Result & _res = getResult();
304             SymbolicRange & range = _res.getRange();
305             if (range.isValid())
306             {
307                 //std::wcerr << *range.getStart()->poly << ":" << *range.getEnd()->poly << ",," << *dim.getValue()->poly << std::endl;
308                 safe = getCM().check(ConstraintManager::VALID_RANGE, range.getStart(), range.getEnd(), getGVN().getValue(1), dim.getValue());
309                 out = _res.getType().rows * _res.getType().cols;
310
311                 return true;
312             }
313
314             if (GVN::Value * const v = _res.getConstant().getGVNValue())
315             {
316                 if (GVN::Value * const dollar = getGVN().getExistingValue(symbol::Symbol(L"$")))
317                 {
318                     if (GVN::Value * const w = SymbolicList::evalDollar(getGVN(), v, dollar, dim.getValue()))
319                     {
320                         bool b = getCM().check(ConstraintManager::GREATER, dim.getValue(), w);
321                         if (b)
322                         {
323                             safe = getCM().check(ConstraintManager::STRICT_POSITIVE, w);
324                         }
325                         else
326                         {
327                             safe = false;
328                         }
329                         out = SymbolicDimension(getGVN(), 1);
330                         return true;
331                     }
332                 }
333             }
334
335             // To use with find
336             // e.g. a(find(a > 0)): find(a > 0) return a matrix where the max index is rc(a) so the extraction is safe
337             if (_res.getType().ismatrix() && _res.getType().type != TIType::BOOLEAN)
338             {
339                 out = _res.getType().rows * _res.getType().cols;
340                 SymbolicDimension & maxIndex = _res.getMaxIndex();
341                 if (maxIndex.isValid())
342                 {
343                     safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), maxIndex.getValue());
344                 }
345                 else
346                 {
347                     safe = false;
348                 }
349                 return true;
350             }
351             return false;
352         }
353     }
354 }
355
356
357 }