[ast] improved polynomial display with unicode superscripts
[scilab.git] / scilab / modules / ast / src / cpp / types / singlepoly.cpp
index 1027ed4..04a15cf 100644 (file)
@@ -2,19 +2,23 @@
 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 *  Copyright (C) 2008-2008 - DIGITEO - Antoine ELIAS
 *
-*  This file must be used under the terms of the CeCILL.
-*  This source file is licensed as described in the file COPYING, which
-*  you should have received as part of this distribution.  The terms
-*  are also available at
-*  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+ * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ *
+ * This file is hereby licensed under the terms of the GNU GPL v2.0,
+ * pursuant to article 5.3.4 of the CeCILL v.2.1.
+ * This file was originally licensed under the terms of the CeCILL v2.1,
+ * and continues to be available under such terms.
+ * For more information, see the COPYING file which you should have received
+ * along with this program.
 *
 */
 #include <sstream>
-#include <math.h>
+#include <cmath>
 #include "singlepoly.hxx"
 #include "double.hxx"
 #include "tostring_common.hxx"
 #include "configvariable.hxx"
+#include "scilabWrite.hxx"
 
 extern "C"
 {
@@ -23,207 +27,233 @@ extern "C"
 #include "elem_common.h"
 }
 
-using namespace std;
-
 namespace types
 {
 SinglePoly::SinglePoly()
 {
-    int iRank = 1;
     double* pdblCoefR = NULL;
-    createPoly(&pdblCoefR, NULL, iRank);
+    int piDims[2] = {1, 1};
+    create(piDims, 2, &pdblCoefR, NULL);
     pdblCoefR[0] = 0;
+#ifndef NDEBUG
+    Inspector::addItem(this);
+#endif
 }
 
 SinglePoly::SinglePoly(double** _pdblCoefR, int _iRank)
 {
-    createPoly(_pdblCoefR, NULL, _iRank);
+    int piDims[2] = {_iRank + 1, 1};
+    create(piDims, 2, _pdblCoefR, NULL);
+#ifndef NDEBUG
+    Inspector::addItem(this);
+#endif
 }
 
 SinglePoly::SinglePoly(double** _pdblCoefR, double** _pdblCoefI, int _iRank)
 {
-    createPoly(_pdblCoefR, _pdblCoefI, _iRank);
+    int piDims[2] = {_iRank + 1, 1};
+    create(piDims, 2, _pdblCoefR, _pdblCoefI);
+#ifndef NDEBUG
+    Inspector::addItem(this);
+#endif
 }
 
-SinglePoly::SinglePoly(Double** _poCoefR, int _iRank)
+SinglePoly::~SinglePoly()
 {
-    double *pR = NULL;
-    double *pI = NULL;
-    createPoly(&pR, &pI, _iRank);
-    *_poCoefR = m_pdblCoef;
+    deleteAll();
+#ifndef NDEBUG
+    Inspector::removeItem(this);
+#endif
 }
 
+void SinglePoly::deleteAll()
+{
+    delete[] m_pRealData;
+    m_pRealData = NULL;
+    deleteImg();
+}
 
-SinglePoly::~SinglePoly()
+void SinglePoly::deleteImg()
 {
-    if (m_pdblCoef)
+    if (m_pImgData != NULL)
     {
-        delete m_pdblCoef;
+        delete[] m_pImgData;
+        m_pImgData = NULL;
     }
 }
 
-/*Real constructor, private only*/
-void SinglePoly::createPoly(double** _pdblCoefR, double** _pdblCoefI, int _iRank)
+double SinglePoly::getNullValue()
 {
-    double *pR = NULL;
-    double *pI = NULL;
-    m_bComplex = false;
-    m_iRank     = _iRank;
+    return 0;
+}
 
-    if (m_iRank == 0)
-    {
-        m_pdblCoef = NULL;
-        return;
-    }
+SinglePoly* SinglePoly::createEmpty(int /*_iDims*/, int* _piDims, bool _bComplex)
+{
+    double* pdblData = NULL;
+    SinglePoly* pSP = new SinglePoly(&pdblData, _piDims[0] - 1);
+    pSP->setComplex(_bComplex);
 
-    if (_pdblCoefI != NULL)
+    return pSP;
+}
+
+double* SinglePoly::allocData(int _iSize)
+{
+    double* pDbl = NULL;
+    try
     {
-        m_pdblCoef = new Double(1, _iRank, &pR, &pI);
+        if (_iSize < 0)
+        {
+            m_pRealData = NULL;
+            m_pImgData = NULL;
+            char message[bsiz];
+            os_sprintf(message, _("Can not allocate negative size (%d).\n"),  _iSize);
+            throw ast::InternalError(message);
+        }
+        else
+        {
+            pDbl = new double[_iSize];
+        }
     }
-    else
+    catch (std::bad_alloc &/*e*/)
     {
-        m_pdblCoef = new Double(1, _iRank, &pR);
+        char message[bsiz];
+        char byteString[9];
+        humanReadableByteCount(((size_t) m_iSize) * sizeof(double), byteString);
+        os_sprintf(message, _("Can not allocate %s memory.\n"), byteString);
+        throw ast::InternalError(message);
     }
 
-    m_pdblCoef->IncreaseRef();
-    m_pdblCoef->setZeros();
-    if (_pdblCoefR != NULL)
-    {
-        *_pdblCoefR = pR;
-    }
+    return pDbl;
+}
 
-    if (_pdblCoefI != NULL)
-    {
-        m_bComplex = true;
-        *_pdblCoefI = pI;
-    }
+double SinglePoly::copyValue(double _dblData)
+{
+    return _dblData;
 }
 
 int SinglePoly::getRank()
 {
-    return m_iRank;
+    return m_iSize - 1;
 }
 
-int SinglePoly::getRealRank()
+double SinglePoly::getDegree()
 {
-    return m_iRank - 1;
+    return m_iSize == 1 && m_pRealData[0] == 0 && (m_pImgData == NULL || m_pImgData[0] == 0) ? -INFINITY : m_iSize - 1;
 }
 
 bool SinglePoly::setRank(int _iRank, bool bSave)
 {
-    double *pR = NULL;
-    double *pI = NULL;
+    double *pR = NULL;
+    double *pI = NULL;
     if (bSave == false)
     {
-        if (m_iRank != _iRank)
+        if (getRank() != _iRank)
         {
-            delete m_pdblCoef;
-
-            if (m_bComplex == false)
+            int piDims[2] = {_iRank + 1, 1};
+            if (m_pImgData == NULL)
             {
-                createPoly(&pR, NULL, _iRank);
+                deleteAll();
+                create(piDims, 2, &pR, NULL);
             }
             else
             {
-                createPoly(&pR, &pI, _iRank);
+                deleteAll();
+                create(piDims, 2, &pR, &pI);
             }
+
             return true;
         }
+
         return true;
     }
     else
     {
-        Double *pCoef = NULL;
-        if (_iRank != 0)
+        double* pdblOldReal = m_pRealData;
+        double* pdblOldImg  = m_pImgData;
+        int iMinSize = Min(m_iSize, _iRank + 1);
+        int piDims[2] = {_iRank + 1, 1};
+
+        if (m_pImgData == NULL)
         {
-            pCoef = new Double(1, _iRank, &pR, &pI);
-            pCoef->set(m_pdblCoef->getReal());
-            pCoef->setComplex(m_pdblCoef->isComplex());
-            if (m_pdblCoef->isComplex())
-            {
-                pCoef->setImg(m_pdblCoef->getImg());
-            }
-            m_iRank = _iRank;
+            create(piDims, 2, &pR, NULL);
         }
         else
         {
-            m_iRank = 1;
-            pCoef = new Double(1, 1, &pR, &pI);
-            pCoef->setComplex(m_pdblCoef->isComplex());
-            pCoef->set(0, 0, 0);
+            create(piDims, 2, &pR, &pI);
+            memcpy(m_pImgData, pdblOldImg, iMinSize * sizeof(double));
         }
 
-        m_pdblCoef->DecreaseRef();
-        if (m_pdblCoef->isDeletable())
+        memcpy(m_pRealData, pdblOldReal, iMinSize * sizeof(double));
+
+        if (pdblOldImg)
         {
-            delete m_pdblCoef;
+            delete[] pdblOldImg;
+            pdblOldImg = NULL;
         }
 
-        m_pdblCoef = pCoef;
-        m_pdblCoef->IncreaseRef();
+        delete[] pdblOldReal;
+        pdblOldReal = NULL;
+
         return true;
     }
+
     return false;
 }
 
-Double* SinglePoly::getCoef()
+bool SinglePoly::setZeros()
 {
-    return m_pdblCoef;
-}
+    if (m_pRealData != NULL)
+    {
+        memset(m_pRealData, 0x00, m_iSize * sizeof(double));
+    }
+    else
+    {
+        return false;
+    }
 
-double* SinglePoly::getCoefReal()
-{
-    return m_pdblCoef->getReal();
-}
+    if (isComplex() == true)
+    {
+        if (m_pImgData != NULL)
+        {
+            memset(m_pImgData, 0x00, m_iSize * sizeof(double));
+        }
+        else
+        {
+            return false;
+        }
+    }
 
-double* SinglePoly::getCoefImg()
-{
-    return m_pdblCoef->getImg();
+    return true;
 }
 
 bool SinglePoly::setCoef(Double* _pdblCoefR)
 {
-    if (m_pdblCoef == NULL || _pdblCoefR == NULL)
+    if (m_pRealData == NULL || _pdblCoefR == NULL)
     {
         return false;
     }
 
-    double *pInR       = _pdblCoefR->getReal();
-    double *pInI       = _pdblCoefR->getImg();
+    double *pInR    = _pdblCoefR->getReal();
+    double *pInI    = _pdblCoefR->getImg();
 
     return setCoef(pInR, pInI);
 }
 
-void SinglePoly::setComplex(bool _bComplex)
-{
-    m_pdblCoef->setComplex(_bComplex);
-    m_bComplex = _bComplex;
-}
-
-bool SinglePoly::setCoef(double* _pdblCoefR, double* _pdblCoefI)
+bool SinglePoly::setCoef(const double* _pdblCoefR, const double* _pdblCoefI)
 {
-    if (m_pdblCoef == NULL)
-    {
-        return false;
-    }
-
     if (_pdblCoefI != NULL && isComplex() == false)
     {
-        m_pdblCoef->setComplex(true);
-        m_bComplex = true;
+        setComplex(true);
     }
 
-    double *pR = m_pdblCoef->getReal();
-    double *pI = m_pdblCoef->getImg();
-
-    if (_pdblCoefR != NULL && pR != NULL)
+    if (_pdblCoefR != NULL)
     {
-        memcpy(pR, _pdblCoefR, m_iRank * sizeof(double));
+        memcpy(m_pRealData, _pdblCoefR, m_iSize * sizeof(double));
     }
 
-    if (_pdblCoefI != NULL && pI != NULL)
+    if (_pdblCoefI != NULL)
     {
-        memcpy(pI, _pdblCoefI, m_iRank * sizeof(double));
+        memcpy(m_pImgData, _pdblCoefI, m_iSize * sizeof(double));
     }
 
     return true;
@@ -234,108 +264,65 @@ void SinglePoly::whoAmI()
     std::cout << "types::SinglePoly";
 }
 
-bool SinglePoly::isComplex()
-{
-    return m_bComplex;
-}
-
-GenericType* SinglePoly::getColumnValues(int _iPos)
-{
-    return NULL;
-}
-
 bool SinglePoly::evaluate(double _dblInR, double _dblInI, double *_pdblOutR, double *_pdblOutI)
 {
-    double *pCoefR = m_pdblCoef->getReal();
-    double *pCoefI = m_pdblCoef->getImg();
-
     *_pdblOutR = 0;
     *_pdblOutI = 0;
-    if (m_iRank == 0)
+    if (m_iSize == 0)
     {
         return true;
     }
 
-    for (int i = 0 ; i < m_iRank ; i++)
+    for (int i = 0 ; i < m_iSize ; i++)
     {
         //real part
-        *_pdblOutR += pCoefR[i] * pow(_dblInR, i);
+        *_pdblOutR += m_pRealData[i] * std::pow(_dblInR, i);
         //only if variable is complex
-        if (m_pdblCoef->isComplex())
+        if (isComplex())
         {
-            *_pdblOutR -= pCoefI[i] * pow(_dblInI, i);
+            *_pdblOutR -= m_pImgData[i] * std::pow(_dblInI, i);
             //img part
-            *_pdblOutI += pCoefI[i] * pow(_dblInR, i);
+            *_pdblOutI += m_pRealData[i] * std::pow(_dblInR, i);
         }
-        *_pdblOutI += pCoefR[i] * pow(_dblInI, i);
-    }
-
-    //old version, does not work
-    //for(int i = m_iRank - 1 ; i >= 0 ; i--)
-    //{
-    // //(a1 + ib1)(a2 + ib2)**n = (a1 + ib1) * exp(n * log(a2 + ib2))
-    // double dblLogR = 0;
-    // double dblLogI = 0;
-    // double dblExpR = 0;
-    // double dblExpI = 0;
-
-    // //log(a2 + ib2)
-    // if(_dblInI != 0)
-    // {
-    //         wlog(_dblInR, _dblInI, &dblLogR, &dblLogI);
-    // }
-    // else
-    // {
-    //         dblLogR = dlogs(_dblInR);
-    // }
-
-    // //n * log(a2 + ib2)
-    // dblLogR *= i;
-    // dblLogI *= i;
-
-    // //exp(n * log(a2 + ib2))
-    // if(dblLogI != 0)
-    // {
-    //         zexps(dblLogR, dblLogI, &dblExpR, &dblExpI);
-    // }
-    // else
-    // {
-    //         dblExpR = dexps(dblLogR);
-    // }
-
-    // //(a1 + ib1) * exp(n * log(a2 + ib2))
-    // if(m_pdblCoef->isComplex())
-    // {
-    //         *_pdblOutR += (dblExpR * pCoefR[i] - dblExpI * pCoefI[i]);
-    //         *_pdblOutI += (dblExpR * pCoefI[i] + dblExpI * pCoefR[i]);
-    // }
-    // else
-    // {
-    //         *_pdblOutR += (dblExpR * pCoefR[i]);
-    //         *_pdblOutI += (dblExpI * pCoefR[i]);
-    // }
-    //}
+        *_pdblOutI += m_pRealData[i] * std::pow(_dblInI, i);
+    }
+
     return true;
 }
 
 void SinglePoly::updateRank(void)
 {
-    double dblEps = getRelativeMachinePrecision();
-    int iNewRank = m_iRank;
-    double *pCoefR = getCoef()->getReal();
-    double *pCoefI = getCoef()->getImg();
-    for (int i = m_iRank - 1; i > 0 ; i--)
+    int iNewRank = getRank();
+    if (m_pImgData)
     {
-        if (fabs(pCoefR[i]) <= dblEps && (pCoefI != NULL ? fabs(pCoefI[i]) : 0) <= dblEps)
+        for (int i = getRank(); i > 0 ; i--)
         {
-            iNewRank--;
+            if (std::fabs(m_pRealData[i]) == 0.0 && std::fabs(m_pImgData[i]) == 0.0)
+            {
+                iNewRank--;
+            }
+            else
+            {
+                break;
+            }
         }
-        else
+    }
+    else
+    {
+        for (int i = getRank(); i > 0 ; i--)
         {
-            break;
+            if (std::fabs(m_pRealData[i]) == 0.0)
+            {
+                iNewRank--;
+            }
+            else
+            {
+                break;
+            }
         }
     }
-    if (iNewRank < m_iRank)
+
+    if (iNewRank < getRank())
     {
         setRank(iNewRank, true);
     }
@@ -347,122 +334,107 @@ bool SinglePoly::toString(std::wostringstream& ostr)
     return true;
 }
 
