00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <map>
00028 #include <vector>
00029
00030 #include <stdint.h>
00031
00032 #include "data-conv.h"
00033 #include "f77-fcn.h"
00034 #include "lo-error.h"
00035 #include "lo-ieee.h"
00036 #include "lo-mappers.h"
00037 #include "mach-info.h"
00038 #include "oct-locbuf.h"
00039 #include "oct-rand.h"
00040 #include "oct-time.h"
00041 #include "randgamma.h"
00042 #include "randmtzig.h"
00043 #include "randpoisson.h"
00044 #include "singleton-cleanup.h"
00045
00046 extern "C"
00047 {
00048 F77_RET_T
00049 F77_FUNC (dgennor, DGENNOR) (const double&, const double&, double&);
00050
00051 F77_RET_T
00052 F77_FUNC (dgenunf, DGENUNF) (const double&, const double&, double&);
00053
00054 F77_RET_T
00055 F77_FUNC (dgenexp, DGENEXP) (const double&, double&);
00056
00057 F77_RET_T
00058 F77_FUNC (dignpoi, DIGNPOI) (const double&, double&);
00059
00060 F77_RET_T
00061 F77_FUNC (dgengam, DGENGAM) (const double&, const double&, double&);
00062
00063 F77_RET_T
00064 F77_FUNC (setall, SETALL) (const int32_t&, const int32_t&);
00065
00066 F77_RET_T
00067 F77_FUNC (getsd, GETSD) (int32_t&, int32_t&);
00068
00069 F77_RET_T
00070 F77_FUNC (setsd, SETSD) (const int32_t&, const int32_t&);
00071
00072 F77_RET_T
00073 F77_FUNC (setcgn, SETCGN) (const int32_t&);
00074 }
00075
00076 octave_rand *octave_rand::instance = 0;
00077
00078 octave_rand::octave_rand (void)
00079 : current_distribution (uniform_dist), use_old_generators (false),
00080 rand_states ()
00081 {
00082 initialize_ranlib_generators ();
00083
00084 initialize_mersenne_twister ();
00085 }
00086
00087 bool
00088 octave_rand::instance_ok (void)
00089 {
00090 bool retval = true;
00091
00092 if (! instance)
00093 {
00094 instance = new octave_rand ();
00095
00096 if (instance)
00097 singleton_cleanup_list::add (cleanup_instance);
00098 }
00099
00100 if (! instance)
00101 {
00102 (*current_liboctave_error_handler)
00103 ("unable to create octave_rand object!");
00104
00105 retval = false;
00106 }
00107
00108 return retval;
00109 }
00110
00111 double
00112 octave_rand::do_seed (void)
00113 {
00114 union d2i { double d; int32_t i[2]; };
00115 union d2i u;
00116
00117 oct_mach_info::float_format ff = oct_mach_info::native_float_format ();
00118
00119 switch (ff)
00120 {
00121 case oct_mach_info::flt_fmt_ieee_big_endian:
00122 F77_FUNC (getsd, GETSD) (u.i[1], u.i[0]);
00123 break;
00124 default:
00125 F77_FUNC (getsd, GETSD) (u.i[0], u.i[1]);
00126 break;
00127 }
00128
00129 return u.d;
00130 }
00131
00132 static int32_t
00133 force_to_fit_range (int32_t i, int32_t lo, int32_t hi)
00134 {
00135 assert (hi > lo && lo >= 0 && hi > lo);
00136
00137 i = i > 0 ? i : -i;
00138
00139 if (i < lo)
00140 i = lo;
00141 else if (i > hi)
00142 i = i % hi;
00143
00144 return i;
00145 }
00146
00147 void
00148 octave_rand::do_seed (double s)
00149 {
00150 use_old_generators = true;
00151
00152 int i0, i1;
00153 union d2i { double d; int32_t i[2]; };
00154 union d2i u;
00155 u.d = s;
00156
00157 oct_mach_info::float_format ff = oct_mach_info::native_float_format ();
00158
00159 switch (ff)
00160 {
00161 case oct_mach_info::flt_fmt_ieee_big_endian:
00162 i1 = force_to_fit_range (u.i[0], 1, 2147483563);
00163 i0 = force_to_fit_range (u.i[1], 1, 2147483399);
00164 break;
00165 default:
00166 i0 = force_to_fit_range (u.i[0], 1, 2147483563);
00167 i1 = force_to_fit_range (u.i[1], 1, 2147483399);
00168 break;
00169 }
00170
00171 F77_FUNC (setsd, SETSD) (i0, i1);
00172 }
00173
00174 void
00175 octave_rand::do_reset (void)
00176 {
00177 use_old_generators = true;
00178 initialize_ranlib_generators ();
00179 }
00180
00181 ColumnVector
00182 octave_rand::do_state (const std::string& d)
00183 {
00184 return rand_states[d.empty () ? current_distribution : get_dist_id (d)];
00185 }
00186
00187 void
00188 octave_rand::do_state (const ColumnVector& s, const std::string& d)
00189 {
00190 use_old_generators = false;
00191
00192 int old_dist = current_distribution;
00193
00194 int new_dist = d.empty () ? current_distribution : get_dist_id (d);
00195
00196 ColumnVector saved_state;
00197
00198 if (old_dist != new_dist)
00199 saved_state = get_internal_state ();
00200
00201 set_internal_state (s);
00202
00203 rand_states[new_dist] = get_internal_state ();
00204
00205 if (old_dist != new_dist)
00206 rand_states[old_dist] = saved_state;
00207 }
00208
00209 void
00210 octave_rand::do_reset (const std::string& d)
00211 {
00212 use_old_generators = false;
00213
00214 int old_dist = current_distribution;
00215
00216 int new_dist = d.empty () ? current_distribution : get_dist_id (d);
00217
00218 ColumnVector saved_state;
00219
00220 if (old_dist != new_dist)
00221 saved_state = get_internal_state ();
00222
00223 oct_init_by_entropy ();
00224 rand_states[new_dist] = get_internal_state ();
00225
00226 if (old_dist != new_dist)
00227 rand_states[old_dist] = saved_state;
00228 }
00229
00230 std::string
00231 octave_rand::do_distribution (void)
00232 {
00233 std::string retval;
00234
00235 switch (current_distribution)
00236 {
00237 case uniform_dist:
00238 retval = "uniform";
00239 break;
00240
00241 case normal_dist:
00242 retval = "normal";
00243 break;
00244
00245 case expon_dist:
00246 retval = "exponential";
00247 break;
00248
00249 case poisson_dist:
00250 retval = "poisson";
00251 break;
00252
00253 case gamma_dist:
00254 retval = "gamma";
00255 break;
00256
00257 default:
00258 (*current_liboctave_error_handler)
00259 ("rand: invalid distribution ID = %d", current_distribution);
00260 break;
00261 }
00262
00263 return retval;
00264 }
00265
00266 void
00267 octave_rand::do_distribution (const std::string& d)
00268 {
00269 int id = get_dist_id (d);
00270
00271 switch (id)
00272 {
00273 case uniform_dist:
00274 octave_rand::uniform_distribution ();
00275 break;
00276
00277 case normal_dist:
00278 octave_rand::normal_distribution ();
00279 break;
00280
00281 case expon_dist:
00282 octave_rand::exponential_distribution ();
00283 break;
00284
00285 case poisson_dist:
00286 octave_rand::poisson_distribution ();
00287 break;
00288
00289 case gamma_dist:
00290 octave_rand::gamma_distribution ();
00291 break;
00292
00293 default:
00294 (*current_liboctave_error_handler)
00295 ("rand: invalid distribution ID = %d", id);
00296 break;
00297 }
00298 }
00299
00300 void
00301 octave_rand::do_uniform_distribution (void)
00302 {
00303 switch_to_generator (uniform_dist);
00304
00305 F77_FUNC (setcgn, SETCGN) (uniform_dist);
00306 }
00307
00308 void
00309 octave_rand::do_normal_distribution (void)
00310 {
00311 switch_to_generator (normal_dist);
00312
00313 F77_FUNC (setcgn, SETCGN) (normal_dist);
00314 }
00315
00316 void
00317 octave_rand::do_exponential_distribution (void)
00318 {
00319 switch_to_generator (expon_dist);
00320
00321 F77_FUNC (setcgn, SETCGN) (expon_dist);
00322 }
00323
00324 void
00325 octave_rand::do_poisson_distribution (void)
00326 {
00327 switch_to_generator (poisson_dist);
00328
00329 F77_FUNC (setcgn, SETCGN) (poisson_dist);
00330 }
00331
00332 void
00333 octave_rand::do_gamma_distribution (void)
00334 {
00335 switch_to_generator (gamma_dist);
00336
00337 F77_FUNC (setcgn, SETCGN) (gamma_dist);
00338 }
00339
00340
00341 double
00342 octave_rand::do_scalar (double a)
00343 {
00344 double retval = 0.0;
00345
00346 if (use_old_generators)
00347 {
00348 switch (current_distribution)
00349 {
00350 case uniform_dist:
00351 F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, retval);
00352 break;
00353
00354 case normal_dist:
00355 F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, retval);
00356 break;
00357
00358 case expon_dist:
00359 F77_FUNC (dgenexp, DGENEXP) (1.0, retval);
00360 break;
00361
00362 case poisson_dist:
00363 if (a < 0.0 || xisnan(a) || xisinf(a))
00364 retval = octave_NaN;
00365 else
00366 {
00367
00368 F77_FUNC (dignpoi, DIGNPOI) (a + 1, retval);
00369 F77_FUNC (dignpoi, DIGNPOI) (a, retval);
00370 }
00371 break;
00372
00373 case gamma_dist:
00374 if (a <= 0.0 || xisnan(a) || xisinf(a))
00375 retval = octave_NaN;
00376 else
00377 F77_FUNC (dgengam, DGENGAM) (1.0, a, retval);
00378 break;
00379
00380 default:
00381 (*current_liboctave_error_handler)
00382 ("rand: invalid distribution ID = %d", current_distribution);
00383 break;
00384 }
00385 }
00386 else
00387 {
00388 switch (current_distribution)
00389 {
00390 case uniform_dist:
00391 retval = oct_randu ();
00392 break;
00393
00394 case normal_dist:
00395 retval = oct_randn ();
00396 break;
00397
00398 case expon_dist:
00399 retval = oct_rande ();
00400 break;
00401
00402 case poisson_dist:
00403 retval = oct_randp (a);
00404 break;
00405
00406 case gamma_dist:
00407 retval = oct_randg (a);
00408 break;
00409
00410 default:
00411 (*current_liboctave_error_handler)
00412 ("rand: invalid distribution ID = %d", current_distribution);
00413 break;
00414 }
00415
00416 save_state ();
00417 }
00418
00419 return retval;
00420 }
00421
00422 Matrix
00423 octave_rand::do_matrix (octave_idx_type n, octave_idx_type m, double a)
00424 {
00425 Matrix retval;
00426
00427 if (n >= 0 && m >= 0)
00428 {
00429 retval.clear (n, m);
00430
00431 if (n > 0 && m > 0)
00432 fill (retval.capacity(), retval.fortran_vec(), a);
00433 }
00434 else
00435 (*current_liboctave_error_handler) ("rand: invalid negative argument");
00436
00437 return retval;
00438 }
00439
00440 NDArray
00441 octave_rand::do_nd_array (const dim_vector& dims, double a)
00442 {
00443 NDArray retval;
00444
00445 if (! dims.all_zero ())
00446 {
00447 retval.clear (dims);
00448
00449 fill (retval.capacity(), retval.fortran_vec(), a);
00450 }
00451
00452 return retval;
00453 }
00454
00455 Array<double>
00456 octave_rand::do_vector (octave_idx_type n, double a)
00457 {
00458 Array<double> retval;
00459
00460 if (n > 0)
00461 {
00462 retval.clear (n, 1);
00463
00464 fill (retval.capacity (), retval.fortran_vec (), a);
00465 }
00466 else if (n < 0)
00467 (*current_liboctave_error_handler) ("rand: invalid negative argument");
00468
00469 return retval;
00470 }
00471
00472
00473
00474
00475
00476
00477 void
00478 octave_rand::initialize_ranlib_generators (void)
00479 {
00480 octave_localtime tm;
00481 int stored_distribution = current_distribution;
00482 F77_FUNC (setcgn, SETCGN) (uniform_dist);
00483
00484 int hour = tm.hour() + 1;
00485 int minute = tm.min() + 1;
00486 int second = tm.sec() + 1;
00487
00488 int32_t s0 = tm.mday() * hour * minute * second;
00489 int32_t s1 = hour * minute * second;
00490
00491 s0 = force_to_fit_range (s0, 1, 2147483563);
00492 s1 = force_to_fit_range (s1, 1, 2147483399);
00493
00494 F77_FUNC (setall, SETALL) (s0, s1);
00495 F77_FUNC (setcgn, SETCGN) (stored_distribution);
00496 }
00497
00498 void
00499 octave_rand::initialize_mersenne_twister (void)
00500 {
00501 oct_init_by_entropy ();
00502
00503 ColumnVector s = get_internal_state ();
00504
00505 rand_states[uniform_dist] = s;
00506
00507 oct_init_by_entropy ();
00508 s = get_internal_state ();
00509 rand_states[normal_dist] = s;
00510
00511 oct_init_by_entropy ();
00512 s = get_internal_state ();
00513 rand_states[expon_dist] = s;
00514
00515 oct_init_by_entropy ();
00516 s = get_internal_state ();
00517 rand_states[poisson_dist] = s;
00518
00519 oct_init_by_entropy ();
00520 s = get_internal_state ();
00521 rand_states[gamma_dist] = s;
00522 }
00523
00524 ColumnVector
00525 octave_rand::get_internal_state (void)
00526 {
00527 ColumnVector s (MT_N + 1);
00528
00529 OCTAVE_LOCAL_BUFFER (uint32_t, tmp, MT_N + 1);
00530
00531 oct_get_state (tmp);
00532
00533 for (octave_idx_type i = 0; i <= MT_N; i++)
00534 s.elem (i) = static_cast<double> (tmp [i]);
00535
00536 return s;
00537 }
00538
00539 void
00540 octave_rand::save_state (void)
00541 {
00542 rand_states[current_distribution] = get_internal_state ();;
00543 }
00544
00545 int
00546 octave_rand::get_dist_id (const std::string& d)
00547 {
00548 int retval = unknown_dist;
00549
00550 if (d == "uniform" || d == "rand")
00551 retval = uniform_dist;
00552 else if (d == "normal" || d == "randn")
00553 retval = normal_dist;
00554 else if (d == "exponential" || d == "rande")
00555 retval = expon_dist;
00556 else if (d == "poisson" || d == "randp")
00557 retval = poisson_dist;
00558 else if (d == "gamma" || d == "randg")
00559 retval = gamma_dist;
00560 else
00561 (*current_liboctave_error_handler)
00562 ("rand: invalid distribution '%s'", d.c_str ());
00563
00564 return retval;
00565 }
00566
00567 void
00568 octave_rand::set_internal_state (const ColumnVector& s)
00569 {
00570 octave_idx_type len = s.length ();
00571 octave_idx_type n = len < MT_N + 1 ? len : MT_N + 1;
00572
00573 OCTAVE_LOCAL_BUFFER (uint32_t, tmp, MT_N + 1);
00574
00575 for (octave_idx_type i = 0; i < n; i++)
00576 tmp[i] = static_cast<uint32_t> (s.elem(i));
00577
00578 if (len == MT_N + 1 && tmp[MT_N] <= MT_N && tmp[MT_N] > 0)
00579 oct_set_state (tmp);
00580 else
00581 oct_init_by_array (tmp, len);
00582 }
00583
00584 void
00585 octave_rand::switch_to_generator (int dist)
00586 {
00587 if (dist != current_distribution)
00588 {
00589 current_distribution = dist;
00590
00591 set_internal_state (rand_states[dist]);
00592 }
00593 }
00594
00595 #define MAKE_RAND(len) \
00596 do \
00597 { \
00598 double val; \
00599 for (volatile octave_idx_type i = 0; i < len; i++) \
00600 { \
00601 octave_quit (); \
00602 RAND_FUNC (val); \
00603 v[i] = val; \
00604 } \
00605 } \
00606 while (0)
00607
00608 void
00609 octave_rand::fill (octave_idx_type len, double *v, double a)
00610 {
00611 if (len < 1)
00612 return;
00613
00614 switch (current_distribution)
00615 {
00616 case uniform_dist:
00617 if (use_old_generators)
00618 {
00619 #define RAND_FUNC(x) F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, x)
00620 MAKE_RAND (len);
00621 #undef RAND_FUNC
00622 }
00623 else
00624 oct_fill_randu (len, v);
00625 break;
00626
00627 case normal_dist:
00628 if (use_old_generators)
00629 {
00630 #define RAND_FUNC(x) F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, x)
00631 MAKE_RAND (len);
00632 #undef RAND_FUNC
00633 }
00634 else
00635 oct_fill_randn (len, v);
00636 break;
00637
00638 case expon_dist:
00639 if (use_old_generators)
00640 {
00641 #define RAND_FUNC(x) F77_FUNC (dgenexp, DGENEXP) (1.0, x)
00642 MAKE_RAND (len);
00643 #undef RAND_FUNC
00644 }
00645 else
00646 oct_fill_rande (len, v);
00647 break;
00648
00649 case poisson_dist:
00650 if (use_old_generators)
00651 {
00652 if (a < 0.0 || xisnan(a) || xisinf(a))
00653 #define RAND_FUNC(x) x = octave_NaN;
00654 MAKE_RAND (len);
00655 #undef RAND_FUNC
00656 else
00657 {
00658
00659 double tmp;
00660 F77_FUNC (dignpoi, DIGNPOI) (a + 1, tmp);
00661 #define RAND_FUNC(x) F77_FUNC (dignpoi, DIGNPOI) (a, x)
00662 MAKE_RAND (len);
00663 #undef RAND_FUNC
00664 }
00665 }
00666 else
00667 oct_fill_randp (a, len, v);
00668 break;
00669
00670 case gamma_dist:
00671 if (use_old_generators)
00672 {
00673 if (a <= 0.0 || xisnan(a) || xisinf(a))
00674 #define RAND_FUNC(x) x = octave_NaN;
00675 MAKE_RAND (len);
00676 #undef RAND_FUNC
00677 else
00678 #define RAND_FUNC(x) F77_FUNC (dgengam, DGENGAM) (1.0, a, x)
00679 MAKE_RAND (len);
00680 #undef RAND_FUNC
00681 }
00682 else
00683 oct_fill_randg (a, len, v);
00684 break;
00685
00686 default:
00687 (*current_liboctave_error_handler)
00688 ("rand: invalid distribution ID = %d", current_distribution);
00689 break;
00690 }
00691
00692 save_state ();
00693
00694 return;
00695 }