Mercurial > octave
annotate scripts/general/rng.m @ 31202:434b5a1b9498
isequal.m: Add ability to compare Java objects (bug #62930)
* isequal.m: Add elseif clause to detect Java objects and use built-in Java
"equals" method for comparison. Add BIST test for Java object comparison.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 25 Aug 2022 15:35:25 -0700 |
parents | 5d3faba0342e |
children | 597f3ee61a48 |
rev | line source |
---|---|
28106 | 1 ######################################################################## |
2 ## | |
30564
796f54d4ddbf
update Octave Project Developers copyright for the new year
John W. Eaton <jwe@octave.org>
parents:
29359
diff
changeset
|
3 ## Copyright (C) 2020-2022 The Octave Project Developers |
28106 | 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 ## -*- texinfo -*- | |
27 ## @deftypefn {} {} rng (@var{seed}) | |
28111 | 28 ## @deftypefnx {} {} rng (@var{seed}, "@var{generator}") |
28106 | 29 ## @deftypefnx {} {} rng ("shuffle") |
28111 | 30 ## @deftypefnx {} {} rng ("shuffle", "@var{generator}") |
28106 | 31 ## @deftypefnx {} {} rng ("default") |
32 ## @deftypefnx {} {@var{s} =} rng () | |
33 ## @deftypefnx {} {} rng (@var{s}) | |
34 ## @deftypefnx {} {@var{s} =} rng (@dots{}) | |
28111 | 35 ## Set or query the seed of the random number generator used by @code{rand} and |
36 ## @code{randn}. | |
28106 | 37 ## |
28957
efc998c08d27
doc: Use @var rather than @code to mark function inputs in TexInfo.
Rik <rik@octave.org>
parents:
28945
diff
changeset
|
38 ## The input @var{seed} is a scalar numeric value used to initialize the state |
28106 | 39 ## vector of the random number generator. |
40 ## | |
41 ## The optional string @var{generator} specifies the type of random number | |
28111 | 42 ## generator to be used. Its value can be @qcode{"twister"}, |
43 ## @qcode{"v5uniform"}, or @qcode{"v5normal"}. The @qcode{"twister"} keyword | |
44 ## is described below. @qcode{"v5uniform"} and @qcode{"v5normal"} refer to | |
45 ## older versions of Octave that used to use a different random number | |
46 ## generator. | |
28106 | 47 ## |
28111 | 48 ## The state or seed of the random number generator can be reset to a new |
49 ## random value using the @qcode{"shuffle"} keyword. | |
28106 | 50 ## |
28111 | 51 ## The random number generator can be reset to default values using the |
52 ## @qcode{"default"} keyword. The default values are to use the Mersenne | |
53 ## Twister generator with a seed of 0. | |
28106 | 54 ## |
55 ## The optional return value @var{s} contains the state of the random number | |
28111 | 56 ## generator at the time the function is called (i.e., before it might be |
57 ## modified according to the input arguments). It is encoded as a structure | |
58 ## variable with three fields: @qcode{"Type"}, @qcode{"Seed"}, and | |
59 ## @qcode{"State"}. The random number generator can be restored to the state | |
60 ## @var{s} using @code{rng (@var{s})}. This is useful when the identical | |
28693
2bb050267d74
maint: Remove trailing spaces from code base.
Rik <rik@octave.org>
parents:
28111
diff
changeset
|
61 ## sequence of pseudo-random numbers is required for an algorithm. |
28106 | 62 ## |
63 ## By default, and with the @qcode{"twister"} option, pseudo-random sequences | |
64 ## are computed using the Mersenne Twister with a period of @math{2^{19937}-1} | |
65 ## (See @nospell{M. Matsumoto and T. Nishimura}, | |
66 ## @cite{Mersenne Twister: A 623-dimensionally equidistributed uniform | |
67 ## pseudorandom number generator}, | |
68 ## @nospell{ACM} Trans.@: on Modeling and Computer Simulation Vol.@: 8, No.@: 1, | |
69 ## pp.@: 3--30, January 1998, | |
70 ## @url{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html}). | |
71 ## Do @strong{not} use for cryptography without securely hashing several | |
72 ## returned values together, otherwise the generator state can be learned after | |
73 ## reading 624 consecutive values. | |
74 ## | |
75 ## @seealso{rand, randn} | |
76 ## @end deftypefn | |
77 | |
30875
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
78 function s = rng (varargin) |
28106 | 79 |
28107
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
80 if (nargin > 2) |
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
81 print_usage (); |
28106 | 82 endif |
83 | |
84 ## Store current settings of random number generator | |
85 ## FIXME: there doesn't seem to be a way to query the type of generator | |
86 ## currently used in Octave - assume "twister". | |
87 ## FIXME: there doesn't seem to be a way to query the seed initialization | |
88 ## value - use "Not applicable". | |
89 ## FIXME: rand and randn use different generators - storing both states. | |
90 ## For older Matlab generators (v4, v5), the settings are stored like this: | |
91 ## struct ("Type","Legacy", "Seed", "Not applicable", "State",{[],[],...}) | |
92 | |
28107
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
93 ## Type is the generator name. |
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
94 ## Seed is the initial seed value. |
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
95 ## State is a structure describing internal state of the generator. |
30875
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
96 srng = struct ("Type", "twister", |
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
97 "Seed", "Not applicable", |
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
98 "State", {{rand("state"), randn("state")}}); |
28107
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
99 |
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
100 if (nargin == 0) |
30875
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
101 s = srng; |
28106 | 102 return; |
103 endif | |
104 | |
28111 | 105 arg1 = varargin{1}; |
106 if (isscalar (arg1) && isnumeric (arg1) && isreal (arg1) && arg1 >= 0) | |
107 s_rand = s_randn = arg1; | |
28106 | 108 generator = check_generator (varargin(2:end)); |
109 | |
28111 | 110 elseif (ischar (arg1) && strcmpi (arg1, "shuffle")) |
28106 | 111 ## Seed the random number generator based on the current time |
28111 | 112 s_rand = s_randn = "reset"; # or sum (1000*clock) |
28106 | 113 generator = check_generator (varargin(2:end)); |
114 | |
28111 | 115 elseif (ischar (arg1) && strcmpi (arg1, "default") && nargin == 1) |
28107
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
116 generator = "twister"; |
28111 | 117 s_rand = s_randn = 0; # FIXME: In Matlab, seed 0 corresponds to 5489 |
28106 | 118 |
28111 | 119 elseif (isstruct (arg1) && isscalar (arg1) && nargin == 1) |
120 if (numfields (arg1) != 3 | |
121 || ! all (isfield (arg1, {"Type", "Seed", "State"}))) | |
122 error ('rng: input structure requires "Type", "Seed", "State" fields"'); | |
28106 | 123 endif |
124 ## Only the internal state "State" and generator type "Type" are needed | |
28111 | 125 generator = arg1.Type; |
126 if (iscell (arg1.State)) | |
127 [s_rand, s_randn] = deal (arg1.State{:}); | |
28106 | 128 else |
28111 | 129 s_rand = s_randn = arg1.State; |
28106 | 130 endif |
131 | |
132 else | |
133 print_usage (); | |
134 endif | |
135 | |
136 ## Set the type of random number generator and seed it | |
137 if (isempty (generator)) | |
30875
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
138 generator = srng.Type; |
28106 | 139 endif |
28111 | 140 switch (generator) |
28106 | 141 case "twister" |
142 rand ("state", s_rand); | |
143 randn ("state", s_randn); | |
144 | |
145 case "legacy" | |
146 rand ("seed", s_rand); | |
147 randn ("seed", s_randn); | |
148 | |
28107
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
149 case "v5uniform" |
28106 | 150 rand ("seed", s_rand); |
151 | |
152 case "v5normal" | |
153 randn ("seed", s_randn); | |
154 | |
28111 | 155 otherwise |
156 error ('rng: invalid GENERATOR: "%s"', generator); | |
28107
d320728d5d06
style fixes for rng; document and mention in NEWS file
John W. Eaton <jwe@octave.org>
parents:
28106
diff
changeset
|
157 |
28106 | 158 endswitch |
159 | |
160 if (nargout > 0) | |
30875
5d3faba0342e
doc: Ensure documentation lists output argument when it exists for all m-files.
Rik <rik@octave.org>
parents:
30564
diff
changeset
|
161 s = srng; |
28106 | 162 endif |
163 | |
164 endfunction | |
165 | |
166 | |
167 function gen = check_generator (val) | |
28945
6e460773bdda
maint: Use newlines after "function" and before "endfunction" for clarity.
Rik <rik@octave.org>
parents:
28693
diff
changeset
|
168 |
28106 | 169 if (isempty (val)) |
170 gen = ""; | |
171 return; | |
172 elseif (! iscellstr (val)) | |
28111 | 173 error ("rng: GENERATOR must be a string"); |
28106 | 174 endif |
28945
6e460773bdda
maint: Use newlines after "function" and before "endfunction" for clarity.
Rik <rik@octave.org>
parents:
28693
diff
changeset
|
175 |
28106 | 176 gen = tolower (char (val)); |
28111 | 177 if (any (strcmp (gen, {"simdtwister", "combrecursive", "philox", "threefry", "multfibonacci", "v4"}))) |
178 error ('rng: random number generator "%s" is not available in Octave', gen); | |
179 elseif (! any (strcmp (gen, {"twister", "v5uniform", "v5normal"}))) | |
180 error ('rng: unknown random number generator "%s"', gen); | |
28106 | 181 endif |
28945
6e460773bdda
maint: Use newlines after "function" and before "endfunction" for clarity.
Rik <rik@octave.org>
parents:
28693
diff
changeset
|
182 |
28106 | 183 endfunction |
184 | |
185 | |
186 %!test | |
28111 | 187 %! state = rng (); |
188 %! unwind_protect | |
189 %! rng (42); | |
190 %! ru1 = rand (); | |
191 %! rn1 = randn (); | |
192 %! rng (42); | |
193 %! ru2 = rand (); | |
194 %! rn2 = randn (); | |
195 %! assert (ru2, ru1); | |
196 %! assert (rn2, rn1); | |
197 %! s1 = rng (); | |
198 %! s2 = rng (42); | |
199 %! assert (isequal (s1, s2)); | |
200 %! ru1 = rand (); | |
201 %! rn1 = randn (); | |
202 %! s3 = rng (42); | |
203 %! ru2 = rand (); | |
204 %! rn2 = randn (); | |
205 %! assert (ru2, ru1); | |
206 %! assert (rn2, rn1); | |
207 %! unwind_protect_cleanup | |
208 %! rng (state); | |
209 %! end_unwind_protect | |
210 | |
211 %!test | |
212 %! state = rng (); | |
213 %! unwind_protect | |
214 %! rng (42, "twister"); | |
215 %! ru1 = rand (); | |
216 %! rn1 = randn (); | |
217 %! rng (42, "twister"); | |
218 %! ru2 = rand (); | |
219 %! rn2 = randn (); | |
220 %! assert (ru2, ru1); | |
221 %! assert (rn2, rn1); | |
222 %! s1 = rng (); | |
223 %! s2 = rng (42, "twister"); | |
224 %! assert (isequal (s1, s2)); | |
225 %! ru1 = rand (); | |
226 %! rn1 = randn (); | |
227 %! s3 = rng (42, "twister"); | |
228 %! ru2 = rand (); | |
229 %! rn2 = randn (); | |
230 %! assert (ru2, ru1); | |
231 %! assert (rn2, rn1); | |
232 %! unwind_protect_cleanup | |
233 %! rng (state); | |
234 %! end_unwind_protect | |
28106 | 235 |
236 %!test | |
28111 | 237 %! state = rng (); |
238 %! unwind_protect | |
239 %! rng ("shuffle"); | |
240 %! rng ("shuffle", "twister"); | |
241 %! s = rng ("shuffle"); | |
242 %! assert (! isequal (s, rng ("shuffle"))); | |
243 %! s = rng ("shuffle", "twister"); | |
244 %! assert (! isequal (s, rng ("shuffle", "twister"))); | |
245 %! unwind_protect_cleanup | |
246 %! rng (state); | |
247 %! end_unwind_protect | |
28106 | 248 |
249 %!test | |
28111 | 250 %! state = rng (); |
251 %! unwind_protect | |
252 %! rng ("default"); | |
253 %! ru1 = rand (); | |
254 %! rn1 = randn (); | |
255 %! rng (0, "twister"); | |
256 %! ru2 = rand (); | |
257 %! rn2 = randn (); | |
258 %! assert (ru2, ru1); | |
259 %! assert (rn2, rn1); | |
260 %! rng (0, "twister"); | |
261 %! s = rng ("default"); | |
262 %! assert (isequal (s, rng ())); | |
263 %! unwind_protect_cleanup | |
264 %! rng (state); | |
265 %! end_unwind_protect | |
28106 | 266 |
267 %!test | |
28111 | 268 %! state = rng (); |
269 %! unwind_protect | |
270 %! s = rng (); | |
271 %! ru1 = rand (); | |
272 %! rn1 = randn (); | |
273 %! rng (s); | |
274 %! ru2 = rand (); | |
275 %! rn2 = randn (); | |
276 %! assert (ru2, ru1); | |
277 %! assert (rn2, rn1); | |
278 %! rng (42); rand (1,2); x = rand (1,2); | |
279 %! rng (42); rand (1,2); s = rng (); y = rand (1,2); | |
280 %! assert (x, y); | |
281 %! rng (s); z = rand (1,2); | |
282 %! assert (x, z); | |
283 %! s1 = rng (); | |
284 %! s2 = rng (s1); | |
285 %! assert (isequal (s1, s2)); | |
286 %! unwind_protect_cleanup | |
287 %! rng (state); | |
288 %! end_unwind_protect | |
28106 | 289 |
290 ## Test input validation | |
291 %!error <Invalid call> rng (1, 2, 3) | |
28111 | 292 %!error <Invalid call> rng (eye (2)) |
28106 | 293 %!error <Invalid call> rng ({}) |
28111 | 294 %!error <Invalid call> rng (2i) |
295 %!error <Invalid call> rng (-2) | |
296 %!error <Invalid call> rng ("foobar") | |
28106 | 297 %!error <Invalid call> rng ("default", "twister") |
28111 | 298 %!error <Invalid call> rng (struct ("Seed", {1, 2})) |
299 %!error <Invalid call> rng (struct ("Type",[],"State",[],"Seed",[]), "twister") | |
300 %!error <input structure requires "Type"> rng (struct ()) | |
301 %!error <input structure requires "Type"> | |
302 %! rng (struct ("Type1",[],"State",[],"Seed",[])); | |
303 %!error <GENERATOR must be a string> rng (0, struct ()) | |
304 %!error <"philox" is not available in Octave> rng (0, "philox") | |
305 %!error <GENERATOR must be a string> rng ("shuffle", struct ()) | |
306 %!error <unknown random number generator "foobar"> rng ("shuffle", "foobar") |