-void SinglePoly::toStringReal(wstring _szVar, list<wstring>* _pListExp , list<wstring>* _pListCoef)
+void SinglePoly::toStringReal(const std::wstring& _szVar, std::list<std::wstring>* _pListWstPoly)
 {
-    toStringInternal(m_pdblCoef->getReal(), _szVar, _pListExp, _pListCoef);
+    toStringInternal(m_pRealData, _szVar, _pListWstPoly);
 }
 
-void SinglePoly::toStringImg(wstring _szVar, list<wstring>* _pListExp , list<wstring>* _pListCoef)
+void SinglePoly::toStringImg(const std::wstring& _szVar, std::list<std::wstring>* _pListWstPoly)
 {
     if (isComplex() == false)
     {
-        _pListExp->clear();
-        _pListCoef->clear();
+        _pListWstPoly->clear();
         return;
     }
 
-    toStringInternal(m_pdblCoef->getImg(), _szVar, _pListExp, _pListCoef);
+    toStringInternal(m_pImgData, _szVar, _pListWstPoly);
 }
 
-void SinglePoly::toStringInternal(double *_pdblVal, wstring _szVar, list<wstring>* _pListExp , list<wstring>* _pListCoef)
+bool SinglePoly::subMatrixToString(std::wostringstream& /*ostr*/, int* /*_piDims*/, int /*_iDims*/)
 {
-    int iPrecision = ConfigVariable::getFormatSize();
-    int iLineLen = ConfigVariable::getConsoleWidth();
+    return false;
+}
 
