Mercurial > hg > octave-nkf
annotate liboctave/oct-rand.cc @ 7533:ff52243af934
save state separately for each MT random number generator
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 26 Feb 2008 05:28:59 -0500 |
parents | a1dbe9d80eee |
children | bda16af4fd2f |
rev | line source |
---|---|
4308 | 1 /* |
2 | |
7017 | 3 Copyright (C) 2003, 2005, 2006, 2007 John W. Eaton |
4308 | 4 |
5 This file is part of Octave. | |
6 | |
7 Octave is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
7016 | 9 Free Software Foundation; either version 3 of the License, or (at your |
10 option) any later version. | |
4308 | 11 |
12 Octave is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
7016 | 18 along with Octave; see the file COPYING. If not, see |
19 <http://www.gnu.org/licenses/>. | |
4308 | 20 |
21 */ | |
22 | |
23 #ifdef HAVE_CONFIG_H | |
24 #include <config.h> | |
25 #endif | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
26 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
27 #include <map> |
5730 | 28 #include <vector> |
4308 | 29 |
30 #include "f77-fcn.h" | |
5730 | 31 #include "lo-ieee.h" |
4308 | 32 #include "lo-error.h" |
5730 | 33 #include "lo-mappers.h" |
4308 | 34 #include "oct-rand.h" |
4415 | 35 #include "oct-time.h" |
5730 | 36 #include "data-conv.h" |
37 #include "randmtzig.h" | |
38 #include "randpoisson.h" | |
39 #include "randgamma.h" | |
6435 | 40 #include "mach-info.h" |
4308 | 41 |
42 // Possible distributions of random numbers. This was handled with an | |
43 // enum, but unwind_protecting that doesn't work so well. | |
44 #define uniform_dist 1 | |
45 #define normal_dist 2 | |
5730 | 46 #define expon_dist 3 |
47 #define poisson_dist 4 | |
48 #define gamma_dist 5 | |
4308 | 49 |
50 // Current distribution of random numbers. | |
51 static int current_distribution = uniform_dist; | |
52 | |
5730 | 53 // Has the seed/state been set yet? |
54 static bool old_initialized = false; | |
55 static bool new_initialized = false; | |
56 static bool use_old_generators = false; | |
4308 | 57 |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
58 std::map<int, ColumnVector> rand_states; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
59 |
4308 | 60 extern "C" |
61 { | |
4552 | 62 F77_RET_T |
63 F77_FUNC (dgennor, DGENNOR) (const double&, const double&, double&); | |
4308 | 64 |
4552 | 65 F77_RET_T |
66 F77_FUNC (dgenunf, DGENUNF) (const double&, const double&, double&); | |
67 | |
68 F77_RET_T | |
5730 | 69 F77_FUNC (dgenexp, DGENEXP) (const double&, double&); |
70 | |
71 F77_RET_T | |
72 F77_FUNC (dignpoi, DIGNPOI) (const double&, double&); | |
73 | |
74 F77_RET_T | |
75 F77_FUNC (dgengam, DGENGAM) (const double&, const double&, double&); | |
76 | |
77 F77_RET_T | |
5275 | 78 F77_FUNC (setall, SETALL) (const octave_idx_type&, const octave_idx_type&); |
4308 | 79 |
4552 | 80 F77_RET_T |
5275 | 81 F77_FUNC (getsd, GETSD) (octave_idx_type&, octave_idx_type&); |
4308 | 82 |
4552 | 83 F77_RET_T |
5275 | 84 F77_FUNC (setsd, SETSD) (const octave_idx_type&, const octave_idx_type&); |
4308 | 85 |
4552 | 86 F77_RET_T |
5275 | 87 F77_FUNC (setcgn, SETCGN) (const octave_idx_type&); |
4308 | 88 } |
89 | |
5275 | 90 static octave_idx_type |
91 force_to_fit_range (octave_idx_type i, octave_idx_type lo, octave_idx_type hi) | |
4308 | 92 { |
93 assert (hi > lo && lo >= 0 && hi > lo); | |
94 | |
95 i = i > 0 ? i : -i; | |
96 | |
97 if (i < lo) | |
98 i = lo; | |
99 else if (i > hi) | |
100 i = i % hi; | |
101 | |
102 return i; | |
103 } | |
104 | |
105 // Make the random number generator give us a different sequence every | |
106 // time we start octave unless we specifically set the seed. The | |
107 // technique used below will cycle monthly, but it it does seem to | |
108 // work ok to give fairly different seeds each time Octave starts. | |
109 | |
110 static void | |
5730 | 111 do_old_initialization (void) |
4308 | 112 { |
4415 | 113 octave_localtime tm; |
6326 | 114 int stored_distribution = current_distribution; |
115 F77_FUNC (setcgn, SETCGN) (uniform_dist); | |
116 | |
4415 | 117 int hour = tm.hour() + 1; |
118 int minute = tm.min() + 1; | |
119 int second = tm.sec() + 1; | |
4308 | 120 |
5275 | 121 octave_idx_type s0 = tm.mday() * hour * minute * second; |
122 octave_idx_type s1 = hour * minute * second; | |
4308 | 123 |
124 s0 = force_to_fit_range (s0, 1, 2147483563); | |
125 s1 = force_to_fit_range (s1, 1, 2147483399); | |
126 | |
127 F77_FUNC (setall, SETALL) (s0, s1); | |
6326 | 128 F77_FUNC (setcgn, SETCGN) (stored_distribution); |
4308 | 129 |
5730 | 130 old_initialized = true; |
4308 | 131 } |
132 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
133 static ColumnVector |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
134 get_internal_state (void) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
135 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
136 ColumnVector s (MT_N + 1); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
137 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
138 OCTAVE_LOCAL_BUFFER (uint32_t, tmp, MT_N + 1); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
139 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
140 oct_get_state (tmp); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
141 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
142 for (octave_idx_type i = 0; i <= MT_N; i++) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
143 s.elem (i) = static_cast<double> (tmp [i]); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
144 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
145 return s; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
146 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
147 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
148 static inline void |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
149 save_state (void) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
150 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
151 rand_states[current_distribution] = get_internal_state ();; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
152 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
153 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
154 static void |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
155 initialize_rand_states (void) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
156 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
157 if (! new_initialized) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
158 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
159 oct_init_by_entropy (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
160 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
161 ColumnVector s = get_internal_state (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
162 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
163 rand_states[uniform_dist] = s; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
164 rand_states[normal_dist] = s; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
165 rand_states[expon_dist] = s; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
166 rand_states[poisson_dist] = s; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
167 rand_states[gamma_dist] = s; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
168 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
169 new_initialized = true; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
170 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
171 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
172 |
4308 | 173 static inline void |
174 maybe_initialize (void) | |
175 { | |
5730 | 176 if (use_old_generators) |
177 { | |
178 if (! old_initialized) | |
179 do_old_initialization (); | |
180 } | |
181 else | |
182 { | |
183 if (! new_initialized) | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
184 initialize_rand_states (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
185 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
186 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
187 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
188 static int |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
189 get_dist_id (const std::string& d) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
190 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
191 int retval; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
192 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
193 if (d == "uniform" || d == "rand") |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
194 retval = uniform_dist; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
195 else if (d == "normal" || d == "randn") |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
196 retval = normal_dist; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
197 else if (d == "exponential" || d == "rande") |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
198 retval = expon_dist; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
199 else if (d == "poisson" || d == "randp") |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
200 retval = poisson_dist; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
201 else if (d == "gamma" || d == "rangd") |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
202 retval = gamma_dist; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
203 else |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
204 (*current_liboctave_error_handler) ("rand: invalid distribution"); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
205 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
206 return retval; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
207 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
208 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
209 static void |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
210 set_internal_state (const ColumnVector& s) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
211 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
212 octave_idx_type len = s.length (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
213 octave_idx_type n = len < MT_N + 1 ? len : MT_N + 1; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
214 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
215 OCTAVE_LOCAL_BUFFER (uint32_t, tmp, MT_N + 1); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
216 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
217 for (octave_idx_type i = 0; i < n; i++) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
218 tmp[i] = static_cast<uint32_t> (s.elem(i)); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
219 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
220 if (len == MT_N + 1 && tmp[MT_N] <= MT_N && tmp[MT_N] > 0) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
221 oct_set_state (tmp); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
222 else |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
223 oct_init_by_array (tmp, len); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
224 } |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
225 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
226 static inline void |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
227 switch_to_generator (int dist) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
228 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
229 if (dist != current_distribution) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
230 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
231 current_distribution = dist; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
232 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
233 set_internal_state (rand_states[dist]); |
5730 | 234 } |
4308 | 235 } |
236 | |
237 double | |
238 octave_rand::seed (void) | |
239 { | |
5730 | 240 if (! old_initialized) |
241 do_old_initialization (); | |
4308 | 242 |
5275 | 243 union d2i { double d; octave_idx_type i[2]; }; |
4308 | 244 union d2i u; |
6435 | 245 |
246 oct_mach_info::float_format ff = oct_mach_info::native_float_format (); | |
247 | |
248 switch (ff) | |
249 { | |
250 case oct_mach_info::flt_fmt_ieee_big_endian: | |
251 F77_FUNC (getsd, GETSD) (u.i[1], u.i[0]); | |
252 break; | |
253 default: | |
254 F77_FUNC (getsd, GETSD) (u.i[0], u.i[1]); | |
255 break; | |
256 } | |
257 | |
4308 | 258 return u.d; |
259 } | |
260 | |
261 void | |
262 octave_rand::seed (double s) | |
263 { | |
5730 | 264 use_old_generators = true; |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
265 |
4308 | 266 maybe_initialize (); |
267 | |
6435 | 268 int i0, i1; |
5275 | 269 union d2i { double d; octave_idx_type i[2]; }; |
4308 | 270 union d2i u; |
271 u.d = s; | |
6435 | 272 |
273 oct_mach_info::float_format ff = oct_mach_info::native_float_format (); | |
274 | |
275 switch (ff) | |
276 { | |
277 case oct_mach_info::flt_fmt_ieee_big_endian: | |
278 i1 = force_to_fit_range (u.i[0], 1, 2147483563); | |
279 i0 = force_to_fit_range (u.i[1], 1, 2147483399); | |
280 break; | |
281 default: | |
282 i0 = force_to_fit_range (u.i[0], 1, 2147483563); | |
283 i1 = force_to_fit_range (u.i[1], 1, 2147483399); | |
284 break; | |
285 } | |
286 | |
4308 | 287 F77_FUNC (setsd, SETSD) (i0, i1); |
288 } | |
289 | |
5730 | 290 ColumnVector |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
291 octave_rand::state (const std::string& d) |
5730 | 292 { |
293 if (! new_initialized) | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
294 initialize_rand_states (); |
5730 | 295 |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
296 return rand_states[d.empty () ? current_distribution : get_dist_id (d)]; |
5730 | 297 } |
298 | |
299 void | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
300 octave_rand::state (const ColumnVector& s, const std::string& d) |
5730 | 301 { |
302 use_old_generators = false; | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
303 |
5730 | 304 maybe_initialize (); |
305 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
306 int old_dist = current_distribution; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
307 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
308 int new_dist = d.empty () ? current_distribution : get_dist_id (d); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
309 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
310 ColumnVector saved_state; |
5730 | 311 |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
312 if (old_dist != new_dist) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
313 saved_state = get_internal_state (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
314 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
315 set_internal_state (s); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
316 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
317 rand_states[new_dist] = get_internal_state (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
318 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
319 if (old_dist != new_dist) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
320 rand_states[old_dist] = saved_state; |
5730 | 321 } |
322 | |
4308 | 323 std::string |
324 octave_rand::distribution (void) | |
325 { | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
326 std::string retval; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
327 |
4308 | 328 maybe_initialize (); |
329 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
330 switch (current_distribution) |
4308 | 331 { |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
332 case uniform_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
333 retval = "uniform"; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
334 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
335 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
336 case normal_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
337 retval = "normal"; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
338 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
339 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
340 case expon_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
341 retval = "exponential"; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
342 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
343 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
344 case poisson_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
345 retval = "poisson"; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
346 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
347 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
348 case gamma_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
349 retval = "gamma"; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
350 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
351 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
352 default: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
353 (*current_liboctave_error_handler) ("rand: invalid distribution"); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
354 break; |
4308 | 355 } |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
356 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
357 return retval; |
4308 | 358 } |
359 | |
360 void | |
361 octave_rand::distribution (const std::string& d) | |
362 { | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
363 switch (get_dist_id (d)) |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
364 { |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
365 case uniform_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
366 octave_rand::uniform_distribution (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
367 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
368 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
369 case normal_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
370 octave_rand::normal_distribution (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
371 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
372 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
373 case expon_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
374 octave_rand::exponential_distribution (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
375 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
376 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
377 case poisson_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
378 octave_rand::poisson_distribution (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
379 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
380 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
381 case gamma_dist: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
382 octave_rand::gamma_distribution (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
383 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
384 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
385 default: |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
386 (*current_liboctave_error_handler) ("rand: invalid distribution"); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
387 break; |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
388 } |
4308 | 389 } |
390 | |
391 void | |
392 octave_rand::uniform_distribution (void) | |
393 { | |
394 maybe_initialize (); | |
395 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
396 switch_to_generator (uniform_dist); |
4308 | 397 |
398 F77_FUNC (setcgn, SETCGN) (uniform_dist); | |
399 } | |
400 | |
401 void | |
402 octave_rand::normal_distribution (void) | |
403 { | |
404 maybe_initialize (); | |
405 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
406 switch_to_generator (normal_dist); |
4308 | 407 |
408 F77_FUNC (setcgn, SETCGN) (normal_dist); | |
409 } | |
410 | |
5730 | 411 void |
412 octave_rand::exponential_distribution (void) | |
413 { | |
414 maybe_initialize (); | |
415 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
416 switch_to_generator (expon_dist); |
5730 | 417 |
418 F77_FUNC (setcgn, SETCGN) (expon_dist); | |
419 } | |
420 | |
421 void | |
422 octave_rand::poisson_distribution (void) | |
423 { | |
424 maybe_initialize (); | |
425 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
426 switch_to_generator (poisson_dist); |
5730 | 427 |
428 F77_FUNC (setcgn, SETCGN) (poisson_dist); | |
429 } | |
430 | |
431 void | |
432 octave_rand::gamma_distribution (void) | |
433 { | |
434 maybe_initialize (); | |
435 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
436 switch_to_generator (gamma_dist); |
5730 | 437 |
438 F77_FUNC (setcgn, SETCGN) (gamma_dist); | |
439 } | |
440 | |
441 | |
4308 | 442 double |
5730 | 443 octave_rand::scalar (double a) |
4308 | 444 { |
445 maybe_initialize (); | |
446 | |
447 double retval = 0.0; | |
448 | |
5730 | 449 if (use_old_generators) |
4308 | 450 { |
5730 | 451 switch (current_distribution) |
452 { | |
453 case uniform_dist: | |
454 F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, retval); | |
455 break; | |
4308 | 456 |
5730 | 457 case normal_dist: |
458 F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, retval); | |
459 break; | |
4308 | 460 |
5730 | 461 case expon_dist: |
462 F77_FUNC (dgenexp, DGENEXP) (1.0, retval); | |
463 break; | |
4308 | 464 |
5730 | 465 case poisson_dist: |
466 if (a < 0.0 || xisnan(a) || xisinf(a)) | |
467 retval = octave_NaN; | |
468 else | |
469 { | |
470 // workaround bug in ignpoi, by calling with different Mu | |
471 F77_FUNC (dignpoi, DIGNPOI) (a + 1, retval); | |
472 F77_FUNC (dignpoi, DIGNPOI) (a, retval); | |
473 } | |
474 break; | |
4308 | 475 |
5730 | 476 case gamma_dist: |
477 if (a <= 0.0 || xisnan(a) || xisinf(a)) | |
478 retval = octave_NaN; | |
479 else | |
480 F77_FUNC (dgengam, DGENGAM) (1.0, a, retval); | |
481 break; | |
4308 | 482 |
5730 | 483 default: |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
484 (*current_liboctave_error_handler) ("rand: invalid distribution"); |
5730 | 485 break; |
4308 | 486 } |
487 } | |
488 else | |
4543 | 489 { |
490 switch (current_distribution) | |
491 { | |
492 case uniform_dist: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
493 retval = oct_randu (); |
4543 | 494 break; |
495 | |
496 case normal_dist: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
497 retval = oct_randn (); |
5730 | 498 break; |
499 | |
500 case expon_dist: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
501 retval = oct_rande (); |
5730 | 502 break; |
503 | |
504 case poisson_dist: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
505 retval = oct_randp (a); |
5730 | 506 break; |
507 | |
508 case gamma_dist: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
509 retval = oct_randg (a); |
4543 | 510 break; |
511 | |
512 default: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
513 (*current_liboctave_error_handler) ("rand: invalid distribution"); |
4543 | 514 break; |
515 } | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
516 |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
517 save_state (); |
4543 | 518 } |
519 | |
520 return retval; | |
521 } | |
522 | |
5730 | 523 #define MAKE_RAND(len) \ |
4308 | 524 do \ |
525 { \ | |
526 double val; \ | |
5730 | 527 for (volatile octave_idx_type i = 0; i < len; i++) \ |
4308 | 528 { \ |
529 OCTAVE_QUIT; \ | |
5730 | 530 RAND_FUNC (val); \ |
531 v[i] = val; \ | |
4308 | 532 } \ |
533 } \ | |
534 while (0) | |
535 | |
5730 | 536 static void |
537 fill_rand (octave_idx_type len, double *v, double a) | |
538 { | |
539 maybe_initialize (); | |
540 | |
541 if (len < 1) | |
542 return; | |
543 | |
544 switch (current_distribution) | |
545 { | |
546 case uniform_dist: | |
547 if (use_old_generators) | |
548 { | |
549 #define RAND_FUNC(x) F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, x) | |
550 MAKE_RAND (len); | |
551 #undef RAND_FUNC | |
552 } | |
553 else | |
554 oct_fill_randu (len, v); | |
555 break; | |
556 | |
557 case normal_dist: | |
558 if (use_old_generators) | |
559 { | |
560 #define RAND_FUNC(x) F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, x) | |
561 MAKE_RAND (len); | |
562 #undef RAND_FUNC | |
563 } | |
564 else | |
565 oct_fill_randn (len, v); | |
566 break; | |
567 | |
568 case expon_dist: | |
569 if (use_old_generators) | |
570 { | |
571 #define RAND_FUNC(x) F77_FUNC (dgenexp, DGENEXP) (1.0, x) | |
572 MAKE_RAND (len); | |
573 #undef RAND_FUNC | |
574 } | |
575 else | |
576 oct_fill_rande (len, v); | |
577 break; | |
578 | |
579 case poisson_dist: | |
580 if (use_old_generators) | |
581 { | |
582 if (a < 0.0 || xisnan(a) || xisinf(a)) | |
583 #define RAND_FUNC(x) x = octave_NaN; | |
584 MAKE_RAND (len); | |
585 #undef RAND_FUNC | |
586 else | |
587 { | |
588 // workaround bug in ignpoi, by calling with different Mu | |
589 double tmp; | |
590 F77_FUNC (dignpoi, DIGNPOI) (a + 1, tmp); | |
591 #define RAND_FUNC(x) F77_FUNC (dignpoi, DIGNPOI) (a, x) | |
592 MAKE_RAND (len); | |
593 #undef RAND_FUNC | |
594 } | |
595 } | |
596 else | |
597 oct_fill_randp (a, len, v); | |
598 break; | |
599 | |
600 case gamma_dist: | |
601 if (use_old_generators) | |
602 { | |
603 if (a <= 0.0 || xisnan(a) || xisinf(a)) | |
604 #define RAND_FUNC(x) x = octave_NaN; | |
605 MAKE_RAND (len); | |
606 #undef RAND_FUNC | |
607 else | |
608 #define RAND_FUNC(x) F77_FUNC (dgengam, DGENGAM) (1.0, a, x) | |
609 MAKE_RAND (len); | |
610 #undef RAND_FUNC | |
611 } | |
612 else | |
613 oct_fill_randg (a, len, v); | |
614 break; | |
615 | |
616 default: | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
617 (*current_liboctave_error_handler) ("rand: invalid distribution"); |
5730 | 618 break; |
619 } | |
620 | |
7533
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
621 save_state (); |
ff52243af934
save state separately for each MT random number generator
John W. Eaton <jwe@octave.org>
parents:
7017
diff
changeset
|
622 |
5730 | 623 return; |
624 } | |
625 | |
626 Matrix | |
627 octave_rand::matrix (octave_idx_type n, octave_idx_type m, double a) | |
628 { | |
629 Matrix retval; | |
630 | |
631 if (n >= 0 && m >= 0) | |
632 { | |
633 retval.resize (n, m); | |
634 | |
635 if (n > 0 && m > 0) | |
636 fill_rand (retval.capacity(), retval.fortran_vec(), a); | |
637 } | |
638 else | |
639 (*current_liboctave_error_handler) ("rand: invalid negative argument"); | |
640 | |
641 return retval; | |
642 } | |
643 | |
644 NDArray | |
645 octave_rand::nd_array (const dim_vector& dims, double a) | |
646 { | |
647 NDArray retval; | |
648 | |
649 if (! dims.all_zero ()) | |
650 { | |
651 retval.resize (dims); | |
652 | |
653 fill_rand (retval.capacity(), retval.fortran_vec(), a); | |
654 } | |
655 | |
656 return retval; | |
657 } | |
658 | |
4308 | 659 Array<double> |
5730 | 660 octave_rand::vector (octave_idx_type n, double a) |
4308 | 661 { |
662 maybe_initialize (); | |
663 | |
664 Array<double> retval; | |
665 | |
666 if (n > 0) | |
667 { | |
668 retval.resize (n); | |
669 | |
5730 | 670 fill_rand (retval.capacity(), retval.fortran_vec(), a); |
4308 | 671 } |
672 else if (n < 0) | |
673 (*current_liboctave_error_handler) ("rand: invalid negative argument"); | |
674 | |
675 return retval; | |
676 } | |
677 | |
678 /* | |
679 ;;; Local Variables: *** | |
680 ;;; mode: C++ *** | |
681 ;;; End: *** | |
682 */ |