de7438eb4508e3da78edc340c6bb58ba2234eb8c
[scilab.git] / scilab / modules / elementary_functions / sci_gateway / cpp / sci_rand.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2011 - DIGITEO - Antoine ELIAS
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12 /*--------------------------------------------------------------------------*/
13 #include "elem_func_gw.hxx"
14 #include "function.hxx"
15 #include "overload.hxx"
16 #include "execvisitor.hxx"
17 #include "double.hxx"
18 #include "string.hxx"
19
20 extern "C"
21 {
22 #include "Scierror.h"
23 #include "localization.h"
24 #include "basic_functions.h"
25 }
26
27 #define Ran1            siRandSave              //old C2F(com).ran[0]
28 #define Ran2            siRandType              //old C2F(com).ran[1]
29
30 const wchar_t g_pwstConfigInfo[] = {L"info"};
31 const wchar_t g_pwstConfigSeed[] = {L"seed"};
32
33 const wchar_t g_pwstTypeUniform[] = {L"uniform"};
34 const wchar_t g_pwstTypeNormal[] = {L"normal"};
35
36 int setRandType(wchar_t _wcType);
37 double getNextRandValue(int _iRandType, int* _piRandSave, int _iForceInit);
38
39 types::Function::ReturnValue sci_rand(types::typed_list &in, int _iRetCount, types::typed_list &out)
40 {
41     static int siRandType = 0;
42     static int siRandSave = 0;
43     static int iForceInit       = 0;
44
45     int iSizeIn = (int)in.size();
46
47     if (iSizeIn == 0 || iSizeIn == -1)
48     {
49         //rand or rand()
50         double dblRand = getNextRandValue(siRandType, &siRandSave, 0);
51         out.push_back(new types::Double(dblRand));
52         return types::Function::OK;
53     }
54
55     if (in[0]->isString())
56     {
57         //rand("xxx")
58         types::String* pS = in[0]->getAs<types::String>();
59         if (pS->getSize() != 1)
60         {
61             Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "rand", 1);
62             return types::Function::Error;
63         }
64
65         wchar_t* pwstKey = pS->get(0);
66
67         if (pwstKey[0] == g_pwstConfigInfo[0])
68         {
69             //info
70             if (iSizeIn > 1)
71             {
72                 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "rand", 1);
73                 return types::Function::Error;
74             }
75
76             if (siRandType == 0)
77             {
78                 out.push_back(new types::String(g_pwstTypeUniform));
79             }
80             else
81             {
82                 out.push_back(new types::String(g_pwstTypeNormal));
83             }
84         }
85         else if (pwstKey[0] == g_pwstConfigSeed[0])
86         {
87             //seed
88             if (iSizeIn == 1)
89             {
90                 //get
91                 out.push_back(new types::Double(siRandSave));
92             }
93             else if (iSizeIn == 2)
94             {
95                 if (in[1]->isDouble() == false || in[1]->getAs<types::Double>()->isScalar() == false)
96                 {
97                     Scierror(999, _("%s: Wrong size for input argument #%d: A scalar expected.\n"), "rand", 2);
98                     return types::Function::Error;
99                 }
100
101                 siRandSave = (int)Max(in[1]->getAs<types::Double>()->get(0), 0);
102                 iForceInit = 1;
103             }
104             else
105             {
106                 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "rand", 2);
107                 return types::Function::Error;
108             }
109         }
110         else
111         {
112             siRandType = setRandType(pwstKey[0]);
113         }
114     }
115     else if (in[0]->isDouble())
116     {
117         int iRandSave = siRandType;
118         if (in[iSizeIn - 1]->isString())
119         {
120             //uniform ou normal
121             types::String* pS = in[iSizeIn - 1]->getAs<types::String>();
122             if (pS->getSize() != 1)
123             {
124                 Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "rand", iSizeIn);
125                 return types::Function::Error;
126             }
127
128             //set randomize law
129             iRandSave = siRandType;
130             siRandType = setRandType(pS->get(0)[0]);
131             iSizeIn--;
132         }
133
134         if (iSizeIn == 1)
135         {
136             //rand(X) or rand(X, "")
137             types::Double* pD = in[0]->getAs<types::Double>();
138
139             // rand(:)
140             if (pD->getRows() == -1 && pD->getCols() == -1)
141             {
142                 Scierror(21, _("Invalid index.\n"));
143                 return types::Function::Error;
144             }
145
146             types::Double* pOut = new types::Double(pD->getDims(), pD->getDimsArray(), pD->isComplex());
147
148             double* pReal = pOut->getReal();
149             for (int i = 0 ; i < pOut->getSize() ; i++)
150             {
151                 pReal[i] = getNextRandValue(siRandType, &siRandSave, iForceInit);
152             }
153
154             if (pD->isComplex())
155             {
156                 double* pImg = pOut->getImg();
157                 for (int i = 0 ; i < pOut->getSize() ; i++)
158                 {
159                     pImg[i] = getNextRandValue(siRandType, &siRandSave, iForceInit);
160                 }
161             }
162
163             out.push_back(pOut);
164
165             //retore previous law
166             siRandType = iRandSave;
167         }
168         else
169         {
170             int iDims = iSizeIn;
171             int *piDims = new int[iDims];
172
173             //check others parameter type and size
174             for (int i = 0 ; i < iSizeIn ; i++)
175             {
176                 if (in[i]->isDouble() == false || in[i]->getAs<types::Double>()->isScalar() == false)
177                 {
178                     Scierror(999, _("%s: Wrong type for input argument #%d: Real scalar expected.\n"), "rand" , i + 1);
179                     return types::Function::Error;
180                 }
181
182                 piDims[i] = (int)in[i]->getAs<types::Double>()->get(0);
183             }
184
185             types::Double* pOut = new types::Double(iDims, piDims);
186             delete[] piDims;
187
188             double* pd = pOut->get();
189             for (int i = 0 ; i < pOut->getSize() ; i++)
190             {
191                 pd[i] = getNextRandValue(siRandType, &siRandSave, iForceInit);
192                 iForceInit = 0;
193             }
194             out.push_back(pOut);
195         }
196     }
197     else
198     {
199         std::wstring wstFuncName = L"%"  + in[0]->getShortTypeStr() + L"_rand";
200         return Overload::call(wstFuncName, in, _iRetCount, out, new ast::ExecVisitor());
201     }
202
203     return types::Function::OK;
204 }
205 /*--------------------------------------------------------------------------*/
206 double getNextRandValue(int _iRandType, int* _piRandSave, int _iForceInit)
207 {
208     static int siInit       = TRUE;
209     static double sdblImg   = 0;
210     static double sdblR     = 0;
211     double dblReal          = 0;
212     double dblVal           = 0;
213     double dblTemp          = 2;
214
215     if (_iForceInit)
216     {
217         siInit = TRUE;
218     }
219
220     if (_iRandType == 0)
221     {
222         dblVal = durands(_piRandSave);
223     }
224     else
225     {
226         if (siInit == TRUE)
227         {
228             while (dblTemp > 1)
229             {
230                 dblReal = 2 * durands(_piRandSave) - 1;
231                 sdblImg = 2 * durands(_piRandSave) - 1;
232                 dblTemp = dblReal * dblReal + sdblImg * sdblImg;
233             }
234             sdblR   = dsqrts(-2 * dlogs(dblTemp) / dblTemp);
235             dblVal  = dblReal * sdblR;
236         }
237         else
238         {
239             dblVal = sdblImg * sdblR;
240         }
241         siInit = !siInit;
242     }
243     return dblVal;
244 }
245
246 int setRandType(wchar_t _wcType)
247 {
248     if (_wcType == L'g' || _wcType == L'n')
249     {
250         return 1;
251     }
252     return 0;
253 }
254 /*--------------------------------------------------------------------------*/