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