00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <ctime>
00029 #if defined (HAVE_UNORDERED_MAP)
00030 #include <unordered_map>
00031 #elif defined (HAVE_TR1_UNORDERED_MAP)
00032 #include <tr1/unordered_map>
00033 #endif
00034 #include <string>
00035
00036 #include "f77-fcn.h"
00037 #include "lo-mappers.h"
00038 #include "oct-rand.h"
00039 #include "quit.h"
00040
00041 #include "defun-dld.h"
00042 #include "error.h"
00043 #include "gripes.h"
00044 #include "oct-obj.h"
00045 #include "unwind-prot.h"
00046 #include "utils.h"
00047 #include "ov-re-mat.h"
00048
00049
00050
00051
00052
00053
00054
00055 static octave_value
00056 do_rand (const octave_value_list& args, int nargin, const char *fcn,
00057 const std::string& distribution, bool additional_arg = false)
00058 {
00059 octave_value retval;
00060 NDArray a;
00061 int idx = 0;
00062 dim_vector dims;
00063
00064 unwind_protect frame;
00065
00066 frame.add_fcn (octave_rand::distribution,
00067 octave_rand::distribution ());
00068
00069 octave_rand::distribution (distribution);
00070
00071 if (additional_arg)
00072 {
00073 if (nargin == 0)
00074 {
00075 error ("%s: expecting at least one argument", fcn);
00076 goto done;
00077 }
00078 else if (args(0).is_string())
00079 additional_arg = false;
00080 else
00081 {
00082 a = args(0).array_value ();
00083 if (error_state)
00084 {
00085 error ("%s: expecting scalar or matrix arguments", fcn);
00086 goto done;
00087 }
00088 idx++;
00089 nargin--;
00090 }
00091 }
00092
00093 switch (nargin)
00094 {
00095 case 0:
00096 {
00097 if (additional_arg)
00098 dims = a.dims ();
00099 else
00100 {
00101 dims.resize (2);
00102
00103 dims(0) = 1;
00104 dims(1) = 1;
00105 }
00106 goto gen_matrix;
00107 }
00108 break;
00109
00110 case 1:
00111 {
00112 octave_value tmp = args(idx);
00113
00114 if (tmp.is_string ())
00115 {
00116 std::string s_arg = tmp.string_value ();
00117
00118 if (s_arg == "dist")
00119 {
00120 retval = octave_rand::distribution ();
00121 }
00122 else if (s_arg == "seed")
00123 {
00124 retval = octave_rand::seed ();
00125 }
00126 else if (s_arg == "state" || s_arg == "twister")
00127 {
00128 retval = octave_rand::state (fcn);
00129 }
00130 else if (s_arg == "uniform")
00131 {
00132 octave_rand::uniform_distribution ();
00133 }
00134 else if (s_arg == "normal")
00135 {
00136 octave_rand::normal_distribution ();
00137 }
00138 else if (s_arg == "exponential")
00139 {
00140 octave_rand::exponential_distribution ();
00141 }
00142 else if (s_arg == "poisson")
00143 {
00144 octave_rand::poisson_distribution ();
00145 }
00146 else if (s_arg == "gamma")
00147 {
00148 octave_rand::gamma_distribution ();
00149 }
00150 else
00151 error ("%s: unrecognized string argument", fcn);
00152 }
00153 else if (tmp.is_scalar_type ())
00154 {
00155 double dval = tmp.double_value ();
00156
00157 if (xisnan (dval))
00158 {
00159 error ("%s: NaN is invalid matrix dimension", fcn);
00160 }
00161 else
00162 {
00163 dims.resize (2);
00164
00165 dims(0) = NINTbig (tmp.double_value ());
00166 dims(1) = NINTbig (tmp.double_value ());
00167
00168 if (! error_state)
00169 goto gen_matrix;
00170 }
00171 }
00172 else if (tmp.is_range ())
00173 {
00174 Range r = tmp.range_value ();
00175
00176 if (r.all_elements_are_ints ())
00177 {
00178 octave_idx_type n = r.nelem ();
00179
00180 dims.resize (n);
00181
00182 octave_idx_type base = NINTbig (r.base ());
00183 octave_idx_type incr = NINTbig (r.inc ());
00184
00185 for (octave_idx_type i = 0; i < n; i++)
00186 {
00187
00188
00189 dims(i) = base >= 0 ? base : 0;
00190 base += incr;
00191 }
00192
00193 goto gen_matrix;
00194
00195 }
00196 else
00197 error ("%s: all elements of range must be integers",
00198 fcn);
00199 }
00200 else if (tmp.is_matrix_type ())
00201 {
00202 Array<int> iv = tmp.int_vector_value (true);
00203
00204 if (! error_state)
00205 {
00206 octave_idx_type len = iv.length ();
00207
00208 dims.resize (len);
00209
00210 for (octave_idx_type i = 0; i < len; i++)
00211 {
00212
00213
00214 octave_idx_type elt = iv(i);
00215 dims(i) = elt >=0 ? elt : 0;
00216 }
00217
00218 goto gen_matrix;
00219 }
00220 else
00221 error ("%s: expecting integer vector", fcn);
00222 }
00223 else
00224 {
00225 gripe_wrong_type_arg ("rand", tmp);
00226 return retval;
00227 }
00228 }
00229 break;
00230
00231 default:
00232 {
00233 octave_value tmp = args(idx);
00234
00235 if (nargin == 2 && tmp.is_string ())
00236 {
00237 std::string ts = tmp.string_value ();
00238
00239 if (ts == "seed")
00240 {
00241 if (args(idx+1).is_real_scalar ())
00242 {
00243 double d = args(idx+1).double_value ();
00244
00245 if (! error_state)
00246 octave_rand::seed (d);
00247 }
00248 else if (args(idx+1).is_string ()
00249 && args(idx+1).string_value() == "reset")
00250 octave_rand::reset ();
00251 else
00252 error ("%s: seed must be a real scalar", fcn);
00253 }
00254 else if (ts == "state" || ts == "twister")
00255 {
00256 if (args(idx+1).is_string ()
00257 && args(idx+1).string_value() == "reset")
00258 octave_rand::reset (fcn);
00259 else
00260 {
00261 ColumnVector s =
00262 ColumnVector (args(idx+1).vector_value(false, true));
00263
00264 if (! error_state)
00265 octave_rand::state (s, fcn);
00266 }
00267 }
00268 else
00269 error ("%s: unrecognized string argument", fcn);
00270 }
00271 else
00272 {
00273 dims.resize (nargin);
00274
00275 for (int i = 0; i < nargin; i++)
00276 {
00277 octave_idx_type elt = args(idx+i).int_value ();
00278 if (error_state)
00279 {
00280 error ("%s: expecting integer arguments", fcn);
00281 goto done;
00282 }
00283
00284 dims(i) = elt >= 0 ? elt : 0;
00285 }
00286
00287 goto gen_matrix;
00288 }
00289 }
00290 break;
00291 }
00292
00293 done:
00294
00295 return retval;
00296
00297 gen_matrix:
00298
00299 dims.chop_trailing_singletons ();
00300
00301 if (additional_arg)
00302 {
00303 if (a.length() == 1)
00304 return octave_rand::nd_array (dims, a(0));
00305 else
00306 {
00307 if (a.dims() != dims)
00308 {
00309 error ("%s: mismatch in argument size", fcn);
00310 return retval;
00311 }
00312 octave_idx_type len = a.length ();
00313 NDArray m (dims);
00314 double *v = m.fortran_vec ();
00315 for (octave_idx_type i = 0; i < len; i++)
00316 v[i] = octave_rand::scalar (a(i));
00317 return m;
00318 }
00319 }
00320 else
00321 return octave_rand::nd_array (dims);
00322 }
00323
00324 DEFUN_DLD (rand, args, ,
00325 "-*- texinfo -*-\n\
00326 @deftypefn {Loadable Function} {} rand (@var{n})\n\
00327 @deftypefnx {Loadable Function} {} rand (@var{n}, @var{m}, @dots{})\n\
00328 @deftypefnx {Loadable Function} {} rand ([@var{n} @var{m} @dots{}])\n\
00329 @deftypefnx {Loadable Function} {@var{v} =} rand (\"state\")\n\
00330 @deftypefnx {Loadable Function} {} rand (\"state\", @var{v})\n\
00331 @deftypefnx {Loadable Function} {} rand (\"state\", \"reset\")\n\
00332 @deftypefnx {Loadable Function} {@var{v} =} rand (\"seed\")\n\
00333 @deftypefnx {Loadable Function} {} rand (\"seed\", @var{v})\n\
00334 @deftypefnx {Loadable Function} {} rand (\"seed\", \"reset\")\n\
00335 Return a matrix with random elements uniformly distributed on the\n\
00336 interval (0, 1). The arguments are handled the same as the arguments\n\
00337 for @code{eye}.\n\
00338 \n\
00339 You can query the state of the random number generator using the\n\
00340 form\n\
00341 \n\
00342 @example\n\
00343 v = rand (\"state\")\n\
00344 @end example\n\
00345 \n\
00346 This returns a column vector @var{v} of length 625. Later, you can\n\
00347 restore the random number generator to the state @var{v}\n\
00348 using the form\n\
00349 \n\
00350 @example\n\
00351 rand (\"state\", v)\n\
00352 @end example\n\
00353 \n\
00354 @noindent\n\
00355 You may also initialize the state vector from an arbitrary vector of\n\
00356 length @leq{} 625 for @var{v}. This new state will be a hash based on the\n\
00357 value of @var{v}, not @var{v} itself.\n\
00358 \n\
00359 By default, the generator is initialized from @code{/dev/urandom} if it is\n\
00360 available, otherwise from CPU time, wall clock time, and the current\n\
00361 fraction of a second.\n\
00362 \n\
00363 To compute the pseudo-random sequence, @code{rand} uses the Mersenne\n\
00364 Twister with a period of @math{2^{19937}-1} (See M. Matsumoto and\n\
00365 T. Nishimura,\n\
00366 @cite{Mersenne Twister: A 623-dimensionally equidistributed uniform\n\
00367 pseudorandom number generator}, ACM Trans. on\n\
00368 Modeling and Computer Simulation Vol. 8, No. 1, pp. 3-30, January 1998,\n\
00369 @url{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html}).\n\
00370 Do @strong{not} use for cryptography without securely hashing\n\
00371 several returned values together, otherwise the generator state\n\
00372 can be learned after reading 624 consecutive values.\n\
00373 \n\
00374 Older versions of Octave used a different random number generator.\n\
00375 The new generator is used by default\n\
00376 as it is significantly faster than the old generator, and produces\n\
00377 random numbers with a significantly longer cycle time. However, in\n\
00378 some circumstances it might be desirable to obtain the same random\n\
00379 sequences as used by the old generators. To do this the keyword\n\
00380 \"seed\" is used to specify that the old generators should be use,\n\
00381 as in\n\
00382 \n\
00383 @example\n\
00384 rand (\"seed\", val)\n\
00385 @end example\n\
00386 \n\
00387 @noindent\n\
00388 which sets the seed of the generator to @var{val}. The seed of the\n\
00389 generator can be queried with\n\
00390 \n\
00391 @example\n\
00392 s = rand (\"seed\")\n\
00393 @end example\n\
00394 \n\
00395 However, it should be noted that querying the seed will not cause\n\
00396 @code{rand} to use the old generators, only setting the seed will.\n\
00397 To cause @code{rand} to once again use the new generators, the\n\
00398 keyword \"state\" should be used to reset the state of the @code{rand}.\n\
00399 \n\
00400 The state or seed of the generator can be reset to a new random value\n\
00401 using the \"reset\" keyword.\n\
00402 @seealso{randn, rande, randg, randp}\n\
00403 @end deftypefn")
00404 {
00405 octave_value retval;
00406
00407 int nargin = args.length ();
00408
00409 retval = do_rand (args, nargin, "rand", "uniform");
00410
00411 return retval;
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 static std::string current_distribution = octave_rand::distribution ();
00488
00489 DEFUN_DLD (randn, args, ,
00490 "-*- texinfo -*-\n\
00491 @deftypefn {Loadable Function} {} randn (@var{n})\n\
00492 @deftypefnx {Loadable Function} {} randn (@var{n}, @var{m}, @dots{})\n\
00493 @deftypefnx {Loadable Function} {} randn ([@var{n} @var{m} @dots{}])\n\
00494 @deftypefnx {Loadable Function} {@var{v} =} randn (\"state\")\n\
00495 @deftypefnx {Loadable Function} {} randn (\"state\", @var{v})\n\
00496 @deftypefnx {Loadable Function} {} randn (\"state\", \"reset\")\n\
00497 @deftypefnx {Loadable Function} {@var{v} =} randn (\"seed\")\n\
00498 @deftypefnx {Loadable Function} {} randn (\"seed\", @var{v})\n\
00499 @deftypefnx {Loadable Function} {} randn (\"seed\", \"reset\")\n\
00500 Return a matrix with normally distributed random\n\
00501 elements having zero mean and variance one. The arguments are\n\
00502 handled the same as the arguments for @code{rand}.\n\
00503 \n\
00504 By default, @code{randn} uses the Marsaglia and Tsang ``Ziggurat technique''\n\
00505 to transform from a uniform to a normal distribution.\n\
00506 \n\
00507 Reference: G. Marsaglia and W.W. Tsang,\n\
00508 @cite{Ziggurat Method for Generating Random Variables},\n\
00509 J. Statistical Software, vol 5, 2000,\n\
00510 @url{http://www.jstatsoft.org/v05/i08/})\n\
00511 \n\
00512 @seealso{rand, rande, randg, randp}\n\
00513 @end deftypefn")
00514 {
00515 octave_value retval;
00516
00517 int nargin = args.length ();
00518
00519 retval = do_rand (args, nargin, "randn", "normal");
00520
00521 return retval;
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 DEFUN_DLD (rande, args, ,
00556 "-*- texinfo -*-\n\
00557 @deftypefn {Loadable Function} {} rande (@var{n})\n\
00558 @deftypefnx {Loadable Function} {} rande (@var{n}, @var{m}, @dots{})\n\
00559 @deftypefnx {Loadable Function} {} rande ([@var{n} @var{m} @dots{}])\n\
00560 @deftypefnx {Loadable Function} {@var{v} =} rande (\"state\")\n\
00561 @deftypefnx {Loadable Function} {} rande (\"state\", @var{v})\n\
00562 @deftypefnx {Loadable Function} {} rande (\"state\", \"reset\")\n\
00563 @deftypefnx {Loadable Function} {@var{v} =} rande (\"seed\")\n\
00564 @deftypefnx {Loadable Function} {} rande (\"seed\", @var{v})\n\
00565 @deftypefnx {Loadable Function} {} rande (\"seed\", \"reset\")\n\
00566 Return a matrix with exponentially distributed random elements. The\n\
00567 arguments are handled the same as the arguments for @code{rand}.\n\
00568 \n\
00569 By default, @code{randn} uses the Marsaglia and Tsang ``Ziggurat technique''\n\
00570 to transform from a uniform to an exponential distribution.\n\
00571 \n\
00572 Reference: G. Marsaglia and W.W. Tsang,\n\
00573 @cite{Ziggurat Method for Generating Random Variables},\n\
00574 J. Statistical Software, vol 5, 2000,\n\
00575 @url{http://www.jstatsoft.org/v05/i08/})\n\
00576 \n\
00577 @seealso{rand, randn, randg, randp}\n\
00578 @end deftypefn")
00579 {
00580 octave_value retval;
00581
00582 int nargin = args.length ();
00583
00584 retval = do_rand (args, nargin, "rande", "exponential");
00585
00586 return retval;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 DEFUN_DLD (randg, args, ,
00623 "-*- texinfo -*-\n\
00624 @deftypefn {Loadable Function} {} randg (@var{n})\n\
00625 @deftypefnx {Loadable Function} {} randg (@var{n}, @var{m}, @dots{})\n\
00626 @deftypefnx {Loadable Function} {} randg ([@var{n} @var{m} @dots{}])\n\
00627 @deftypefnx {Loadable Function} {@var{v} =} randg (\"state\")\n\
00628 @deftypefnx {Loadable Function} {} randg (\"state\", @var{v})\n\
00629 @deftypefnx {Loadable Function} {} randg (\"state\", \"reset\")\n\
00630 @deftypefnx {Loadable Function} {@var{v} =} randg (\"seed\")\n\
00631 @deftypefnx {Loadable Function} {} randg (\"seed\", @var{v})\n\
00632 @deftypefnx {Loadable Function} {} randg (\"seed\", \"reset\")\n\
00633 Return a matrix with @code{gamma(@var{a},1)} distributed random elements.\n\
00634 The arguments are handled the same as the arguments for @code{rand},\n\
00635 except for the argument @var{a}.\n\
00636 \n\
00637 This can be used to generate many distributions:\n\
00638 \n\
00639 @table @asis\n\
00640 @item @code{gamma (a, b)} for @code{a > -1}, @code{b > 0}\n\
00641 \n\
00642 @example\n\
00643 r = b * randg (a)\n\
00644 @end example\n\
00645 \n\
00646 @item @code{beta (a, b)} for @code{a > -1}, @code{b > -1}\n\
00647 \n\
00648 @example\n\
00649 @group\n\
00650 r1 = randg (a, 1)\n\
00651 r = r1 / (r1 + randg (b, 1))\n\
00652 @end group\n\
00653 @end example\n\
00654 \n\
00655 @item @code{Erlang (a, n)}\n\
00656 \n\
00657 @example\n\
00658 r = a * randg (n)\n\
00659 @end example\n\
00660 \n\
00661 @item @code{chisq (df)} for @code{df > 0}\n\
00662 \n\
00663 @example\n\
00664 r = 2 * randg (df / 2)\n\
00665 @end example\n\
00666 \n\
00667 @item @code{t (df)} for @code{0 < df < inf} (use randn if df is infinite)\n\
00668 \n\
00669 @example\n\
00670 r = randn () / sqrt (2 * randg (df / 2) / df)\n\
00671 @end example\n\
00672 \n\
00673 @item @code{F (n1, n2)} for @code{0 < n1}, @code{0 < n2}\n\
00674 \n\
00675 @example\n\
00676 @group\n\
00677 ## r1 equals 1 if n1 is infinite\n\
00678 r1 = 2 * randg (n1 / 2) / n1\n\
00679 ## r2 equals 1 if n2 is infinite\n\
00680 r2 = 2 * randg (n2 / 2) / n2\n\
00681 r = r1 / r2\n\n\
00682 @end group\n\
00683 @end example\n\
00684 \n\
00685 @item negative @code{binomial (n, p)} for @code{n > 0}, @code{0 < p <= 1}\n\
00686 \n\
00687 @example\n\
00688 r = randp ((1 - p) / p * randg (n))\n\
00689 @end example\n\
00690 \n\
00691 @item non-central @code{chisq (df, L)}, for @code{df >= 0} and @code{L > 0}\n\
00692 (use chisq if @code{L = 0})\n\
00693 \n\
00694 @example\n\
00695 @group\n\
00696 r = randp (L / 2)\n\
00697 r(r > 0) = 2 * randg (r(r > 0))\n\
00698 r(df > 0) += 2 * randg (df(df > 0)/2)\n\
00699 @end group\n\
00700 @end example\n\
00701 \n\
00702 @item @code{Dirichlet (a1, @dots{} ak)}\n\
00703 \n\
00704 @example\n\
00705 @group\n\
00706 r = (randg (a1), @dots{}, randg (ak))\n\
00707 r = r / sum (r)\n\
00708 @end group\n\
00709 @end example\n\
00710 \n\
00711 @end table\n\
00712 @seealso{rand, randn, rande, randp}\n\
00713 @end deftypefn")
00714 {
00715 octave_value retval;
00716
00717 int nargin = args.length ();
00718
00719 if (nargin < 1)
00720 error ("randg: insufficient arguments");
00721 else
00722 retval = do_rand (args, nargin, "randg", "gamma", true);
00723
00724 return retval;
00725 }
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879 DEFUN_DLD (randp, args, ,
00880 "-*- texinfo -*-\n\
00881 @deftypefn {Loadable Function} {} randp (@var{l}, @var{n})\n\
00882 @deftypefnx {Loadable Function} {} randp (@var{l}, @var{n}, @var{m}, @dots{})\n\
00883 @deftypefnx {Loadable Function} {} randp (@var{l}, [@var{n} @var{m} @dots{}])\n\
00884 @deftypefnx {Loadable Function} {@var{v} =} randp (\"state\")\n\
00885 @deftypefnx {Loadable Function} {} randp (\"state\", @var{v})\n\
00886 @deftypefnx {Loadable Function} {} randp (\"state\", \"reset\")\n\
00887 @deftypefnx {Loadable Function} {@var{v} =} randp (\"seed\")\n\
00888 @deftypefnx {Loadable Function} {} randp (\"seed\", @var{v})\n\
00889 @deftypefnx {Loadable Function} {} randp (\"seed\", \"reset\")\n\
00890 Return a matrix with Poisson distributed random elements with mean value\n\
00891 parameter given by the first argument, @var{l}. The arguments\n\
00892 are handled the same as the arguments for @code{rand}, except for the\n\
00893 argument @var{l}.\n\
00894 \n\
00895 Five different algorithms are used depending on the range of @var{l}\n\
00896 and whether or not @var{l} is a scalar or a matrix.\n\
00897 \n\
00898 @table @asis\n\
00899 @item For scalar @var{l} @leq{} 12, use direct method.\n\
00900 W.H. Press, et al., @cite{Numerical Recipes in C},\n\
00901 Cambridge University Press, 1992.\n\
00902 \n\
00903 @item For scalar @var{l} > 12, use rejection method.[1]\n\
00904 W.H. Press, et al., @cite{Numerical Recipes in C},\n\
00905 Cambridge University Press, 1992.\n\
00906 \n\
00907 @item For matrix @var{l} @leq{} 10, use inversion method.[2]\n\
00908 E. Stadlober, et al., WinRand source code, available via FTP.\n\
00909 \n\
00910 @item For matrix @var{l} > 10, use patchwork rejection method.\n\
00911 E. Stadlober, et al., WinRand source code, available via FTP, or\n\
00912 H. Zechner, @cite{Efficient sampling from continuous and discrete\n\
00913 unimodal distributions}, Doctoral Dissertation, 156pp., Technical\n\
00914 University Graz, Austria, 1994.\n\
00915 \n\
00916 @item For @var{l} > 1e8, use normal approximation.\n\
00917 L. Montanet, et al., @cite{Review of Particle Properties}, Physical Review\n\
00918 D 50 p1284, 1994.\n\
00919 @end table\n\
00920 @seealso{rand, randn, rande, randg}\n\
00921 @end deftypefn")
00922 {
00923 octave_value retval;
00924
00925 int nargin = args.length ();
00926
00927 if (nargin < 1)
00928 error ("randp: insufficient arguments");
00929 else
00930 retval = do_rand (args, nargin, "randp", "poisson", true);
00931
00932 return retval;
00933 }
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 DEFUN_DLD (randperm, args, ,
01022 "-*- texinfo -*-\n\
01023 @deftypefn {Loadable Function} {} randperm (@var{n})\n\
01024 @deftypefnx {Loadable Function} {} randperm (@var{n}, @var{m})\n\
01025 Return a row vector containing a random permutation of @code{1:@var{n}}.\n\
01026 If @var{m} is supplied, return @var{m} unique entries, sampled without\n\
01027 replacement from @code{1:@var{n}}. The complexity is O(@var{n}) in\n\
01028 memory and O(@var{m}) in time, unless @var{m} < @var{n}/5, in which case\n\
01029 O(@var{m}) memory is used as well. The randomization is performed using\n\
01030 rand(). All permutations are equally likely.\n\
01031 @seealso{perms}\n\
01032 @end deftypefn")
01033 {
01034
01035 #ifdef USE_UNORDERED_MAP_WITH_TR1
01036 using std::tr1::unordered_map;
01037 #else
01038 using std::unordered_map;
01039 #endif
01040
01041 int nargin = args.length ();
01042 octave_value retval;
01043
01044 if (nargin == 1 || nargin == 2)
01045 {
01046 octave_idx_type n, m;
01047
01048 n = args(0).idx_type_value (true);
01049
01050 if (nargin == 2)
01051 m = args(1).idx_type_value (true);
01052 else
01053 m = n;
01054
01055 if (m < 0 || n < 0)
01056 error ("randperm: M and N must be non-negative");
01057
01058 if (m > n)
01059 error ("randperm: M must be less than or equal to N");
01060
01061
01062
01063 bool short_shuffle = m < n/5 && m < 1e5;
01064
01065 if (! error_state)
01066 {
01067
01068 NDArray r = octave_rand::nd_array (dim_vector (1, m));
01069 double *rvec = r.fortran_vec ();
01070
01071 octave_idx_type idx_len = short_shuffle ? m : n;
01072 Array<octave_idx_type> idx (dim_vector (1, idx_len));
01073 octave_idx_type *ivec = idx.fortran_vec ();
01074
01075 for (octave_idx_type i = 0; i < idx_len; i++)
01076 ivec[i] = i;
01077
01078 if (short_shuffle)
01079 {
01080 unordered_map<octave_idx_type, octave_idx_type> map (m);
01081
01082
01083
01084 for (octave_idx_type i = 0; i < m; i++)
01085 {
01086 octave_idx_type k = i +
01087 gnulib::floor (rvec[i] * (n - i));
01088
01089
01090
01091 if (k < m)
01092 {
01093 std::swap (ivec[i], ivec[k]);
01094 }
01095 else
01096 {
01097 if (map.find (k) == map.end ())
01098 map[k] = k;
01099
01100 std::swap (ivec[i], map[k]);
01101 }
01102 }
01103 }
01104 else
01105 {
01106
01107
01108 for (octave_idx_type i = 0; i < m; i++)
01109 {
01110 octave_idx_type k = i +
01111 gnulib::floor (rvec[i] * (n - i));
01112 std::swap (ivec[i], ivec[k]);
01113 }
01114 }
01115
01116
01117 for (octave_idx_type i = 0; i < m; i++)
01118 rvec[i] = ivec[i] + 1;
01119
01120 if (m < n)
01121 idx.resize (dim_vector (1, m));
01122
01123
01124 retval = new octave_matrix (r, idx_vector (idx));
01125 }
01126 }
01127 else
01128 print_usage ();
01129
01130 return retval;
01131 }
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143