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