-    wostringstream ostemp;
-    wostringstream ostemp2;
+void SinglePoly::toStringInternal(double *_pdblVal, const std::wstring& _szVar, std::list<std::wstring>* _pListWstPoly)
+{
+    int iLineLen = ConfigVariable::getConsoleWidth();
 
-    ostemp << L"  ";
-    ostemp2 << L"";
+    std::wstring strExponentDigits (L"\u2070\u00B9\u00B2\u00B3\u2074\u2075\u2076\u2077\u2078\u2079");
+    std::vector<int> iExponentsDigits = {0};
+    std::wostringstream ostemp;
+    bool bFirst = true;
 
-    //to add exponant value a the good place
-    int *piIndexExp = new int[m_iRank];
+    ostemp << L" ";
 
-    int iLen                           = 0;
-    int iLastFlush     = 2;
-    for (int i = 0 ; i < m_iRank ; i++)
+    int k;
+    int iLen = 0;
+    int iLastFlush = 2;
+    for (int i = 0 ; i < m_iSize ; i++)
     {
-        piIndexExp[i] = 0;
-        if (isRealZero(_pdblVal[i]) == false)
+        if (_pdblVal[i] != 0)
         {
             DoubleFormat df;
             getDoubleFormat(_pdblVal[i], &df);
 
-            if (iLen + df.iWidth + 2 >= iLineLen)
+            if (iLen + df.iWidth + df.iSignLen >= iLineLen - 1)
             {
-                //flush
-                for (int j = iLastFlush ; j < i ; j++)
-                {
-                    if (piIndexExp[j] == 0)
-                    {
-                        continue;
-                    }
-
-                    addSpaces(&ostemp2, piIndexExp[j] - static_cast<int>(ostemp2.str().size()));
-                    if (isRealZero(_pdblVal[j]) == false)
-                    {
-                        ostemp2 << j;
-                    }
-                }
                 iLastFlush = i;
-                _pListExp->push_back(ostemp2.str());
-                ostemp2.str(L""); //reset stream
-                addSpaces(&ostemp2, 12); //take from scilab ... why not ...
-
-                _pListCoef->push_back(ostemp.str());
+                _pListWstPoly->push_back(ostemp.str());
                 ostemp.str(L""); //reset stream
-                addSpaces(&ostemp, 12); //take from scilab ... why not ...
+                addSpaces(&ostemp, 1); //take from scilab ... why not ...
             }
 
-            bool bFirst = ostemp.str().size() == 2;
-
-            df.bPrintPoint = false;
-            df.bPrintPlusSign = ostemp.str().size() != 2;
+            // In scientific notation case bExp == true, so we have to print point (2.000D+10s)
+            // In other case don't print point (2s)
+            df.bPrintPoint = df.bExp;
+            df.bPrintPlusSign = bFirst == false;
             df.bPrintOne = i == 0;
+            bFirst = false;
             addDoubleValue(&ostemp, _pdblVal[i], &df);
-
-            if (i != 0)
+            
+            if (i == 0)
             {
-                ostemp << _szVar;
-                piIndexExp[i] = static_cast<int>(ostemp.str().size());
+                iLen = static_cast<int>(ostemp.str().size());
             }
-            ostemp << L" ";
-            iLen = static_cast<int>(ostemp.str().size());
-        }
-    }
-
-    if (iLastFlush != 0)
-    {
-        for (int j = iLastFlush ; j < m_iRank ; j++)
-        {
-            if (piIndexExp[j] == 0)
+            else if (i == 1)
             {
-                continue;
+                // add polynomial variable
+                ostemp << _szVar;
+                iLen = static_cast<int>(ostemp.str().size());
             }
-
-            addSpaces(&ostemp2, piIndexExp[j] - static_cast<int>(ostemp2.str().size()));
-            if (isRealZero(_pdblVal[j]) == false)
+            else
             {
-                ostemp2 << j;
-            }
+                // add polynomial variable and exponent
+                ostemp << _szVar;
+                for (auto it = iExponentsDigits.rbegin(); it != iExponentsDigits.rend(); ++it)
+                {
+                    ostemp << strExponentDigits[*it];
+                }
+                iLen = static_cast<int>(ostemp.str().size());            
+            }            
         }
 
-        if (ostemp.str() == L"  ")
+        for (k=0; k < iExponentsDigits.size() && iExponentsDigits[k] == 9; k++)
         {
-            ostemp << L"  0";
-            addSpaces(&ostemp2, static_cast<int>(ostemp.str().size()));
+            iExponentsDigits[k] = 0;
+        }
+        if (k == iExponentsDigits.size())
+        {
+            iExponentsDigits.push_back(0);
         }
+        iExponentsDigits[k]++;
+    }
 
