GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
rand.cc
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////*
2//
3// Copyright (C) 1996-2025 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 (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <unordered_map>
31#include <string>
32
33#include "f77-fcn.h"
34#include "lo-mappers.h"
35#include "oct-rand.h"
36#include "quit.h"
37
38#include "defun.h"
39#include "error.h"
40#include "errwarn.h"
41#include "ovl.h"
42#include "unwind-prot.h"
43#include "utils.h"
44#include "ov-re-mat.h"
45
47
48/*
49%% Restore all rand* "seed" and "state" values in order, so that the
50%% new "state" algorithm remains active after these tests complete.
51%!function restore_rand_states (seed, state)
52%! rand ("seed", seed.rand);
53%! rande ("seed", seed.rande);
54%! randg ("seed", seed.randg);
55%! randn ("seed", seed.randn);
56%! randp ("seed", seed.randp);
57%! rand ("state", state.rand);
58%! rande ("state", state.rande);
59%! randg ("state", state.randg);
60%! randn ("state", state.randn);
61%! randp ("state", state.randp);
62%!endfunction
63
64%!shared __random_statistical_tests__, old_seed, old_state, restore_state
65%! ## Flag whether the statistical tests should be run in "make check" or not
66%! __random_statistical_tests__ = 0;
67%! ## Save and restore the states of each of the random number generators
68%! ## that are tested by the unit tests in this file.
69%! old_seed.rand = rand ("seed");
70%! old_seed.rande = rande ("seed");
71%! old_seed.randg = randg ("seed");
72%! old_seed.randn = randn ("seed");
73%! old_seed.randp = randp ("seed");
74%! old_state.rand = rand ("state");
75%! old_state.rande = rande ("state");
76%! old_state.randg = randg ("state");
77%! old_state.randn = randn ("state");
78%! old_state.randp = randp ("state");
79%! restore_state = onCleanup (@() restore_rand_states (old_seed, old_state));
80*/
81
82static octave_value
83do_rand (const octave_value_list& args, int nargin, const char *fcn,
84 const std::string& distribution, bool additional_arg = false)
85{
86 NDArray a;
87 int idx = 0;
88 bool is_single = false;
89
90 if (nargin > 0 && args(nargin-1).is_string ())
91 {
92 std::string s_arg = args(nargin-1).string_value ();
93
94 if (s_arg == "single")
95 {
96 is_single = true;
97 nargin--;
98 }
99 else if (s_arg == "double")
100 nargin--;
101 }
102
103 if (additional_arg)
104 {
105 if (nargin == 0)
106 error ("%s: at least one argument is required", fcn);
107 else if (args(0).is_string ())
108 additional_arg = false;
109 else
110 {
111 a = args(0).xarray_value ("%s: dimension must be a scalar integer", fcn);
112
113 idx++;
114 nargin--;
115 }
116 }
117
118 octave_value retval;
119 dim_vector dims;
120
121 // Restore current distribution on any exit.
122 unwind_action restore_distribution
123 ([] (const std::string& old_distribution)
124 {
125 rand::distribution (old_distribution);
126 }, rand::distribution ());
127
128 rand::distribution (distribution);
129
130 switch (nargin)
131 {
132 case 0:
133 {
134 if (additional_arg)
135 dims = a.dims ();
136 else
137 {
138 dims.resize (2);
139
140 dims(0) = 1;
141 dims(1) = 1;
142 }
143
144 goto gen_matrix;
145 }
146 break;
147
148 case 1:
149 {
150 octave_value tmp = args(idx);
151
152 if (tmp.is_string ())
153 {
154 std::string s_arg = tmp.string_value ();
155
156 if (s_arg == "dist")
157 retval = rand::distribution ();
158 else if (s_arg == "seed")
159 retval = rand::seed ();
160 else if (s_arg == "state" || s_arg == "twister")
161 retval = rand::state (fcn);
162 else if (s_arg == "uniform")
164 else if (s_arg == "normal")
166 else if (s_arg == "exponential")
168 else if (s_arg == "poisson")
170 else if (s_arg == "gamma")
172 else
173 error ("%s: unrecognized string argument", fcn);
174 }
175 else if (tmp.is_scalar_type ())
176 {
177 octave_idx_type n = tmp.idx_type_value (true);
178
179 dims.resize (2);
180
181 dims(0) = dims(1) = n;
182
183 goto gen_matrix;
184 }
185 else if (tmp.is_range ())
186 {
187 range<double> r = tmp.range_value ();
188
189 if (! r.all_elements_are_ints ())
190 error ("%s: all elements of range must be integers", fcn);
191
192 octave_idx_type n = r.numel ();
193
194 dims.resize (n);
195
196 octave_idx_type base = math::nint_big (r.base ());
197 octave_idx_type incr = math::nint_big (r.increment ());
198
199 for (octave_idx_type i = 0; i < n; i++)
200 {
201 // Negative dimensions treated as zero for Matlab compatibility
202 dims(i) = (base >= 0 ? base : 0);
203 base += incr;
204 }
205
206 goto gen_matrix;
207 }
208 else if (tmp.is_matrix_type ())
209 {
211
212 try
213 {
214 iv = tmp.octave_idx_type_vector_value (true);
215 }
216 catch (execution_exception& ee)
217 {
218 error (ee, "%s: dimensions must be a scalar or array of integers", fcn);
219 }
220
221 octave_idx_type len = iv.numel ();
222
223 dims.resize (len);
224
225 for (octave_idx_type i = 0; i < len; i++)
226 {
227 // Negative dimensions treated as zero for Matlab compatibility
228 octave_idx_type elt = iv(i);
229 dims(i) = (elt >=0 ? elt : 0);
230 }
231
232 goto gen_matrix;
233 }
234 else
235 err_wrong_type_arg ("rand", tmp);
236 }
237 break;
238
239 default:
240 {
241 octave_value tmp = args(idx);
242
243 if (nargin == 2 && tmp.is_string ())
244 {
245 std::string ts = tmp.string_value ();
246
247 if (ts == "seed")
248 {
249 if (args(idx+1).is_real_scalar ())
250 {
251 double d = args(idx+1).double_value ();
252
253 rand::seed (d);
254 }
255 else if (args(idx+1).is_string ()
256 && args(idx+1).string_value () == "reset")
257 rand::reset ();
258 else
259 error ("%s: seed must be a real scalar", fcn);
260 }
261 else if (ts == "state" || ts == "twister")
262 {
263 if (args(idx+1).is_string ()
264 && args(idx+1).string_value () == "reset")
265 rand::reset (fcn);
266 else
267 {
269 = ColumnVector (args(idx+1).vector_value (false, true));
270
271 // Backwards compatibility with previous versions of
272 // Octave which mapped Inf to 0.
273 for (octave_idx_type i = 0; i < s.numel (); i++)
274 if (math::isinf (s.xelem (i)))
275 s.xelem (i) = 0.0;
276
277 rand::state (s, fcn);
278 }
279 }
280 else
281 error ("%s: unrecognized string argument", fcn);
282 }
283 else
284 {
285 dims.resize (nargin);
286
287 for (int i = 0; i < nargin; i++)
288 {
289 octave_idx_type elt = args(idx+i).idx_type_value (true);
290
291 // Negative dimensions treated as zero for Matlab compatibility
292 dims(i) = (elt >= 0 ? elt : 0);
293 }
294
295 goto gen_matrix;
296 }
297 }
298 break;
299 }
300
301 // No "goto gen_matrix" in code path. Must be done processing.
302 return retval;
303
304gen_matrix:
305
307
308 if (is_single)
309 {
310 if (additional_arg)
311 {
312 if (a.numel () == 1)
313 return rand::float_nd_array (dims, a(0));
314 else
315 {
316 if (a.dims () != dims)
317 error ("%s: mismatch in argument size", fcn);
318
320 FloatNDArray m (dims);
321 float *v = m.rwdata ();
322
323 for (octave_idx_type i = 0; i < len; i++)
324 v[i] = rand::float_scalar (a(i));
325
326 return m;
327 }
328 }
329 else
330 return rand::float_nd_array (dims);
331 }
332 else
333 {
334 if (additional_arg)
335 {
336 if (a.numel () == 1)
337 return rand::nd_array (dims, a(0));
338 else
339 {
340 if (a.dims () != dims)
341 error ("%s: mismatch in argument size", fcn);
342
344 NDArray m (dims);
345 double *v = m.rwdata ();
346
347 for (octave_idx_type i = 0; i < len; i++)
348 v[i] = rand::scalar (a(i));
349
350 return m;
351 }
352 }
353 else
354 return rand::nd_array (dims);
355 }
356}
357
358DEFUN (rand, args, ,
359 doc: /* -*- texinfo -*-
360@deftypefn {} {@var{x} =} rand (@var{n})
361@deftypefnx {} {@var{x} =} rand (@var{m}, @var{n}, @dots{})
362@deftypefnx {} {@var{x} =} rand ([@var{m} @var{n} @dots{}])
363@deftypefnx {} {@var{x} =} rand (@dots{}, "single")
364@deftypefnx {} {@var{x} =} rand (@dots{}, "double")
365@deftypefnx {} {@var{v} =} rand ("state")
366@deftypefnx {} {} rand ("state", @var{v})
367@deftypefnx {} {} rand ("state", "reset")
368@deftypefnx {} {@var{v} =} rand ("seed")
369@deftypefnx {} {} rand ("seed", @var{v})
370@deftypefnx {} {} rand ("seed", "reset")
371Return a matrix with random elements uniformly distributed on the
372interval (0, 1).
373
374The arguments are handled the same as the arguments for @code{eye}.
375
376You can query the state of the random number generator using the form
377
378@example
379v = rand ("state")
380@end example
381
382This returns a column vector @var{v} of length 625. Later, you can restore
383the random number generator to the state @var{v} using the form
384
385@example
386rand ("state", v)
387@end example
388
389@noindent
390You may also initialize the state vector from an arbitrary vector of length
391@leq{} 625 for @var{v}. This new state will be a hash based on the value of
392@var{v}, not @var{v} itself.
393
394By default, the generator is initialized by contributing entropy from the
395wall clock time, the CPU time, the current fraction of a second, the process
396ID and---if available---up to 1024 bits from the C++ random numbers source
397@code{random_device}, which might be non-deterministic (implementation
398specific). Note that this differs from @sc{matlab}, which always initializes
399the state to the same state at startup. To obtain behavior comparable to
400@sc{matlab}, initialize with a deterministic state vector in Octave's startup
401files (@pxref{Startup Files}).
402
403To compute the pseudo-random sequence, @code{rand} uses the Mersenne
404Twister with a period of @math{2^{19937}-1}
405(See @nospell{M. Matsumoto and T. Nishimura},
406@cite{Mersenne Twister: A 623-dimensionally equidistributed uniform
407pseudorandom number generator},
408@nospell{ACM} Trans.@: on Modeling and Computer Simulation Vol.@: 8, No.@: 1,
409pp.@: 3--30, January 1998,
410@url{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html}).
411Do @strong{not} use for cryptography without securely hashing several
412returned values together, otherwise the generator state can be learned after
413reading 624 consecutive values.
414
415Older versions of Octave used a different random number generator.
416The new generator is used by default as it is significantly faster than the
417old generator, and produces random numbers with a significantly longer cycle
418time. However, in some circumstances it might be desirable to obtain the
419same random sequences as produced by the old generators. To do this the
420keyword @qcode{"seed"} is used to specify that the old generators should
421be used, as in
422
423@example
424rand ("seed", val)
425@end example
426
427@noindent
428which sets the seed of the generator to @var{val}. The seed of the
429generator can be queried with
430
431@example
432s = rand ("seed")
433@end example
434
435However, it should be noted that querying the seed will not cause
436@code{rand} to use the old generators, only setting the seed will. To cause
437@code{rand} to once again use the new generators, the keyword
438@qcode{"state"} should be used to reset the state of the @code{rand}.
439
440The state or seed of the generator can be reset to a new random value using
441the @qcode{"reset"} keyword.
442
443The class of the value returned can be controlled by a trailing
444@qcode{"double"} or @qcode{"single"} argument. These are the only valid
445classes.
446@seealso{randn, rande, randg, randp}
447@end deftypefn */)
448{
449 return do_rand (args, args.length (), "rand", "uniform");
450}
451
452// FIXME: The old generator (selected when "seed" is set) will not
453// work properly if compiled to use 64-bit integers.
454
455/*
456%!test # "state" can be a scalar
457%! rand ("state", 12); x = rand (1,4);
458%! rand ("state", 12); y = rand (1,4);
459%! assert (x, y);
460%!test # "state" can be a vector
461%! rand ("state", [12,13]); x = rand (1,4);
462%! rand ("state", [12;13]); y = rand (1,4);
463%! assert (x, y);
464%!test # querying "state" returns a value which can be used later
465%! s = rand ("state"); x = rand (1,2);
466%! rand ("state", s); y = rand (1,2);
467%! assert (x, y);
468%!test # querying "state" doesn't disturb sequence
469%! rand ("state", 12); rand (1,2); x = rand (1,2);
470%! rand ("state", 12); rand (1,2); s = rand ("state"); y = rand (1,2);
471%! assert (x, y);
472%! rand ("state", s); z = rand (1,2);
473%! assert (x, z);
474%!test # "seed" must be a scalar
475%! rand ("seed", 12); x = rand (1,4);
476%! rand ("seed", 12); y = rand (1,4);
477%! assert (x, y);
478%!error <seed must be a real scalar> rand ("seed", [12,13])
479%!test # querying "seed" returns a value which can be used later
480%! s = rand ("seed"); x = rand (1,2);
481%! rand ("seed", s); y = rand (1,2);
482%! assert (x, y);
483%!test # querying "seed" doesn't disturb sequence
484%! rand ("seed", 12); rand (1,2); x = rand (1,2);
485%! rand ("seed", 12); rand (1,2); s = rand ("seed"); y = rand (1,2);
486%! assert (x, y);
487%! rand ("seed", s); z = rand (1,2);
488%! assert (x, z);
489*/
490
491/*
492%!test
493%! ## Test a known fixed state
494%! rand ("state", 1);
495%! assert (rand (1,6), [0.1343642441124013 0.8474337369372327 0.763774618976614 0.2550690257394218 0.495435087091941 0.4494910647887382], eps);
496%!test
497%! ## Test a known fixed seed
498%! rand ("seed", 1);
499%! assert (rand (1,6), [0.8668024251237512 0.9126510815694928 0.09366085007786751 0.1664607301354408 0.7408077004365623 0.7615650338120759], 1e-6);
500%!test
501%! if (__random_statistical_tests__)
502%! ## statistical tests may fail occasionally.
503%! rand ("state", 12);
504%! x = rand (100_000, 1);
505%! assert (min (x) > 0); #*** Please report this!!! ***
506%! assert (max (x) < 1); #*** Please report this!!! ***
507%! assert (mean (x), 0.5, 0.0024);
508%! assert (var (x), 1/48, 0.0632);
509%! assert (skewness (x), 0, 0.012);
510%! assert (kurtosis (x), -6/5, 0.0094);
511%! endif
512%!test
513%! if (__random_statistical_tests__)
514%! ## statistical tests may fail occasionally.
515%! rand ("seed", 12);
516%! x = rand (100_000, 1);
517%! assert (max (x) < 1); #*** Please report this!!! ***
518%! assert (min (x) > 0); #*** Please report this!!! ***
519%! assert (mean (x), 0.5, 0.0024);
520%! assert (var (x), 1/48, 0.0632);
521%! assert (skewness (x), 0, 0.012);
522%! assert (kurtosis (x), -6/5, 0.0094);
523%! endif
524*/
525
526/*
527## Test out-of-range values as rand() seeds.
528%!function v = __rand_sample__ (initval)
529%! rand ("state", initval);
530%! v = rand (1, 6);
531%!endfunction
532%!
533%!assert (__rand_sample__ (-1), __rand_sample__ (0))
534%!assert (__rand_sample__ (-Inf), __rand_sample__ (0))
535%!assert (__rand_sample__ (2^33), __rand_sample__ (intmax ("uint32")))
536%!assert (__rand_sample__ (Inf), __rand_sample__ (0))
537%!assert (__rand_sample__ (NaN), __rand_sample__ (0))
538*/
539
540/*
541## Note: Matlab compatibility requires using 0 for negative dimensions.
542%!assert (size (rand (1, -1, 2)), [1, 0, 2])
543
544## Test input validation
545%!error <conversion of 1.1 to.* failed> rand (1, 1.1)
546%!error <dimensions must be .* array of integers> rand ([1, 1.1])
547*/
548
549static std::string current_distribution = rand::distribution ();
550
551DEFUN (randn, args, ,
552 doc: /* -*- texinfo -*-
553@deftypefn {} {@var{x} =} randn (@var{n})
554@deftypefnx {} {@var{x} =} randn (@var{m}, @var{n}, @dots{})
555@deftypefnx {} {@var{x} =} randn ([@var{m} @var{n} @dots{}])
556@deftypefnx {} {@var{x} =} randn (@dots{}, "single")
557@deftypefnx {} {@var{x} =} randn (@dots{}, "double")
558@deftypefnx {} {@var{v} =} randn ("state")
559@deftypefnx {} {} randn ("state", @var{v})
560@deftypefnx {} {} randn ("state", "reset")
561@deftypefnx {} {@var{v} =} randn ("seed")
562@deftypefnx {} {} randn ("seed", @var{v})
563@deftypefnx {} {} randn ("seed", "reset")
564Return a matrix with normally distributed random elements having zero mean
565and variance one.
566
567The arguments are handled the same as the arguments for @code{rand}.
568
569By default, @code{randn} uses the @nospell{Marsaglia and Tsang}
570``Ziggurat technique'' to transform from a uniform to a normal distribution.
571
572The class of the value returned can be controlled by a trailing
573@qcode{"double"} or @qcode{"single"} argument. These are the only valid
574classes.
575
576Reference: @nospell{G. Marsaglia and W.W. Tsang},
577@cite{Ziggurat Method for Generating Random Variables},
578J. Statistical Software, vol 5, 2000,
579@url{https://www.jstatsoft.org/v05/i08/}
580
581@seealso{rand, rande, randg, randp}
582@end deftypefn */)
583{
584 return do_rand (args, args.length (), "randn", "normal");
585}
586
587/*
588%!test
589%! ## Test a known fixed state
590%! randn ("state", 1);
591%! assert (randn (1, 6), [-2.666521678978671 -0.7381719971724564 1.507903992673601 0.6019427189162239 -0.450661261143348 -0.7054431351574116], 14*eps);
592%!test
593%! ## Test a known fixed seed
594%! randn ("seed", 1);
595%! assert (randn (1, 6), [-1.039402365684509 -1.25938892364502 0.1968704611063004 0.3874166905879974 -0.5976632833480835 -0.6615074276924133], 1e-6);
596%!test
597%! if (__random_statistical_tests__)
598%! ## statistical tests may fail occasionally.
599%! randn ("state", 12);
600%! x = randn (100_000, 1);
601%! assert (mean (x), 0, 0.01);
602%! assert (var (x), 1, 0.02);
603%! assert (skewness (x), 0, 0.02);
604%! assert (kurtosis (x), 0, 0.04);
605%! endif
606%!test
607%! if (__random_statistical_tests__)
608%! ## statistical tests may fail occasionally.
609%! randn ("seed", 12);
610%! x = randn (100_000, 1);
611%! assert (mean (x), 0, 0.01);
612%! assert (var (x), 1, 0.02);
613%! assert (skewness (x), 0, 0.02);
614%! assert (kurtosis (x), 0, 0.04);
615%! endif
616*/
617
618DEFUN (rande, args, ,
619 doc: /* -*- texinfo -*-
620@deftypefn {} {@var{x} =} rande (@var{n})
621@deftypefnx {} {@var{x} =} rande (@var{m}, @var{n}, @dots{})
622@deftypefnx {} {@var{x} =} rande ([@var{m} @var{n} @dots{}])
623@deftypefnx {} {@var{x} =} rande (@dots{}, "single")
624@deftypefnx {} {@var{x} =} rande (@dots{}, "double")
625@deftypefnx {} {@var{v} =} rande ("state")
626@deftypefnx {} {} rande ("state", @var{v})
627@deftypefnx {} {} rande ("state", "reset")
628@deftypefnx {} {@var{v} =} rande ("seed")
629@deftypefnx {} {} rande ("seed", @var{v})
630@deftypefnx {} {} rande ("seed", "reset")
631Return a matrix with exponentially distributed random elements.
632
633The arguments are handled the same as the arguments for @code{rand}.
634
635By default, @code{rande} uses the @nospell{Marsaglia and Tsang}
636``Ziggurat technique'' to transform from a uniform to an exponential
637distribution.
638
639The class of the value returned can be controlled by a trailing
640@qcode{"double"} or @qcode{"single"} argument. These are the only valid
641classes.
642
643Reference: @nospell{G. Marsaglia and W.W. Tsang},
644@cite{Ziggurat Method for Generating Random Variables},
645J. Statistical Software, vol 5, 2000,
646@url{https://www.jstatsoft.org/v05/i08/}
647
648@seealso{rand, randn, randg, randp}
649@end deftypefn */)
650{
651 return do_rand (args, args.length (), "rande", "exponential");
652}
653
654/*
655%!test
656%! ## Test a known fixed state
657%! rande ("state", 1);
658%! assert (rande (1, 6), [3.602973885835625 0.1386190677555021 0.6743112889616958 0.4512830847258422 0.7255744741233175 0.3415969205292291], 2*eps);
659%!test
660%! ## Test a known fixed seed
661%! rande ("seed", 1);
662%! assert (rande (1, 6), [0.06492075175653866 1.717980206012726 0.4816154008731246 0.5231300676241517 0.103910739364359 1.668931916356087], 1e-6);
663%!test
664%! if (__random_statistical_tests__)
665%! ## statistical tests may fail occasionally
666%! rande ("state", 1);
667%! x = rande (100_000, 1);
668%! assert (min (x) > 0); # *** Please report this!!! ***
669%! assert (mean (x), 1, 0.01);
670%! assert (var (x), 1, 0.03);
671%! assert (skewness (x), 2, 0.06);
672%! assert (kurtosis (x), 6, 0.7);
673%! endif
674%!test
675%! if (__random_statistical_tests__)
676%! ## statistical tests may fail occasionally
677%! rande ("seed", 1);
678%! x = rande (100_000, 1);
679%! assert (min (x)>0); # *** Please report this!!! ***
680%! assert (mean (x), 1, 0.01);
681%! assert (var (x), 1, 0.03);
682%! assert (skewness (x), 2, 0.06);
683%! assert (kurtosis (x), 6, 0.7);
684%! endif
685*/
686
687DEFUN (randg, args, ,
688 doc: /* -*- texinfo -*-
689@deftypefn {} {@var{x} =} randg (@var{a}, @var{n})
690@deftypefnx {} {@var{x} =} randg (@var{a}, @var{m}, @var{n}, @dots{})
691@deftypefnx {} {@var{x} =} randg (@var{a}, [@var{m} @var{n} @dots{}])
692@deftypefnx {} {@var{x} =} randg (@dots{}, "single")
693@deftypefnx {} {@var{x} =} randg (@dots{}, "double")
694@deftypefnx {} {@var{v} =} randg ("state")
695@deftypefnx {} {} randg ("state", @var{v})
696@deftypefnx {} {} randg ("state", "reset")
697@deftypefnx {} {@var{v} =} randg ("seed")
698@deftypefnx {} {} randg ("seed", @var{v})
699@deftypefnx {} {} randg ("seed", "reset")
700
701Return a matrix with @code{gamma (@var{a},1)} distributed random elements.
702
703The arguments are handled the same as the arguments for @code{rand}, except
704for the argument @var{a}.
705
706This can be used to generate many distributions:
707
708@table @asis
709@item @code{gamma (a, b)} for @code{a > -1}, @code{b > 0}
710
711@example
712r = b * randg (a)
713@end example
714
715@item @code{beta (a, b)} for @code{a > -1}, @code{b > -1}
716
717@example
718@group
719r1 = randg (a, 1)
720r = r1 / (r1 + randg (b, 1))
721@end group
722@end example
723
724@item @code{Erlang (a, n)}
725
726@example
727r = a * randg (n)
728@end example
729
730@item @code{chisq (df)} for @code{df > 0}
731
732@example
733r = 2 * randg (df / 2)
734@end example
735
736@item @code{t (df)} for @code{0 < df < inf} (use randn if df is infinite)
737
738@example
739r = randn () / sqrt (2 * randg (df / 2) / df)
740@end example
741
742@item @code{F (n1, n2)} for @code{0 < n1}, @code{0 < n2}
743
744@example
745@group
746## r1 equals 1 if n1 is infinite
747r1 = 2 * randg (n1 / 2) / n1
748## r2 equals 1 if n2 is infinite
749r2 = 2 * randg (n2 / 2) / n2
750r = r1 / r2
751@end group
752@end example
753
754@item negative @code{binomial (n, p)} for @code{n > 0}, @code{0 < p <= 1}
755
756@example
757r = randp ((1 - p) / p * randg (n))
758@end example
759
760@item non-central @code{chisq (df, L)}, for @code{df >= 0} and @code{L > 0}
761(use chisq if @code{L = 0})
762
763@example
764@group
765r = randp (L / 2)
766r(r > 0) = 2 * randg (r(r > 0))
767r(df > 0) += 2 * randg (df(df > 0)/2)
768@end group
769@end example
770
771@item @code{Dirichlet (a1, @dots{} ak)}
772
773@example
774@group
775r = (randg (a1), @dots{}, randg (ak))
776r = r / sum (r)
777@end group
778@end example
779
780@end table
781
782The class of the value returned can be controlled by a trailing
783@qcode{"double"} or @qcode{"single"} argument. These are the only valid
784classes.
785@seealso{rand, randn, rande, randp}
786@end deftypefn */)
787{
788 int nargin = args.length ();
789
790 if (nargin < 1)
791 error ("randg: insufficient arguments");
792
793 return do_rand (args, nargin, "randg", "gamma", true);
794}
795
796/*
797%!test
798%! randg ("state", 12);
799%! assert (randg ([-inf, -1, 0, inf, nan]), [nan, nan, nan, nan, nan]);
800
801%!test
802%! ## Test a known fixed state
803%! randg ("state", 1);
804%! assert (randg (0.1, 1, 6), [0.0103951513331241 8.335671459898252e-05 0.00138691397249762 0.000587308416993855 0.495590518784736 2.3921917414795e-12], eps);
805%!test
806%! ## Test a known fixed state
807%! randg ("state", 1);
808%! assert (randg (0.95, 1, 6), [3.099382433255327 0.3974529788871218 0.644367450750855 1.143261091802246 1.964111762696822 0.04011915547957939], 12*eps);
809%!test
810%! ## Test a known fixed state
811%! randg ("state", 1);
812%! assert (randg (1, 1, 6), [0.2273389379645993 1.288822625058359 0.2406335209340746 1.218869553370733 1.024649860162554 0.09631230343599533], 40*eps);
813%!test
814%! ## Test a known fixed state
815%! randg ("state", 1);
816%! assert (randg (10, 1, 6), [3.520369644331133 15.15369864472106 8.332112081991205 8.406211067432674 11.81193475187611 10.88792728177059], 56*eps);
817%!test
818%! ## Test a known fixed state
819%! randg ("state", 1);
820%! assert (randg (100, 1, 6), [75.34570255262264 115.4911985594699 95.23493031356388 95.48926019250911 106.2397448229803 103.4813150404118], 256*eps);
821%!test
822%! ## Test a known fixed seed
823%! randg ("seed", 1);
824%! assert (randg (0.1, 1, 6), [0.07144210487604141 0.460641473531723 0.4749028384685516 0.06823389977216721 0.000293838675133884 1.802567535340305e-12], 1e-6);
825%!test
826%! ## Test a known fixed seed
827%! randg ("seed", 1);
828%! assert (randg (0.95, 1, 6), [1.664905071258545 1.879976987838745 1.905677795410156 0.9948706030845642 0.5606933236122131 0.0766092911362648], 1e-6);
829%!test
830%! ## Test a known fixed seed
831%! randg ("seed", 1);
832%! assert (randg (1, 1, 6), [0.03512085229158401 0.6488978862762451 0.8114678859710693 0.1666885763406754 1.60791552066803 1.90356981754303], 1e-6);
833%!test
834%! ## Test a known fixed seed
835%! randg ("seed", 1);
836%! assert (randg (10, 1, 6), [6.566435813903809 10.11648464202881 10.73162078857422 7.747178077697754 6.278522491455078 6.240195751190186], 1e-5);
837%!test
838%! ## Test a known fixed seed
839%! randg ("seed", 1);
840%! assert (randg (100, 1, 6), [89.40208435058594 101.4734725952148 103.4020004272461 93.62763214111328 88.33104705810547 88.1871337890625], 1e-4);
841%!test
842%! ## Test out-of-bounds values produce NaN w/old-style generators & floats
843%! randg ("seed", 1);
844%! result = randg ([-2 Inf], "single");
845%! assert (result, single ([NaN NaN]));
846
847%!test
848%! if (__random_statistical_tests__)
849%! ## statistical tests may fail occasionally.
850%! randg ("state", 12);
851%! a = 0.1;
852%! x = randg (a, 100_000, 1);
853%! assert (mean (x), a, 0.01);
854%! assert (var (x), a, 0.01);
855%! assert (skewness (x), 2/sqrt (a), 1);
856%! assert (kurtosis (x), 6/a, 50);
857%! endif
858%!test
859%! if (__random_statistical_tests__)
860%! ## statistical tests may fail occasionally.
861%! randg ("state", 12);
862%! a = 0.95;
863%! x = randg (a, 100_000, 1);
864%! assert (mean (x), a, 0.01);
865%! assert (var (x), a, 0.04);
866%! assert (skewness (x), 2/sqrt (a), 0.2);
867%! assert (kurtosis (x), 6/a, 2);
868%! endif
869%!test
870%! if (__random_statistical_tests__)
871%! ## statistical tests may fail occasionally.
872%! randg ("state", 12);
873%! a = 1;
874%! x = randg (a, 100_000, 1);
875%! assert (mean (x), a, 0.01);
876%! assert (var (x), a, 0.04);
877%! assert (skewness (x), 2/sqrt (a), 0.2);
878%! assert (kurtosis (x), 6/a, 2);
879%! endif
880%!test
881%! if (__random_statistical_tests__)
882%! ## statistical tests may fail occasionally.
883%! randg ("state", 12);
884%! a = 10;
885%! x = randg (a, 100_000, 1);
886%! assert (mean (x), a, 0.1);
887%! assert (var (x), a, 0.5);
888%! assert (skewness (x), 2/sqrt (a), 0.1);
889%! assert (kurtosis (x), 6/a, 0.5);
890%! endif
891%!test
892%! if (__random_statistical_tests__)
893%! ## statistical tests may fail occasionally.
894%! randg ("state", 12);
895%! a = 100;
896%! x = randg (a, 100_000, 1);
897%! assert (mean (x), a, 0.2);
898%! assert (var (x), a, 2);
899%! assert (skewness (x), 2/sqrt (a), 0.05);
900%! assert (kurtosis (x), 6/a, 0.2);
901%! endif
902%!test
903%! randg ("seed", 12);
904%! assert (randg ([-inf, -1, 0, inf, nan]), [nan, nan, nan, nan, nan]);
905%!test
906%! if (__random_statistical_tests__)
907%! ## statistical tests may fail occasionally.
908%! randg ("seed", 12);
909%! a = 0.1;
910%! x = randg (a, 100_000, 1);
911%! assert (mean (x), a, 0.01);
912%! assert (var (x), a, 0.01);
913%! assert (skewness (x), 2/sqrt (a), 1);
914%! assert (kurtosis (x), 6/a, 50);
915%! endif
916%!test
917%! if (__random_statistical_tests__)
918%! ## statistical tests may fail occasionally.
919%! randg ("seed", 12);
920%! a = 0.95;
921%! x = randg (a, 100_000, 1);
922%! assert (mean (x), a, 0.01);
923%! assert (var (x), a, 0.04);
924%! assert (skewness (x), 2/sqrt (a), 0.2);
925%! assert (kurtosis (x), 6/a, 2);
926%! endif
927%!test
928%! if (__random_statistical_tests__)
929%! ## statistical tests may fail occasionally.
930%! randg ("seed", 12);
931%! a = 1;
932%! x = randg (a, 100_000, 1);
933%! assert (mean (x), a, 0.01);
934%! assert (var (x), a, 0.04);
935%! assert (skewness (x), 2/sqrt (a), 0.2);
936%! assert (kurtosis (x), 6/a, 2);
937%! endif
938%!test
939%! if (__random_statistical_tests__)
940%! ## statistical tests may fail occasionally.
941%! randg ("seed", 12);
942%! a = 10;
943%! x = randg (a, 100_000, 1);
944%! assert (mean (x), a, 0.1);
945%! assert (var (x), a, 0.5);
946%! assert (skewness (x), 2/sqrt (a), 0.1);
947%! assert (kurtosis (x), 6/a, 0.5);
948%! endif
949%!test
950%! if (__random_statistical_tests__)
951%! ## statistical tests may fail occasionally.
952%! randg ("seed", 12);
953%! a = 100;
954%! x = randg (a, 100_000, 1);
955%! assert (mean (x), a, 0.2);
956%! assert (var (x), a, 2);
957%! assert (skewness (x), 2/sqrt (a), 0.05);
958%! assert (kurtosis (x), 6/a, 0.2);
959%! endif
960*/
961
962DEFUN (randp, args, ,
963 doc: /* -*- texinfo -*-
964@deftypefn {} {@var{x} =} randp (@var{l}, @var{n})
965@deftypefnx {} {@var{x} =} randp (@var{l}, @var{m}, @var{n}, @dots{})
966@deftypefnx {} {@var{x} =} randp (@var{l}, [@var{m} @var{n} @dots{}])
967@deftypefnx {} {@var{x} =} randp (@dots{}, "single")
968@deftypefnx {} {@var{x} =} randp (@dots{}, "double")
969@deftypefnx {} {@var{v} =} randp ("state")
970@deftypefnx {} {} randp ("state", @var{v})
971@deftypefnx {} {} randp ("state", "reset")
972@deftypefnx {} {@var{v} =} randp ("seed")
973@deftypefnx {} {} randp ("seed", @var{v})
974@deftypefnx {} {} randp ("seed", "reset")
975Return a matrix with Poisson distributed random elements with mean value
976parameter given by the first argument, @var{l}.
977
978The arguments are handled the same as the arguments for @code{rand}, except
979for the argument @var{l}.
980
981Five different algorithms are used depending on the range of @var{l} and
982whether or not @var{l} is a scalar or a matrix.
983
984@table @asis
985@item For scalar @var{l} @leq{} 12, use direct method.
986W.H. Press, et al., @cite{Numerical Recipes in C},
987Cambridge University Press, 1992.
988
989@item For scalar @var{l} > 12, use rejection method.[1]
990W.H. Press, et al., @cite{Numerical Recipes in C},
991Cambridge University Press, 1992.
992
993@item For matrix @var{l} @leq{} 10, use inversion method.[2]
994@nospell{E. Stadlober, et al., WinRand source code}, available via FTP.
995
996@item For matrix @var{l} > 10, use patchwork rejection method.
997@nospell{E. Stadlober, et al., WinRand source code}, available via FTP, or
998@nospell{H. Zechner}, @cite{Efficient sampling from continuous and discrete
999unimodal distributions}, Doctoral Dissertation, 156pp., Technical
1000University @nospell{Graz}, Austria, 1994.
1001
1002@item For @var{l} > 1e8, use normal approximation.
1003@nospell{L. Montanet}, et al., @cite{Review of Particle Properties},
1004Physical Review D 50 p1284, 1994.
1005@end table
1006
1007The class of the value returned can be controlled by a trailing
1008@qcode{"double"} or @qcode{"single"} argument. These are the only valid
1009classes.
1010@seealso{rand, randn, rande, randg}
1011@end deftypefn */)
1012{
1013 int nargin = args.length ();
1014
1015 if (nargin < 1)
1016 error ("randp: insufficient arguments");
1017
1018 return do_rand (args, nargin, "randp", "poisson", true);
1019}
1020
1021/*
1022%!test
1023%! randp ("state", 12);
1024%! assert (randp ([-inf, -1, 0, inf, nan]), [nan, nan, 0, nan, nan]);
1025%!test
1026%! ## Test a known fixed state
1027%! randp ("state", 1);
1028%! assert (randp (5, 1, 6), [5 5 3 7 7 3]);
1029%!test
1030%! ## Test a known fixed state
1031%! randp ("state", 1);
1032%! assert (randp (15, 1, 6), [13 15 8 18 18 15]);
1033%!test
1034%! ## Test a known fixed state
1035%! randp ("state", 1);
1036%! assert (randp (1e9, 1, 6),
1037%! [999915677 999976657 1000047684 1000019035 999985749 999977692],
1038%! -1e-6);
1039%!test
1040%! ## Test a known fixed seed
1041%! randp ("seed", 1);
1042%! %%assert (randp (5, 1, 6), [8 2 3 6 6 8])
1043%! assert (randp (5, 1, 5), [8 2 3 6 6]);
1044%!test
1045%! ## Test a known fixed seed
1046%! randp ("seed", 1);
1047%! assert (randp (15, 1, 6), [15 16 12 10 10 12]);
1048%!test
1049%! ## Test a known fixed seed
1050%! randp ("seed", 1);
1051%! assert (randp (1e9, 1, 6),
1052%! [1000006208 1000012224 999981120 999963520 999963072 999981440],
1053%! -1e-6);
1054%!test
1055%! if (__random_statistical_tests__)
1056%! ## statistical tests may fail occasionally.
1057%! randp ("state", 12);
1058%! for a = [5, 15, 1e9; 0.03, 0.03, -5e-3; 0.03, 0.03, 0.03]
1059%! x = randp (a (1), 100_000, 1);
1060%! assert (min (x) >= 0); # *** Please report this!!! ***
1061%! assert (mean (x), a(1), a(2));
1062%! assert (var (x), a(1), 0.02*a(1));
1063%! assert (skewness (x), 1/sqrt (a(1)), a(3));
1064%! assert (kurtosis (x), 1/a(1), 3*a(3));
1065%! endfor
1066%! endif
1067%!test
1068%! if (__random_statistical_tests__)
1069%! ## statistical tests may fail occasionally.
1070%! randp ("state", 12);
1071%! for a = [5, 15, 1e9; 0.03, 0.03, -5e-3; 0.03, 0.03, 0.03]
1072%! x = randp (a(1)* ones (100_000, 1), 100_000, 1);
1073%! assert (min (x) >= 0); # *** Please report this!!! ***
1074%! assert (mean (x), a(1), a(2));
1075%! assert (var (x), a(1), 0.02*a(1));
1076%! assert (skewness (x), 1/sqrt (a(1)), a(3));
1077%! assert (kurtosis (x), 1/a(1), 3*a(3));
1078%! endfor
1079%! endif
1080%!test
1081%! randp ("seed", 12);
1082%! assert (randp ([-inf, -1, 0, inf, nan]), [nan, nan, 0, nan, nan]);
1083%!test
1084%! if (__random_statistical_tests__)
1085%! ## statistical tests may fail occasionally.
1086%! randp ("seed", 12);
1087%! for a = [5, 15, 1e9; 0.03, 0.03, -5e-3; 0.03, 0.03, 0.03]
1088%! x = randp (a(1), 100_000, 1);
1089%! assert (min (x) >= 0); # *** Please report this!!! ***
1090%! assert (mean (x), a(1), a(2));
1091%! assert (var (x), a(1), 0.02*a(1));
1092%! assert (skewness (x), 1/sqrt (a(1)), a(3));
1093%! assert (kurtosis (x), 1/a(1), 3*a(3));
1094%! endfor
1095%! endif
1096%!test
1097%! if (__random_statistical_tests__)
1098%! ## statistical tests may fail occasionally.
1099%! randp ("seed", 12);
1100%! for a = [5, 15, 1e9; 0.03, 0.03, -5e-3; 0.03, 0.03, 0.03]
1101%! x = randp (a(1)* ones (100_000, 1), 100_000, 1);
1102%! assert (min (x) >= 0); # *** Please report this!!! ***
1103%! assert (mean (x), a(1), a(2));
1104%! assert (var (x), a(1), 0.02*a(1));
1105%! assert (skewness (x), 1/sqrt (a(1)), a(3));
1106%! assert (kurtosis (x), 1/a(1), 3*a(3));
1107%! endfor
1108%! endif
1109*/
1110
1111DEFUN (randperm, args, ,
1112 doc: /* -*- texinfo -*-
1113@deftypefn {} {@var{v} =} randperm (@var{n})
1114@deftypefnx {} {@var{v} =} randperm (@var{n}, @var{m})
1115Return a row vector containing a random permutation of @code{1:@var{n}}.
1116
1117If @var{m} is supplied, return @var{m} unique entries, sampled without
1118replacement from @code{1:@var{n}}.
1119
1120The complexity is O(@var{n}) in memory and O(@var{m}) in time, unless
1121@var{m} < @var{n}/5, in which case O(@var{m}) memory is used as well. The
1122randomization is performed using rand(). All permutations are equally
1123likely.
1124@seealso{perms}
1125@end deftypefn */)
1126{
1127 int nargin = args.length ();
1128
1129 if (nargin < 1 || nargin > 2)
1130 print_usage ();
1131
1132 octave_idx_type n = args(0).idx_type_value (true);
1133 octave_idx_type m = (nargin == 2) ? args(1).idx_type_value (true) : n;
1134
1135 if (m < 0 || n < 0)
1136 error ("randperm: M and N must be non-negative");
1137
1138 if (m > n)
1139 error ("randperm: M must be less than or equal to N");
1140
1141 // Quick and dirty heuristic to decide if we allocate or not the
1142 // whole vector for tracking the truncated shuffle.
1143 bool short_shuffle = m < n/5;
1144
1145 // Generate random numbers.
1146 NDArray r = rand::nd_array (dim_vector (1, m));
1147 double *rvec = r.rwdata ();
1148
1149 octave_idx_type idx_len = (short_shuffle ? m : n);
1151 try
1152 {
1153 idx = Array<octave_idx_type> (dim_vector (1, idx_len));
1154 }
1155 catch (const std::bad_alloc&)
1156 {
1157 // Looks like n is too big and short_shuffle is false.
1158 // Let's try again, but this time with the alternative.
1159 idx_len = m;
1160 short_shuffle = true;
1161 idx = Array<octave_idx_type> (dim_vector (1, idx_len));
1162 }
1163
1164 octave_idx_type *ivec = idx.rwdata ();
1165
1166 for (octave_idx_type i = 0; i < idx_len; i++)
1167 ivec[i] = i;
1168
1169 if (short_shuffle)
1170 {
1171 std::unordered_map<octave_idx_type, octave_idx_type> map (m);
1172
1173 // Perform the Knuth shuffle only keeping track of moved
1174 // entries in the map
1175 for (octave_idx_type i = 0; i < m; i++)
1176 {
1177 octave_idx_type k = i + std::floor (rvec[i] * (n - i));
1178
1179 // For shuffling first m entries, no need to use extra storage
1180 if (k < m)
1181 {
1182 std::swap (ivec[i], ivec[k]);
1183 }
1184 else
1185 {
1186 if (map.find (k) == map.end ())
1187 map[k] = k;
1188
1189 std::swap (ivec[i], map[k]);
1190 }
1191 }
1192 }
1193 else
1194 {
1195 // Perform the Knuth shuffle of the first m entries
1196 for (octave_idx_type i = 0; i < m; i++)
1197 {
1198 octave_idx_type k = i + std::floor (rvec[i] * (n - i));
1199 std::swap (ivec[i], ivec[k]);
1200 }
1201 }
1202
1203 // Convert to doubles, reusing r.
1204 for (octave_idx_type i = 0; i < m; i++)
1205 rvec[i] = ivec[i] + 1;
1206
1207 if (m < n)
1208 idx.resize (dim_vector (1, m));
1209
1210 // Now create an array object with a cached idx_vector.
1211 return ovl (new octave_matrix (r, idx_vector (idx)));
1212}
1213
1214/*
1215%!assert (sort (randperm (20)), 1:20)
1216%!assert (length (randperm (20,10)), 10)
1217
1218## Test biggish N
1219%!assert <*39378> (length (randperm (30_000^2, 100_000)), 100_000)
1220
1221%!test
1222%! rand ("seed", 0);
1223%! for i = 1:100
1224%! p = randperm (305, 30);
1225%! assert (length (unique (p)), 30);
1226%! endfor
1227*/
1228
1229OCTAVE_END_NAMESPACE(octave)
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array.h:507
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:525
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
void chop_trailing_singletons()
Definition dim-vector.h:160
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
octave_idx_type length() const
Definition ovl.h:111
bool is_scalar_type() const
Definition ov.h:744
bool is_string() const
Definition ov.h:637
octave_idx_type idx_type_value(bool req_int=false, bool frc_str_conv=false) const
bool is_range() const
Definition ov.h:646
std::string string_value(bool force=false) const
Definition ov.h:983
bool is_matrix_type() const
Definition ov.h:747
Array< octave_idx_type > octave_idx_type_vector_value(bool req_int=false, bool frc_str_conv=false, bool frc_vec_conv=false) const
octave::range< double > range_value() const
Definition ov.h:994
static FloatNDArray float_nd_array(const dim_vector &dims, float a=1.0)
Definition oct-rand.h:179
static uint32NDArray state(const std::string &d="")
Definition oct-rand.h:80
static NDArray nd_array(const dim_vector &dims, double a=1.0)
Definition oct-rand.h:172
static void uniform_distribution()
Definition oct-rand.h:114
static double scalar(double a=1.0)
Definition oct-rand.h:145
static void exponential_distribution()
Definition oct-rand.h:126
static float float_scalar(float a=1.0)
Definition oct-rand.h:152
static void reset()
Definition oct-rand.h:73
static void gamma_distribution()
Definition oct-rand.h:138
static std::string distribution()
Definition oct-rand.h:101
static void normal_distribution()
Definition oct-rand.h:120
static double seed()
Definition oct-rand.h:59
static void poisson_distribution()
Definition oct-rand.h:132
bool all_elements_are_ints() const
Definition Range.cc:308
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition defun.h:56
void error(const char *fmt,...)
Definition error.cc:1003
void err_wrong_type_arg(const char *name, const char *s)
Definition errwarn.cc:166
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
F77_RET_T len
Definition xerbla.cc:61