Merge remote-tracking branch 'origin/master' into windows
[scilab.git] / scilab / modules / polynomials / sci_gateway / cpp / sci_simp.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Cedric DELAMARRE
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
17 #include <algorithm>
18
19 #include "polynomials_gw.hxx"
20 #include "function.hxx"
21 #include "double.hxx"
22 #include "polynom.hxx"
23 #include "overload.hxx"
24 #include "configvariable.hxx"
25
26 extern "C"
27 {
28 #include "Scierror.h"
29 #include "localization.h"
30     extern int C2F(dpsimp)(double*, int*, double*, int*, double*, int*, double*, int*, double*, int*);
31 }
32 /*--------------------------------------------------------------------------*/
33 types::Function::ReturnValue sci_simp(types::typed_list &in, int _iRetCount, types::typed_list &out)
34 {
35     types::InternalType* pNumOut = NULL;
36     types::InternalType* pDenOut = NULL;
37
38     bool bComplex   = false;
39     int iDouble     = 0;
40     int iSize       = 0;
41     int iMaxDegrNum = 0;
42     int iMaxDegrDen = 0;
43     int iErr        = 0;
44
45     std::string strName = "";
46
47     if (in.size() < 1 || in.size() > 2)
48     {
49         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "simp", 1, 2);
50         return types::Function::Error;
51     }
52
53     if (_iRetCount > 2)
54     {
55         Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), "simp", 1, 2);
56         return types::Function::Error;
57     }
58
59     if (ConfigVariable::getSimpMode() == 0)
60     {
61         std::copy(in.begin(), in.end(), std::back_inserter(out));
62         return types::Function::OK;
63     }
64
65     if (in.size() == 1)
66     {
67         // rational case
68         return Overload::call("%r_simp", in, _iRetCount, out);
69     }
70     else // simp(num, den)
71     {
72         if (_iRetCount != 2)
73         {
74             Scierror(78, _("%s: Wrong number of output argument(s): %d expected.\n"), "simp", 2);
75             return types::Function::Error;
76         }
77
78         for (int i = 0; i < in.size(); i++)
79         {
80             if (in[i]->isPoly() == false && in[i]->isDouble() == false)
81             {
82                 Scierror(999, _("%s: Wrong type for input argument #%d: A polynomial expected.\n"), "simp", i + 1);
83                 return types::Function::Error;
84             }
85
86             types::GenericType* pGT = in[i]->getAs<types::GenericType>();
87             bComplex |= pGT->isComplex();
88             iDouble  += in[i]->isDouble() ? i + 1 : 0;
89
90             if (i == 1 && pGT->getSize() != iSize)
91             {
92                 Scierror(999, _("%s: Wrong size for input argument #%d: Same size expected.\n"), "simp", 2);
93                 return types::Function::Error;
94             }
95
96             iSize = pGT->getSize();
97         }
98
99         if (bComplex)
100         {
101             return Overload::call("%p_simp", in, _iRetCount, out);
102         }
103
104         if (iDouble == 3) // simp(double, double)
105         {
106             return Overload::call("%s_simp", in, _iRetCount, out);
107         }
108
109         switch (iDouble)
110         {
111             case 0 : // sim(poly, poly)
112             {
113                 types::Polynom* pNum = in[0]->clone()->getAs<types::Polynom>();
114                 types::Polynom* pDen = in[1]->clone()->getAs<types::Polynom>();
115
116                 strName = pNum->getVariableName();
117
118                 if (strName != pDen->getVariableName())
119                 {
120                     Scierror(999, _("%s: Wrong value for input argument #%d: A polynomial '%s' expected.\n"), "simp", 2, strName.c_str());
121                     return types::Function::Error;
122                 }
123
124                 types::Polynom* pPolyNumOut = new types::Polynom(strName, pNum->getRows(), pNum->getCols());
125                 types::Polynom* pPolyDenOut = new types::Polynom(strName, pNum->getRows(), pNum->getCols());
126
127                 iMaxDegrNum = pNum->getMaxRank();
128                 iMaxDegrDen = pDen->getMaxRank();
129
130                 int iMax = std::max(iMaxDegrNum, iMaxDegrDen) + 1;
131                 int iSizeWork = 2 * (iMaxDegrNum + iMaxDegrDen) +
132                                 std::min(iMaxDegrNum, iMaxDegrDen) +
133                                 10 * iMax + 3 * iMax * iMax + 4;
134                 double* pdblWork = new double[iSizeWork];
135
136                 for (int i = 0; i < iSize; i++)
137                 {
138                     double* pdblNum = pNum->get(i)->get();
139                     double* pdblDen = pDen->get(i)->get();
140                     int iDegreeNum  = pNum->get(i)->getRank();
141                     int iDegreeDen  = pDen->get(i)->getRank();
142
143                     double* pdblNumOut = NULL;
144                     double* pdblDenOut = NULL;
145
146                     double* pdblNumTmp = new double[iDegreeNum + 1];
147                     double* pdblDenTmp = new double[iDegreeDen + 1];
148
149                     int iRankNumOut = 0;
150                     int iRankDenOut = 0;
151
152                     iErr = iSizeWork;
153
154                     C2F(dpsimp)(pdblNum, &iDegreeNum, pdblDen, &iDegreeDen,
155                                 pdblNumTmp, &iRankNumOut, pdblDenTmp, &iRankDenOut,
156                                 pdblWork, &iErr);
157
158                     if (iErr)
159                     {
160                         delete[] pdblNumTmp;
161                         delete[] pdblDenTmp;
162                         break;
163                     }
164
165                     types::SinglePoly* pSPNum = new types::SinglePoly(&pdblNumOut, iRankNumOut - 1);
166                     types::SinglePoly* pSPDen = new types::SinglePoly(&pdblDenOut, iRankDenOut - 1);
167
168                     memcpy(pdblNumOut, pdblNumTmp, iRankNumOut * sizeof(double));
169                     memcpy(pdblDenOut, pdblDenTmp, iRankDenOut * sizeof(double));
170
171                     pPolyNumOut->set(i, pSPNum);
172                     pPolyDenOut->set(i, pSPDen);
173
174                     delete[] pdblNumTmp;
175                     delete[] pdblDenTmp;
176                     delete pSPNum;
177                     delete pSPDen;
178                 }
179
180                 delete[] pdblWork;
181                 delete pNum;
182                 delete pDen;
183
184                 pNumOut = pPolyNumOut;
185                 pDenOut = pPolyDenOut;
186                 break;
187             }
188             case 1 : // sim(double, poly)
189             case 2 : // sim(poly, double)
190             {
191                 pNumOut = in[0];
192                 pDenOut = in[1];
193                 break;
194             }
195         }
196     }
197
198     if (iErr)
199     {
200         Scierror(999, _("%s: Wrong value for input argument #%d: A non null denominator expected.\n"), "simp", 2);
201         return types::Function::Error;
202     }
203
204     out.push_back(pNumOut);
205     out.push_back(pDenOut);
206     return types::Function::OK;
207 }
208 /*--------------------------------------------------------------------------*/
209