-        if (ostemp2.str() == L"")
+    if (iLastFlush != 0)
+    {
+        if (ostemp.str() == L" ")
         {
-            addSpaces(&ostemp2, static_cast<int>(ostemp.str().size()));
+            ostemp << L"  0";
         }
 
-        _pListExp->push_back(ostemp2.str());
-        _pListCoef->push_back(ostemp.str());
+        _pListWstPoly->push_back(ostemp.str());
     }
 
-    delete[] piIndexExp;
     return;
 }
 
@@ -480,7 +452,52 @@ bool SinglePoly::operator==(const InternalType& it)
         return false;
     }
 
-    return *(getCoef()) == *(pP->getCoef());
+    double *pdblReal = pP->get();
+    for (int i = 0 ; i < getSize() ; i++)
+    {
+        if (m_pRealData[i] != pdblReal[i])
+        {
+            return false;
+        }
+    }
+
+    //both complex
+    if (isComplex() && pP->isComplex())
+    {
+        double *pdblImg = pP->getImg();
+        for (int i = 0 ; i < m_iSize ; i++)
+        {
+            if (m_pImgData[i] != pdblImg[i])
+            {
+                return false;
+            }
+        }
+    }
+    //pdbl complex check all img values == 0
+    else if (pP->isComplex())
+    {
+        double *pdblImg = pP->getImg();
+        for (int i = 0 ; i < m_iSize ; i++)
+        {
+            if (pdblImg[i])
+            {
+                return false;
+            }
+        }
+    }
+    //complex check all img values == 0
+    else if (isComplex())
+    {
+        for (int i = 0 ; i < m_iSize ; i++)
+        {
+            if (m_pImgData[i])
+            {
+                return false;
+            }
+        }
+    }
+
+    return true;
 }
 
 bool SinglePoly::operator!=(const InternalType& it)
