[ast] improve display of (complex) polymomials and rationals
[scilab.git] / scilab / modules / ast / src / cpp / types / polynom.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
16 #include <sstream>
17 #include <algorithm>
18 #include "core_math.h"
19 #include "tostring_common.hxx"
20 #include "singlepoly.hxx"
21 #include "polynom.hxx"
22 #include "configvariable.hxx"
23
24 namespace types
25 {
26 Polynom::Polynom()
27 {
28 #ifndef NDEBUG
29     Inspector::addItem(this);
30 #endif
31 }
32
33 Polynom::Polynom(const std::wstring& _szVarName, int _iRows, int _iCols)
34 {
35     int piDims[2]   = {_iRows, _iCols};
36     createPoly(_szVarName, 2, piDims, NULL);
37 }
38
39 Polynom::Polynom(const std::wstring& _szVarName, int _iRows, int _iCols, const int *_piRank)
40 {
41     int piDims[2]   = {_iRows, _iCols};
42     createPoly(_szVarName, 2, piDims, _piRank);
43 }
44
45 Polynom::Polynom(const std::wstring& _szVarName, int _iDims, const int* _piDims)
46 {
47     createPoly(_szVarName, _iDims, _piDims, NULL);
48 }
49
50 Polynom::Polynom(const std::wstring& _szVarName, int _iDims, const int* _piDims, const int *_piRank)
51 {
52     createPoly(_szVarName, _iDims, _piDims, _piRank);
53 }
54
55 Polynom::~Polynom()
56 {
57     if (isDeletable() == true)
58     {
59         deleteAll();
60     }
61 #ifndef NDEBUG
62     Inspector::removeItem(this);
63 #endif
64 }
65
66 bool Polynom::getMemory(long long* _piSize, long long* _piSizePlusType)
67 {
68     *_piSize = 0;
69     for (int i = 0; i<getSize(); i++)
70     {
71         *_piSize += (get(i)->getRank()+1)*sizeof(double);
72     }
73     
74     *_piSize = *_piSize * (isComplex() ? 2 : 1);
75     *_piSizePlusType = *_piSize + getSize()*sizeof(SinglePoly *) + sizeof(*this);
76     return true;
77 }
78
79
80 void Polynom::createPoly(const std::wstring& _szVarName, int _iDims, const int* _piDims, const int *_piRank)
81 {
82     m_szVarName = _szVarName;
83     SinglePoly** pPoly = NULL;
84     create(_piDims, _iDims, &pPoly, NULL);
85
86     if (_piRank)
87     {
88         for (int i = 0 ; i < getSize() ; i++)
89         {
90             double* pReal = NULL;
91             m_pRealData[i] = new SinglePoly(&pReal, _piRank[i]);
92         }
93     }
94 #ifndef NDEBUG
95     Inspector::addItem(this);
96 #endif
97 }
98
99 Polynom* Polynom::set(int _iPos, SinglePoly* _pS)
100 {
101     if (m_pRealData == NULL || _iPos >= m_iSize)
102     {
103         return NULL;
104     }
105
106     typedef Polynom* (Polynom::*set_t)(int, SinglePoly*);
107     Polynom* pIT = checkRef(this, (set_t)&Polynom::set, _iPos, _pS);
108     if (pIT != this)
109     {
110         return pIT;
111     }
112
113     if (m_pRealData[_iPos])
114     {
115         delete m_pRealData[_iPos];
116     }
117
118     m_pRealData[_iPos] = copyValue(_pS);
119
120     bool bComplex = isComplex();
121     if (_pS->isComplex() && bComplex == false)
122     {
123         setComplex(true);
124     }
125     else if (_pS->isComplex() == false && bComplex)
126     {
127         m_pRealData[_iPos]->setComplex(true);
128     }
129
130     return this;
131 }
132
133 Polynom* Polynom::set(int _iRows, int _iCols, SinglePoly* _pS)
134 {
135     return set(_iCols * getRows() + _iRows, _pS);
136 }
137
138 Polynom* Polynom::set(SinglePoly** _pS)
139 {
140     typedef Polynom* (Polynom::*set_t)(SinglePoly**);
141     Polynom* pIT = checkRef(this, (set_t)&Polynom::set, _pS);
142     if (pIT != this)
143     {
144         return pIT;
145     }
146
147     for (int i = 0 ; i < m_iSize ; i++)
148     {
149         set(i, _pS[i]);
150     }
151
152     return this;
153 }
154
155 Polynom* Polynom::setCoef(int _iRows, int _iCols, Double *_pdblCoef)
156 {
157     int piDims[] = {_iRows, _iCols};
158     int iPos = getIndex(piDims);
159     return setCoef(iPos, _pdblCoef);
160 }
161
162 Polynom* Polynom::setCoef(int _iIdx, Double *_pdblCoef)
163 {
164     if (_iIdx > m_iSize)
165     {
166         return NULL;
167     }
168
169     typedef Polynom* (Polynom::*setCoef_t)(int, Double*);
170     Polynom* pIT = checkRef(this, (setCoef_t)&Polynom::setCoef, _iIdx, _pdblCoef);
171     if (pIT != this)
172     {
173         return pIT;
174     }
175
176     /*Get old SinglePoly*/
177     m_pRealData[_iIdx]->setRank(_pdblCoef->getSize() - 1);
178     m_pRealData[_iIdx]->setCoef(_pdblCoef);
179
180     return this;
181 }
182
183 void Polynom::setZeros()
184 {
185     for (int i = 0; i < m_iSize; i++)
186     {
187         m_pRealData[i]->setZeros();
188     }
189 }
190
191 bool Polynom::getSizes(int *_piSizes)
192 {
193     if (_piSizes == NULL || m_pRealData == NULL)
194     {
195         return false;
196     }
197
198     for (int i = 0 ; i < getSize() ; i++)
199     {
200         _piSizes[i] = m_pRealData[i]->getSize();
201     }
202
203     return true;
204 }
205
206 bool Polynom::getRank(int *_piRank)
207 {
208     if (_piRank == NULL || m_pRealData == NULL)
209     {
210         return false;
211     }
212
213     for (int i = 0 ; i < getSize() ; i++)
214     {
215         _piRank[i] = m_pRealData[i]->getRank();
216     }
217
218     return true;
219 }
220
221 void Polynom::whoAmI(void)
222 {
223     std::cout << "types::SinglePoly";
224 }
225
226 std::wstring& Polynom::getVariableName()
227 {
228     return m_szVarName;
229 }
230
231 void Polynom::setVariableName(const std::wstring& _szVarName)
232 {
233     m_szVarName = _szVarName;
234 }
235
236 bool Polynom::isComplex()
237 {
238         for (int i = 0 ; i < getSize() ; i++)
239         {
240             if  (m_pRealData[i] && m_pRealData[i]->isComplex())
241             {
242                 return true;
243             }
244         }
245         return false;
246 }
247
248 Polynom* Polynom::setComplex(bool _bComplex)
249 {
250     if (_bComplex == isComplex())
251     {
252         return this;
253     }
254
255     typedef Polynom* (Polynom::*setcplx_t)(bool);
256     Polynom* pIT = checkRef(this, (setcplx_t)&Polynom::setComplex, _bComplex);
257     if (pIT != this)
258     {
259         return pIT;
260     }
261
262     for (int i = 0 ; i < getSize() ; i++)
263     {
264         get(i)->setComplex(_bComplex);
265     }
266
267     return this;
268 }
269
270 Polynom* Polynom::clone()
271 {
272     Polynom* pMP = new Polynom(getVariableName(), getDims(), getDimsArray());
273     for (int i = 0 ; i < getSize() ; i++)
274     {
275         pMP->set(i, m_pRealData[i]);
276     }
277
278     return pMP;
279 }
280
281 bool Polynom::transpose(InternalType *& out)
282 {
283     if (isScalar())
284     {
285         out = clone();
286         return true;
287     }
288
289     if (m_iDims == 2)
290     {
291         int piNewDims[2] = {m_piDims[1], m_piDims[0]};
292         Polynom* pPoly = new Polynom(m_szVarName, m_iDims, piNewDims);
293         Transposition::transpose_clone(getRows(), getCols(), m_pRealData, pPoly->get());
294         out = pPoly;
295         return true;
296     }
297
298     return false;
299
300 }
301
302 bool Polynom::adjoint(InternalType *& out)
303 {
304     if (isComplex())
305     {
306         if (m_iDims == 2)
307         {
308             int piNewDims[2] = {m_piDims[1], m_piDims[0]};
309             Polynom* pPoly = new Polynom(m_szVarName, m_iDims, piNewDims);
310             Transposition::adjoint_clone(getRows(), getCols(), m_pRealData, pPoly->get());
311             out = pPoly;
312             return true;
313         }
314         else
315         {
316             return false;
317         }
318     }
319     else
320     {
321         return transpose(out);
322     }
323 }
324
325 Double* Polynom::evaluate(Double* _pdblValue)
326 {
327     double *pR = _pdblValue->getReal();
328     double *pI = _pdblValue->getImg();
329     int iRows  = _pdblValue->getRows();
330     int iCols  = _pdblValue->getCols();
331
332     double *pReturnR = NULL;
333     double *pReturnI = NULL;
334     Double *pReturn  = new Double(getRows() * iRows, getCols() * iCols, &pReturnR, &pReturnI);
335     pReturn->setComplex(_pdblValue->isComplex());
336
337     int i = 0;
338     //all lines of the matrix remplacement
339     for (int iCol = 0 ; iCol < iCols ; iCol++)
340     {
341         for (int iPolyCol = 0 ; iPolyCol < getCols() ; iPolyCol++)
342         {
343             for (int iRow = 0 ; iRow < iRows ; iRow++)
344             {
345                 for (int iPolyRow = 0 ; iPolyRow < getRows() ; iPolyRow++)
346                 {
347                     double OutR = 0;
348                     double OutI = 0;
349
350                     SinglePoly *pPoly = get(iPolyRow, iPolyCol);
351                     if (pReturn->isComplex())
352                     {
353                         pPoly->evaluate(pR[iCol * iRows + iRow], pI[iCol * iRows + iRow], &OutR, &OutI);
354                         pReturnR[i] = OutR;
355                         pReturnI[i] = OutI;
356                     }
357                     else
358                     {
359                         pPoly->evaluate(pR[iCol * iRows + iRow], 0, &OutR, &OutI);
360                         pReturnR[i] = OutR;
361                     }
362                     i++;
363                 }
364             }
365         }
366     }
367     return pReturn;
368 }
369
370 void Polynom::updateRank(void)
371 {
372     for (int i = 0 ; i < getSize() ; i++)
373     {
374         m_pRealData[i]->updateRank();
375     }
376 }
377
378 int Polynom::getMaxRank(void)
379 {
380     int *piRank = new int[getSize()];
381     getRank(piRank);
382     int iMaxRank = 0;
383     for (int i = 0 ; i < getSize() ; i++)
384     {
385         iMaxRank = std::max(iMaxRank, piRank[i]);
386     }
387     delete[] piRank;
388     return iMaxRank;
389 }
390
391 Double* Polynom::getCoef(void)
392 {
393     int iMaxRank = getMaxRank();
394     int iColsOut = getCols() * (iMaxRank + 1);
395
396     Double *pCoef = new Double(getRows(), iColsOut, isComplex());
397     pCoef->setZeros();
398     double *pCoefR = pCoef->getReal();
399
400     if (isComplex())
401     {
402         double *pCoefI = pCoef->getImg();
403         for (int i = 0 ; i < m_iSize ; i++)
404         {
405             SinglePoly *pPoly = m_pRealData[i];
406             int iSize = pPoly->getSize();
407             double *pR = pPoly->get();
408             double *pI = pPoly->getImg();
409
410             for (int iRank = 0 ; iRank < iSize ; iRank++)
411             {
412                 pCoefR[iRank * m_iSize + i] = pR[iRank];
413                 pCoefI[iRank * m_iSize + i] = pI[iRank];
414             }
415         }
416     }
417     else
418     {
419         for (int i = 0 ; i < m_iSize ; i++)
420         {
421             SinglePoly *pPoly = m_pRealData[i];
422             int iSize = pPoly->getSize();
423             double *pR = pPoly->get();
424             for (int iRank = 0 ; iRank < iSize ; iRank++)
425             {
426                 pCoefR[iRank * m_iSize + i] = pR[iRank];
427             }
428         }
429     }
430
431     return pCoef;
432 }
433
434 Polynom* Polynom::setCoef(Double *_pCoef)
435 {
436     typedef Polynom* (Polynom::*setCoef_t)(Double*);
437     Polynom* pIT = checkRef(this, (setCoef_t)&Polynom::setCoef, _pCoef);
438     if (pIT != this)
439     {
440         return pIT;
441     }
442
443     setComplex(_pCoef->isComplex());
444     double *pR = _pCoef->getReal();
445
446     if (isComplex())
447     {
448         double *pI = _pCoef->getImg();
449         for (int i = 0 ; i < m_iSize ; i++)
450         {
451             SinglePoly *pPoly = m_pRealData[i];
452             int iSize = pPoly->getSize();
453             double* pTempR = pPoly->get();
454             double* pTempI = pPoly->getImg();
455
456             for (int iRank = 0 ; iRank < iSize ; iRank++)
457             {
458                 pTempR[iRank] = pR[iRank * m_iSize + i];
459                 pTempI[iRank] = pI[iRank * m_iSize + i];
460             }
461         }
462     }
463     else
464     {
465         for (int i = 0 ; i < m_iSize ; i++)
466         {
467             SinglePoly *pPoly = m_pRealData[i];
468             int iSize = pPoly->getSize();
469             double* pTempR = pPoly->get();
470
471             for (int iRank = 0 ; iRank < iSize ; iRank++)
472             {
473                 pTempR[iRank] = pR[iRank * m_iSize + i];
474             }
475         }
476     }
477
478     return this;
479 }
480
481 bool Polynom::subMatrixToString(std::wostringstream& ostr, int* _piDims, int _iDims)
482 {
483
484     ostr << getMatrixString(_piDims, _iDims, false);
485     
486     return true;
487 }
488
489 std::wstring Polynom::getMatrixString(int* _piDims, int /*_iDims*/, bool _bComplex)
490 {
491     int iLineLen = ConfigVariable::getConsoleWidth();
492
493     std::wostringstream ostr;
494     std::wostringstream osPoly;
495
496     std::list<std::wstring> listWstPoly;
497
498     int iLen        = 0;
499     int iLastCol    = 0;
500     bool bWordWarp  = false;
501
502     int *piMaxLen = new int[abs(getCols())];
503     memset(piMaxLen, 0x00, sizeof(int) * abs(getCols()));
504
505     //find the largest row for each col
506     for (int iCols1 = 0 ; iCols1 < abs(getCols()) ; iCols1++)
507     {
508         for (int iRows1 = 0 ; iRows1 < abs(getRows()) ; iRows1++)
509         {
510             int iLength = 0;
511             _piDims[0] = iRows1;
512             _piDims[1] = iCols1;
513             int iPos = getIndex(_piDims);
514             get(iPos)->toStringRealImg(getVariableName(), &listWstPoly, iLineLen);
515             
516             for (auto it : listWstPoly)
517             {
518                 iLength += static_cast<int>(it.size());
519             }
520             piMaxLen[iCols1] = std::min(std::max(piMaxLen[iCols1], iLength), iLineLen);
521             listWstPoly.clear();
522         }
523
524         //We know the length of the column
525         if (static_cast<int>(iLen + piMaxLen[iCols1]) + 2 >= iLineLen && iLen != 0)
526         {
527             //if the max length exceeded
528             std::wostringstream ostemp;
529             bWordWarp = true;
530             for (int iRows2 = 0 ; iRows2 < abs(getRows()) ; iRows2++)
531             {
532                 bool bMultiLine = false;
533                 for (int iCols2 = iLastCol ; iCols2 < iCols1; iCols2++)
534                 {
535                     _piDims[0] = iRows2;
536                     _piDims[1] = iCols2;
537
538                     int iPos = getIndex(_piDims);
539                     get(iPos)->toStringRealImg(getVariableName(),  &listWstPoly, iLineLen);
540
541                     if (listWstPoly.size() > 1)
542                     {
543                         for (auto it : listWstPoly)
544                         {
545                             osPoly << it << std::endl;
546                             bMultiLine = true;
547                         }
548                     }
549                     else
550                     {
551                         osPoly << L"  " << listWstPoly.front();
552                         addSpaces(&osPoly, piMaxLen[iCols2] - static_cast<int>(listWstPoly.front().size()));
553                         bMultiLine = false;
554                     }
555                     listWstPoly.clear();
556                 }
557
558                 if (bMultiLine == false)
559                 {
560                     osPoly << std::endl;
561                 }
562                 ostemp << osPoly.str() << std::endl;
563                 osPoly.str(L"");
564
565             }
566             iLen = piMaxLen[iCols1];
567
568             //write "column x to y"
569             addColumnString(ostr, iLastCol + 1, iCols1);
570             ostr << ostemp.str() << std::endl;
571
572             iLastCol = iCols1;
573         }
574         else //if((int)(iLen + piMaxLen[iCols1]) <= iLineLen)
575         {
576             iLen += piMaxLen[iCols1];
577         }
578     }//for(int iCols1 = 0 ; iCols1 < getCols() ; iCols1++)
579
580     if (bWordWarp)
581     {
582         addColumnString(ostr, iLastCol + 1, getCols());
583     }
584
585     //print the end
586     for (int iRows2 = 0 ; iRows2 < abs(getRows()) ; iRows2++)
587     {
588         for (int iCols2 = iLastCol ; iCols2 < abs(getCols()) ; iCols2++)
589         {
590             _piDims[0] = iRows2;
591             _piDims[1] = iCols2;
592
593             int iPos = getIndex(_piDims);
594             get(iPos)->toStringRealImg(getVariableName(), &listWstPoly, iLineLen);
595
596             if (listWstPoly.size() > 1)
597             {
598                 for (auto it : listWstPoly)
599                 {
600                     osPoly << it << std::endl;
601                 }
602             }
603             else
604             {
605                 osPoly << L"  " << listWstPoly.front();
606                 addSpaces(&osPoly, piMaxLen[iCols2] - static_cast<int>(listWstPoly.front().size()));
607             }
608             listWstPoly.clear();
609         }
610
611         osPoly << std::endl;
612         if (isIdentity())
613         {
614             ostr << L"eye *" << std::endl << std::endl;
615         }
616         ostr << osPoly.str() << std::endl;
617         osPoly.str(L"");
618     }
619
620     delete[] piMaxLen;
621     return ostr.str();
622 }
623
624
625 Double* Polynom::extractCoef(int _iRank)
626 {
627     Double *pdbl = new Double(getRows(), getCols(), isComplex());
628     pdbl->setZeros();
629     double *pReal = pdbl->getReal();
630
631     if (isComplex())
632     {
633         double *pImg = pdbl->getImg();
634         for (int i = 0 ; i < getSize() ; i++)
635         {
636             SinglePoly *pPoly = m_pRealData[i];
637             if (pPoly->getRank() >= _iRank)
638             {
639                 pReal[i] = pPoly->get()[_iRank];
640                 pImg[i]  = pPoly->getImg()[_iRank];
641             }
642         }
643     }
644     else
645     {
646         for (int i = 0 ; i < getSize() ; i++)
647         {
648             SinglePoly *pPoly = m_pRealData[i];
649             if (pPoly->getRank() >= _iRank)
650             {
651                 pReal[i] = pPoly->get()[_iRank];
652             }
653         }
654     }
655
656     return pdbl;
657 }
658
659 bool Polynom::insertCoef(int _iRank, Double* _pCoef)
660 {
661     double *pReal = _pCoef->getReal();
662     if (isComplex())
663     {
664         double *pImg  = _pCoef->getImg();
665         for (int i = 0 ; i < getSize() ; i++)
666         {
667             SinglePoly *pPoly = m_pRealData[i];
668             if (pPoly->getRank() <= _iRank)
669             {
670                 return false;
671             }
672
673             pPoly->get()[_iRank] = pReal[i];
674             pPoly->getImg()[_iRank] = pImg[i];
675         }
676     }
677     else
678     {
679         for (int i = 0 ; i < getSize() ; i++)
680         {
681             SinglePoly *pPoly = m_pRealData[i];
682             if (pPoly->getRank() <= _iRank)
683             {
684                 return false;
685             }
686
687             pPoly->get()[_iRank] = pReal[i];
688         }
689     }
690
691     return true;
692 }
693
694 bool Polynom::operator==(const InternalType& it)
695 {
696     if (const_cast<InternalType &>(it).isPoly() == false)
697     {
698         return false;
699     }
700
701     Polynom* pM = const_cast<InternalType &>(it).getAs<types::Polynom>();
702
703     if (pM->getRows() != getRows() || pM->getCols() != getCols())
704     {
705         return false;
706     }
707
708     for (int i = 0 ; i < getSize() ; i++)
709     {
710         SinglePoly* p1 = get(i);
711         SinglePoly* p2 = pM->get(i);
712
713         if (*p1 != *p2)
714         {
715             return false;
716         }
717     }
718     return true;
719 }
720
721 bool Polynom::operator!=(const InternalType& it)
722 {
723     return !(*this == it);
724 }
725
726 SinglePoly* Polynom::getNullValue()
727 {
728     return new SinglePoly();
729 }
730
731 Polynom* Polynom::createEmpty(int _iDims, int* _piDims, bool /*_bComplex*/)
732 {
733     return new Polynom(getVariableName(), _iDims, _piDims, NULL);
734 }
735
736 SinglePoly* Polynom::copyValue(SinglePoly* _pData)
737 {
738     if (_pData == NULL)
739     {
740         return NULL;
741     }
742     return _pData->clone();
743 }
744
745 void Polynom::deleteAll()
746 {
747     for (int i = 0 ; i < m_iSizeMax ; i++)
748     {
749         m_pRealData[i]->killMe();
750     }
751     delete[] m_pRealData;
752     m_pRealData = NULL;
753     deleteImg();
754 }
755
756 void Polynom::deleteImg()
757 {
758
759 }
760
761 SinglePoly** Polynom::allocData(int _iSize)
762 {
763     SinglePoly** pData = new SinglePoly*[_iSize];
764     memset(pData, 0x00, _iSize * sizeof(SinglePoly*));
765     return pData;
766 }
767
768 void Polynom::deleteData(SinglePoly* data)
769 {
770     if (data)
771     {
772         data->killMe();
773     }
774 }
775
776 //overload to check variable name and call arrayof<>::insert after
777 Polynom* Polynom::insert(typed_list* _pArgs, InternalType* _pSource)
778 {
779     Polynom* p = _pSource->getAs<Polynom>();
780     if (p->getVariableName() != getVariableName())
781     {
782         char szError[512];
783         os_sprintf(szError, _("Input arguments should have the same formal variable name.\n"));
784         wchar_t* pwstError = to_wide_string(szError);
785         std::wstring wstError(pwstError);
786         FREE(pwstError);
787         throw ast::InternalError(wstError);
788     }
789
790     return ArrayOf<SinglePoly*>::insert(_pArgs, _pSource)->getAs<Polynom>();
791 }
792
793 Polynom* Polynom::Dollar()
794 {
795     int iRank = 1;
796     Polynom* pDollar = new Polynom(L"$", 1, 1, &iRank);
797     double* pdblCoef = pDollar->get(0)->get();
798     pdblCoef[0] = 0;
799     pdblCoef[1] = 1;
800
801     return pDollar;
802 }
803
804 bool Polynom::isDollar()
805 {
806     if (m_szVarName != L"$" || getSize() != 1)
807     {
808         return false;
809     }
810
811     double* pCoef = get(0)->get();
812
813     if (pCoef[0] != 0 && pCoef[1] != 1)
814     {
815         return false;
816     }
817
818     return true;
819 }
820
821 }
822