[ast] improved polynomial display with unicode superscripts
[scilab.git] / scilab / modules / ast / src / cpp / types / singlepoly.cpp
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 #include <sstream>
16 #include <cmath>
17 #include "singlepoly.hxx"
18 #include "double.hxx"
19 #include "tostring_common.hxx"
20 #include "configvariable.hxx"
21 #include "scilabWrite.hxx"
22
23 extern "C"
24 {
25 #include "log.h"
26 #include "exp.h"
27 #include "elem_common.h"
28 }
29
30 namespace types
31 {
32 SinglePoly::SinglePoly()
33 {
34     double* pdblCoefR = NULL;
35     int piDims[2] = {1, 1};
36     create(piDims, 2, &pdblCoefR, NULL);
37     pdblCoefR[0] = 0;
38 #ifndef NDEBUG
39     Inspector::addItem(this);
40 #endif
41 }
42
43 SinglePoly::SinglePoly(double** _pdblCoefR, int _iRank)
44 {
45     int piDims[2] = {_iRank + 1, 1};
46     create(piDims, 2, _pdblCoefR, NULL);
47 #ifndef NDEBUG
48     Inspector::addItem(this);
49 #endif
50 }
51
52 SinglePoly::SinglePoly(double** _pdblCoefR, double** _pdblCoefI, int _iRank)
53 {
54     int piDims[2] = {_iRank + 1, 1};
55     create(piDims, 2, _pdblCoefR, _pdblCoefI);
56 #ifndef NDEBUG
57     Inspector::addItem(this);
58 #endif
59 }
60
61 SinglePoly::~SinglePoly()
62 {
63     deleteAll();
64 #ifndef NDEBUG
65     Inspector::removeItem(this);
66 #endif
67 }
68
69 void SinglePoly::deleteAll()
70 {
71     delete[] m_pRealData;
72     m_pRealData = NULL;
73     deleteImg();
74 }
75
76 void SinglePoly::deleteImg()
77 {
78     if (m_pImgData != NULL)
79     {
80         delete[] m_pImgData;
81         m_pImgData = NULL;
82     }
83 }
84
85 double SinglePoly::getNullValue()
86 {
87     return 0;
88 }
89
90 SinglePoly* SinglePoly::createEmpty(int /*_iDims*/, int* _piDims, bool _bComplex)
91 {
92     double* pdblData = NULL;
93     SinglePoly* pSP = new SinglePoly(&pdblData, _piDims[0] - 1);
94     pSP->setComplex(_bComplex);
95
96     return pSP;
97 }
98
99 double* SinglePoly::allocData(int _iSize)
100 {
101     double* pDbl = NULL;
102     try
103     {
104         if (_iSize < 0)
105         {
106             m_pRealData = NULL;
107             m_pImgData = NULL;
108             char message[bsiz];
109             os_sprintf(message, _("Can not allocate negative size (%d).\n"),  _iSize);
110             throw ast::InternalError(message);
111         }
112         else
113         {
114             pDbl = new double[_iSize];
115         }
116     }
117     catch (std::bad_alloc &/*e*/)
118     {
119         char message[bsiz];
120         char byteString[9];
121         humanReadableByteCount(((size_t) m_iSize) * sizeof(double), byteString);
122         os_sprintf(message, _("Can not allocate %s memory.\n"), byteString);
123         throw ast::InternalError(message);
124     }
125
126     return pDbl;
127 }
128
129 double SinglePoly::copyValue(double _dblData)
130 {
131     return _dblData;
132 }
133
134 int SinglePoly::getRank()
135 {
136     return m_iSize - 1;
137 }
138
139 double SinglePoly::getDegree()
140 {
141     return m_iSize == 1 && m_pRealData[0] == 0 && (m_pImgData == NULL || m_pImgData[0] == 0) ? -INFINITY : m_iSize - 1;
142 }
143
144 bool SinglePoly::setRank(int _iRank, bool bSave)
145 {
146     double *pR = NULL;
147     double *pI = NULL;
148     if (bSave == false)
149     {
150         if (getRank() != _iRank)
151         {
152             int piDims[2] = {_iRank + 1, 1};
153             if (m_pImgData == NULL)
154             {
155                 deleteAll();
156                 create(piDims, 2, &pR, NULL);
157             }
158             else
159             {
160                 deleteAll();
161                 create(piDims, 2, &pR, &pI);
162             }
163
164             return true;
165         }
166
167         return true;
168     }
169     else
170     {
171         double* pdblOldReal = m_pRealData;
172         double* pdblOldImg  = m_pImgData;
173         int iMinSize = Min(m_iSize, _iRank + 1);
174         int piDims[2] = {_iRank + 1, 1};
175
176         if (m_pImgData == NULL)
177         {
178             create(piDims, 2, &pR, NULL);
179         }
180         else
181         {
182             create(piDims, 2, &pR, &pI);
183             memcpy(m_pImgData, pdblOldImg, iMinSize * sizeof(double));
184         }
185
186         memcpy(m_pRealData, pdblOldReal, iMinSize * sizeof(double));
187
188         if (pdblOldImg)
189         {
190             delete[] pdblOldImg;
191             pdblOldImg = NULL;
192         }
193
194         delete[] pdblOldReal;
195         pdblOldReal = NULL;
196
197         return true;
198     }
199
200     return false;
201 }
202
203 bool SinglePoly::setZeros()
204 {
205     if (m_pRealData != NULL)
206     {
207         memset(m_pRealData, 0x00, m_iSize * sizeof(double));
208     }
209     else
210     {
211         return false;
212     }
213
214     if (isComplex() == true)
215     {
216         if (m_pImgData != NULL)
217         {
218             memset(m_pImgData, 0x00, m_iSize * sizeof(double));
219         }
220         else
221         {
222             return false;
223         }
224     }
225
226     return true;
227 }
228
229 bool SinglePoly::setCoef(Double* _pdblCoefR)
230 {
231     if (m_pRealData == NULL || _pdblCoefR == NULL)
232     {
233         return false;
234     }
235
236     double *pInR    = _pdblCoefR->getReal();
237     double *pInI    = _pdblCoefR->getImg();
238
239     return setCoef(pInR, pInI);
240 }
241
242 bool SinglePoly::setCoef(const double* _pdblCoefR, const double* _pdblCoefI)
243 {
244     if (_pdblCoefI != NULL && isComplex() == false)
245     {
246         setComplex(true);
247     }
248
249     if (_pdblCoefR != NULL)
250     {
251         memcpy(m_pRealData, _pdblCoefR, m_iSize * sizeof(double));
252     }
253
254     if (_pdblCoefI != NULL)
255     {
256         memcpy(m_pImgData, _pdblCoefI, m_iSize * sizeof(double));
257     }
258
259     return true;
260 }
261
262 void SinglePoly::whoAmI()
263 {
264     std::cout << "types::SinglePoly";
265 }
266
267 bool SinglePoly::evaluate(double _dblInR, double _dblInI, double *_pdblOutR, double *_pdblOutI)
268 {
269     *_pdblOutR = 0;
270     *_pdblOutI = 0;
271     if (m_iSize == 0)
272     {
273         return true;
274     }
275
276     for (int i = 0 ; i < m_iSize ; i++)
277     {
278         //real part
279         *_pdblOutR += m_pRealData[i] * std::pow(_dblInR, i);
280         //only if variable is complex
281         if (isComplex())
282         {
283             *_pdblOutR -= m_pImgData[i] * std::pow(_dblInI, i);
284             //img part
285             *_pdblOutI += m_pRealData[i] * std::pow(_dblInR, i);
286         }
287         *_pdblOutI += m_pRealData[i] * std::pow(_dblInI, i);
288     }
289
290     return true;
291 }
292
293 void SinglePoly::updateRank(void)
294 {
295     int iNewRank = getRank();
296     if (m_pImgData)
297     {
298         for (int i = getRank(); i > 0 ; i--)
299         {
300             if (std::fabs(m_pRealData[i]) == 0.0 && std::fabs(m_pImgData[i]) == 0.0)
301             {
302                 iNewRank--;
303             }
304             else
305             {
306                 break;
307             }
308         }
309     }
310     else
311     {
312         for (int i = getRank(); i > 0 ; i--)
313         {
314             if (std::fabs(m_pRealData[i]) == 0.0)
315             {
316                 iNewRank--;
317             }
318             else
319             {
320                 break;
321             }
322         }
323     }
324
325     if (iNewRank < getRank())
326     {
327         setRank(iNewRank, true);
328     }
329 }
330
331 bool SinglePoly::toString(std::wostringstream& ostr)
332 {
333     ostr << L"FIXME : implement SinglePoly::toString" << std::endl;
334     return true;
335 }
336
337 void SinglePoly::toStringReal(const std::wstring& _szVar, std::list<std::wstring>* _pListWstPoly)
338 {
339     toStringInternal(m_pRealData, _szVar, _pListWstPoly);
340 }
341
342 void SinglePoly::toStringImg(const std::wstring& _szVar, std::list<std::wstring>* _pListWstPoly)
343 {
344     if (isComplex() == false)
345     {
346         _pListWstPoly->clear();
347         return;
348     }
349
350     toStringInternal(m_pImgData, _szVar, _pListWstPoly);
351 }
352
353 bool SinglePoly::subMatrixToString(std::wostringstream& /*ostr*/, int* /*_piDims*/, int /*_iDims*/)
354 {
355     return false;
356 }
357
358 void SinglePoly::toStringInternal(double *_pdblVal, const std::wstring& _szVar, std::list<std::wstring>* _pListWstPoly)
359 {
360     int iLineLen = ConfigVariable::getConsoleWidth();
361
362     std::wstring strExponentDigits (L"\u2070\u00B9\u00B2\u00B3\u2074\u2075\u2076\u2077\u2078\u2079");
363     std::vector<int> iExponentsDigits = {0};
364     std::wostringstream ostemp;
365     bool bFirst = true;
366
367     ostemp << L" ";
368
369     int k;
370     int iLen = 0;
371     int iLastFlush = 2;
372     for (int i = 0 ; i < m_iSize ; i++)
373     {
374         if (_pdblVal[i] != 0)
375         {
376             DoubleFormat df;
377             getDoubleFormat(_pdblVal[i], &df);
378
379             if (iLen + df.iWidth + df.iSignLen >= iLineLen - 1)
380             {
381                 iLastFlush = i;
382                 _pListWstPoly->push_back(ostemp.str());
383                 ostemp.str(L""); //reset stream
384                 addSpaces(&ostemp, 1); //take from scilab ... why not ...
385             }
386
387             // In scientific notation case bExp == true, so we have to print point (2.000D+10s)
388             // In other case don't print point (2s)
389             df.bPrintPoint = df.bExp;
390             df.bPrintPlusSign = bFirst == false;
391             df.bPrintOne = i == 0;
392             bFirst = false;
393             addDoubleValue(&ostemp, _pdblVal[i], &df);
394             
395             if (i == 0)
396             {
397                 iLen = static_cast<int>(ostemp.str().size());
398             }
399             else if (i == 1)
400             {
401                 // add polynomial variable
402                 ostemp << _szVar;
403                 iLen = static_cast<int>(ostemp.str().size());
404             }
405             else
406             {
407                 // add polynomial variable and exponent
408                 ostemp << _szVar;
409                 for (auto it = iExponentsDigits.rbegin(); it != iExponentsDigits.rend(); ++it)
410                 {
411                     ostemp << strExponentDigits[*it];
412                 }
413                 iLen = static_cast<int>(ostemp.str().size());            
414             }            
415         }
416
417         for (k=0; k < iExponentsDigits.size() && iExponentsDigits[k] == 9; k++)
418         {
419             iExponentsDigits[k] = 0;
420         }
421         if (k == iExponentsDigits.size())
422         {
423             iExponentsDigits.push_back(0);
424         }
425         iExponentsDigits[k]++;
426     }
427
428     if (iLastFlush != 0)
429     {
430         if (ostemp.str() == L" ")
431         {
432             ostemp << L"  0";
433         }
434
435         _pListWstPoly->push_back(ostemp.str());
436     }
437
438     return;
439 }
440
441 bool SinglePoly::operator==(const InternalType& it)
442 {
443     if (const_cast<InternalType &>(it).isSinglePoly() == false)
444     {
445         return false;
446     }
447
448     SinglePoly* pP = const_cast<InternalType &>(it).getAs<SinglePoly>();
449
450     if (getRank() != pP->getRank())
451     {
452         return false;
453     }
454
455     double *pdblReal = pP->get();
456     for (int i = 0 ; i < getSize() ; i++)
457     {
458         if (m_pRealData[i] != pdblReal[i])
459         {
460             return false;
461         }
462     }
463
464     //both complex
465     if (isComplex() && pP->isComplex())
466     {
467         double *pdblImg = pP->getImg();
468         for (int i = 0 ; i < m_iSize ; i++)
469         {
470             if (m_pImgData[i] != pdblImg[i])
471             {
472                 return false;
473             }
474         }
475     }
476     //pdbl complex check all img values == 0
477     else if (pP->isComplex())
478     {
479         double *pdblImg = pP->getImg();
480         for (int i = 0 ; i < m_iSize ; i++)
481         {
482             if (pdblImg[i])
483             {
484                 return false;
485             }
486         }
487     }
488     //complex check all img values == 0
489     else if (isComplex())
490     {
491         for (int i = 0 ; i < m_iSize ; i++)
492         {
493             if (m_pImgData[i])
494             {
495                 return false;
496             }
497         }
498     }
499
500     return true;
501 }
502
503 bool SinglePoly::operator!=(const InternalType& it)
504 {
505     return !(*this == it);
506 }
507
508 SinglePoly* SinglePoly::clone()
509 {
510     SinglePoly* pPoly = NULL;
511     double *pR = NULL;
512     if (isComplex())
513     {
514         double *pI = NULL;
515         pPoly = new SinglePoly(&pR, &pI, getRank());
516         pPoly->setCoef(m_pRealData, m_pImgData);
517     }
518     else
519     {
520         pPoly = new SinglePoly(&pR, getRank());
521         pPoly->setCoef(m_pRealData, NULL);
522     }
523     return pPoly;
524 }
525
526 SinglePoly* SinglePoly::conjugate()
527 {
528     if (isComplex())
529     {
530         double *pR = NULL;
531         double *pI = NULL;
532         SinglePoly * pPoly = new SinglePoly(&pR, &pI, getRank());
533
534         Transposition::conjugate(m_iSize, m_pRealData, pR, m_pImgData, pI);
535
536         return pPoly;
537     }
538     else
539     {
540         return clone();
541     }
542 }
543
544 SinglePoly* operator*(const SinglePoly& _lhs, const SinglePoly& _rhs)
545 {
546     SinglePoly& lhs = const_cast<SinglePoly &>(_lhs);
547     SinglePoly& rhs = const_cast<SinglePoly &>(_rhs);
548     SinglePoly* pOut = NULL;
549
550     bool isComplexL = lhs.isComplex();
551     bool isComplexR = rhs.isComplex();
552     bool isComplexOut = isComplexL || isComplexR;
553
554     int iRankL = lhs.getRank();
555     int iRankR = rhs.getRank();
556     int iRankOut = lhs.getRank() + rhs.getRank();
557
558     double* pdblOutR = NULL;
559     double* pdblOutI = NULL;
560     double* pdblLR = lhs.get();
561     double* pdblLI = lhs.getImg();
562     double* pdblRR = rhs.get();
563     double* pdblRI = rhs.getImg();
564
565     if (isComplexOut)
566     {
567         pOut = new SinglePoly(&pdblOutR, &pdblOutI, iRankOut);
568         memset(pdblOutR, 0x00, sizeof(double) * (iRankOut + 1));
569         memset(pdblOutI, 0x00, sizeof(double) * (iRankOut + 1));
570     }
571     else
572     {
573         pOut = new SinglePoly(&pdblOutR, iRankOut);
574         memset(pdblOutR, 0x00, sizeof(double) * (iRankOut + 1));
575     }
576
577     if (isComplexL)
578     {
579         if (isComplexR)
580         {
581             for (int i = 0 ; i < iRankL + 1; ++i)
582             {
583                 for (int j = 0 ; j < iRankR + 1; ++j)
584                 {
585                     pdblOutR[i + j]  += pdblLR[i] * pdblRR[j] - pdblLI[i] * pdblRI[j];
586                     pdblOutI[i + j]  += pdblLI[i] * pdblRR[j] + pdblLR[i] * pdblRI[j];
587                 }
588             }
589         }
590         else
591         {
592             for (int i = 0 ; i < iRankL + 1 ; ++i)
593             {
594                 for (int j = 0 ; j < iRankR + 1 ; ++j)
595                 {
596                     pdblOutR[i + j]  += pdblLR[i] * pdblRR[j];
597                     pdblOutI[i + j]  += pdblLI[i] * pdblRR[j];
598                 }
599             }
600         }
601     }
602     else
603     {
604         if (isComplexR)
605         {
606             for (int i = 0 ; i < iRankL + 1 ; ++i)
607             {
608                 for (int j = 0 ; j < iRankR + 1 ; ++j)
609                 {
610                     pdblOutR[i + j]  += pdblLR[i] * pdblRR[j];
611                     pdblOutI[i + j]  += pdblLR[i] * pdblRI[j];
612                 }
613             }
614         }
615         else
616         {
617             for (int i = 0 ; i < iRankL + 1 ; ++i)
618             {
619                 for (int j = 0 ; j < iRankR + 1 ; ++j)
620                 {
621                     pdblOutR[i + j]  += pdblLR[i] * pdblRR[j];
622                 }
623             }
624         }
625     }
626
627     return pOut;
628 }
629 }
630
631
632