@@ -496,26 +513,25 @@ SinglePoly* SinglePoly::clone()
     {
         double *pI = NULL;
         pPoly = new SinglePoly(&pR, &pI, getRank());
-        pPoly->setCoef(getCoefReal(), getCoefImg());
+        pPoly->setCoef(m_pRealData, m_pImgData);
     }
     else
     {
         pPoly = new SinglePoly(&pR, getRank());
-        pPoly->setCoef(getCoefReal(), NULL);
+        pPoly->setCoef(m_pRealData, NULL);
     }
     return pPoly;
 }
 
 SinglePoly* SinglePoly::conjugate()
 {
-    SinglePoly* pPoly = NULL;
     if (isComplex())
     {
         double *pR = NULL;
         double *pI = NULL;
         SinglePoly * pPoly = new SinglePoly(&pR, &pI, getRank());
 
-        Transposition::conjugate(getRank(), getCoefReal(), pR, getCoefImg(), pI);
+        Transposition::conjugate(m_iSize, m_pRealData, pR, m_pImgData, pI);
 
         return pPoly;
     }
@@ -524,6 +540,93 @@ SinglePoly* SinglePoly::conjugate()
         return clone();
     }
 }
+
+SinglePoly* operator*(const SinglePoly& _lhs, const SinglePoly& _rhs)
+{
+    SinglePoly& lhs = const_cast<SinglePoly &>(_lhs);
+    SinglePoly& rhs = const_cast<SinglePoly &>(_rhs);
+    SinglePoly* pOut = NULL;
+
+    bool isComplexL = lhs.isComplex();
+    bool isComplexR = rhs.isComplex();
+    bool isComplexOut = isComplexL || isComplexR;
+
+    int iRankL = lhs.getRank();
+    int iRankR = rhs.getRank();
+    int iRankOut = lhs.getRank() + rhs.getRank();
+
+    double* pdblOutR = NULL;
+    double* pdblOutI = NULL;
+    double* pdblLR = lhs.get();
+    double* pdblLI = lhs.getImg();
+    double* pdblRR = rhs.get();
+    double* pdblRI = rhs.getImg();
+
+    if (isComplexOut)
+    {
+        pOut = new SinglePoly(&pdblOutR, &pdblOutI, iRankOut);
+        memset(pdblOutR, 0x00, sizeof(double) * (iRankOut + 1));
+        memset(pdblOutI, 0x00, sizeof(double) * (iRankOut + 1));
+    }
+    else
+    {
+        pOut = new SinglePoly(&pdblOutR, iRankOut);
+        memset(pdblOutR, 0x00, sizeof(double) * (iRankOut + 1));
+    }
+
+    if (isComplexL)
+    {
+        if (isComplexR)
+        {
+            for (int i = 0 ; i < iRankL + 1; ++i)
+            {
+                for (int j = 0 ; j < iRankR + 1; ++j)
+                {
+                    pdblOutR[i + j]  += pdblLR[i] * pdblRR[j] - pdblLI[i] * pdblRI[j];
+                    pdblOutI[i + j]  += pdblLI[i] * pdblRR[j] + pdblLR[i] * pdblRI[j];
+                }
+            }
+        }
+        else
+        {
+            for (int i = 0 ; i < iRankL + 1 ; ++i)
+            {
+                for (int j = 0 ; j < iRankR + 1 ; ++j)
+                {
+                    pdblOutR[i + j]  += pdblLR[i] * pdblRR[j];
+                    pdblOutI[i + j]  += pdblLI[i] * pdblRR[j];
+                }
+            }
+        }
+    }
+    else
+    {
+        if (isComplexR)
+        {
+            for (int i = 0 ; i < iRankL + 1 ; ++i)
+            {
+                for (int j = 0 ; j < iRankR + 1 ; ++j)
+                {
+                    pdblOutR[i + j]  += pdblLR[i] * pdblRR[j];
+                    pdblOutI[i + j]  += pdblLR[i] * pdblRI[j];
+                }
+            }
+        }
+        else
+        {
+            for (int i = 0 ; i < iRankL + 1 ; ++i)
+            {
+                for (int j = 0 ; j < iRankR + 1 ; ++j)
+                {
+                    pdblOutR[i + j]  += pdblLR[i] * pdblRR[j];
+                }
+            }
+        }
+    }
+
+    return pOut;
 }
+}
+