1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2003-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_oct_rand_h)
27 #define octave_oct_rand_h 1
28 
29 #include "octave-config.h"
30 
31 #include <map>
32 #include <string>
33 
34 #include "Array.h"
35 #include "dNDArray.h"
36 #include "fNDArray.h"
37 #include "lo-ieee.h"
38 #include "uint32NDArray.h"
39 
40 //class dim_vector;
41 
42 namespace octave
43 {
44   class OCTAVE_API rand
45   {
46   protected:
47 
48     rand (void);
49 
50   public:
51 
52     ~rand (void) = default;
53 
54     static bool instance_ok (void);
55 
56     // Return the current seed.
seed(void)57     static double seed (void)
58     {
59       return (instance_ok ()
60               ? instance->do_seed () : numeric_limits<double>::NaN ());
61     }
62 
63     // Set the seed.
seed(double s)64     static void seed (double s)
65     {
66       if (instance_ok ())
67         instance->do_seed (s);
68     }
69 
70     // Reset the seed.
reset(void)71     static void reset (void)
72     {
73       if (instance_ok ())
74         instance->do_reset ();
75     }
76 
77     // Return the current state.
78     static uint32NDArray state (const std::string& d = "")
79     {
80       return instance_ok () ? instance->do_state (d) : uint32NDArray ();
81     }
82 
83     // Set the current state/
84     static void state (const uint32NDArray& s,
85                        const std::string& d = "")
86     {
87       if (instance_ok ())
88         instance->do_state (s, d);
89     }
90 
91     // Reset the current state/
reset(const std::string & d)92     static void reset (const std::string& d)
93     {
94       if (instance_ok ())
95         instance->do_reset (d);
96     }
97 
98     // Return the current distribution.
distribution(void)99     static std::string distribution (void)
100     {
101       return instance_ok () ? instance->do_distribution () : "";
102     }
103 
104     // Set the current distribution.  May be either "uniform" (the
105     // default), "normal", "exponential", "poisson", or "gamma".
distribution(const std::string & d)106     static void distribution (const std::string& d)
107     {
108       if (instance_ok ())
109         instance->do_distribution (d);
110     }
111 
uniform_distribution(void)112     static void uniform_distribution (void)
113     {
114       if (instance_ok ())
115         instance->do_uniform_distribution ();
116     }
117 
normal_distribution(void)118     static void normal_distribution (void)
119     {
120       if (instance_ok ())
121         instance->do_normal_distribution ();
122     }
123 
exponential_distribution(void)124     static void exponential_distribution (void)
125     {
126       if (instance_ok ())
127         instance->do_exponential_distribution ();
128     }
129 
poisson_distribution(void)130     static void poisson_distribution (void)
131     {
132       if (instance_ok ())
133         instance->do_poisson_distribution ();
134     }
135 
gamma_distribution(void)136     static void gamma_distribution (void)
137     {
138       if (instance_ok ())
139         instance->do_gamma_distribution ();
140     }
141 
142     // Return the next number from the sequence.
143     static double scalar (double a = 1.0)
144     {
145       return (instance_ok ()
146               ? instance->do_scalar (a) : numeric_limits<double>::NaN ());
147     }
148 
149     // Return the next number from the sequence.
150     static float float_scalar (float a = 1.0)
151     {
152       return (instance_ok ()
153               ? instance->do_scalar (a) : numeric_limits<float>::NaN ());
154     }
155 
156     // Return an array of numbers from the sequence.
157     static Array<double> vector (octave_idx_type n, double a = 1.0)
158     {
159       return instance_ok () ? instance->do_vector (n, a) : Array<double> ();
160     }
161 
162     // Return an array of numbers from the sequence.
163     static Array<float> float_vector (octave_idx_type n, float a = 1.0)
164     {
165       return instance_ok () ? instance->do_vector (n, a) : Array<float> ();
166     }
167 
168     // Return an N-dimensional array of numbers from the sequence,
169     // filled in column major order.
170     static NDArray nd_array (const dim_vector& dims, double a = 1.0)
171     {
172       return instance_ok () ? instance->do_nd_array (dims, a) : NDArray ();
173     }
174 
175     // Return an N-dimensional array of numbers from the sequence,
176     // filled in column major order.
177     static FloatNDArray float_nd_array (const dim_vector& dims, float a = 1.0)
178     {
179       return (instance_ok ()
180               ? instance->do_float_nd_array (dims, a) : FloatNDArray ());
181     }
182 
183   private:
184 
185     static rand *instance;
186 
cleanup_instance(void)187     static void cleanup_instance (void) { delete instance; instance = nullptr; }
188 
189     enum
190     {
191       unknown_dist,
192       uniform_dist,
193       normal_dist,
194       expon_dist,
195       poisson_dist,
196       gamma_dist
197     };
198 
199     // Current distribution of random numbers.
200     int current_distribution;
201 
202     // If TRUE, use old RANLIB generators.  Otherwise, use Mersenne
203     // Twister generator.
204     bool use_old_generators;
205 
206     // Saved MT states.
207     std::map<int, uint32NDArray> rand_states;
208 
209     // Return the current seed.
210     double do_seed (void);
211 
212     // Set the seed.
213     void do_seed (double s);
214 
215     // Reset the seed.
216     void do_reset ();
217 
218     // Return the current state.
219     uint32NDArray do_state (const std::string& d);
220 
221     // Set the current state/
222     void do_state (const uint32NDArray& s, const std::string& d);
223 
224     // Reset the current state/
225     void do_reset (const std::string& d);
226 
227     // Return the current distribution.
228     std::string do_distribution (void);
229 
230     // Set the current distribution.  May be either "uniform" (the
231     // default), "normal", "exponential", "poisson", or "gamma".
232     void do_distribution (const std::string& d);
233 
234     void do_uniform_distribution (void);
235 
236     void do_normal_distribution (void);
237 
238     void do_exponential_distribution (void);
239 
240     void do_poisson_distribution (void);
241 
242     void do_gamma_distribution (void);
243 
244     // The following templates only make sense for double and float
245     // types.
246 
247     template <typename T> T uniform (void);
248 
249     template <typename T> T normal (void);
250 
251     template <typename T> T exponential (void);
252 
253     template <typename T> T poisson (T a);
254 
255     template <typename T> T gamma (T a);
256 
257     // Return the next number from the sequence.
258     template <typename T> T do_scalar (T a = 1);
259 
260     // Return an array of numbers from the sequence.
261     template <typename T> Array<T> do_vector (octave_idx_type n, T a = 1);
262 
263     // Return an N-dimensional array of numbers from the sequence,
264     // filled in column major order.
265     NDArray do_nd_array (const dim_vector& dims, double a = 1.);
266 
267     // Return an N-dimensional array of numbers from the sequence,
268     // filled in column major order.
269     FloatNDArray do_float_nd_array (const dim_vector& dims, float a = 1.);
270 
271     // Some helper functions.
272 
273     void initialize_ranlib_generators (void);
274 
275     void initialize_mersenne_twister (void);
276 
277     uint32NDArray get_internal_state (void);
278 
279     void save_state (void);
280 
281     int get_dist_id (const std::string& d);
282 
283     void set_internal_state (const uint32NDArray& s);
284 
285     void switch_to_generator (int dist);
286 
287     void fill (octave_idx_type len, double *v, double a);
288 
289     void fill (octave_idx_type len, float *v, float a);
290   };
291 }
292 
293 #endif
294