Fix `parse-c-struct'.
[bpt/guile.git] / libguile / random.c
CommitLineData
77b13912 1/* Copyright (C) 1999,2000,2001, 2003, 2005, 2006, 2009, 2010 Free Software Foundation, Inc.
73be1d9e 2 * This library is free software; you can redistribute it and/or
53befeb7
NJ
3 * modify it under the terms of the GNU Lesser General Public License
4 * as published by the Free Software Foundation; either version 3 of
5 * the License, or (at your option) any later version.
e7a72986 6 *
53befeb7
NJ
7 * This library is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
e7a72986 11 *
73be1d9e
MV
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
53befeb7
NJ
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301 USA
73be1d9e 16 */
e7a72986 17
1bbd0b84
GB
18
19
e7a72986
MD
20/* Author: Mikael Djurfeldt <djurfeldt@nada.kth.se> */
21
dbb605f5 22#ifdef HAVE_CONFIG_H
2fb8013c
RB
23# include <config.h>
24#endif
25
a0599745 26#include "libguile/_scm.h"
e7a72986 27
8db9cc6c 28#include <gmp.h>
7f146094 29#include <stdio.h>
e7a72986 30#include <math.h>
f34d19c7 31#include <string.h>
a0599745
MD
32#include "libguile/smob.h"
33#include "libguile/numbers.h"
34#include "libguile/feature.h"
35#include "libguile/strings.h"
2fa901a5 36#include "libguile/arrays.h"
46d25cff 37#include "libguile/srfi-4.h"
a0599745 38#include "libguile/vectors.h"
f332e957 39#include "libguile/generalized-vectors.h"
e7a72986 40
a0599745
MD
41#include "libguile/validate.h"
42#include "libguile/random.h"
e7a72986
MD
43
44\f
45/*
46 * A plugin interface for RNGs
47 *
48 * Using this interface, it is possible for the application to tell
49 * libguile to use a different RNG. This is desirable if it is
50 * necessary to use the same RNG everywhere in the application in
51 * order to prevent interference, if the application uses RNG
52 * hardware, or if the application has special demands on the RNG.
53 *
54 * Look in random.h and how the default generator is "plugged in" in
55 * scm_init_random().
56 */
57
92c2555f 58scm_t_rng scm_the_rng;
e7a72986
MD
59
60\f
61/*
62 * The prepackaged RNG
63 *
64 * This is the MWC (Multiply With Carry) random number generator
65 * described by George Marsaglia at the Department of Statistics and
66 * Supercomputer Computations Research Institute, The Florida State
67 * University (http://stat.fsu.edu/~geo).
68 *
69 * It uses 64 bits, has a period of 4578426017172946943 (4.6e18), and
70 * passes all tests in the DIEHARD test suite
71 * (http://stat.fsu.edu/~geo/diehard.html)
72 */
73
99a0ee66
AW
74typedef struct scm_t_i_rstate {
75 scm_t_rstate rstate;
76 scm_t_uint32 w;
77 scm_t_uint32 c;
78} scm_t_i_rstate;
79
80
e7a72986
MD
81#define A 2131995753UL
82
82893676
MG
83#ifndef M_PI
84#define M_PI 3.14159265359
85#endif
86
99a0ee66
AW
87static scm_t_uint32
88scm_i_uniform32 (scm_t_rstate *state)
e7a72986 89{
99a0ee66
AW
90 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
91 scm_t_uint64 x = (scm_t_uint64) A * istate->w + istate->c;
4a9f83ff 92 scm_t_uint32 w = x & 0xffffffffUL;
99a0ee66
AW
93 istate->w = w;
94 istate->c = x >> 32L;
e7a72986
MD
95 return w;
96}
97
99a0ee66
AW
98static void
99scm_i_init_rstate (scm_t_rstate *state, const char *seed, int n)
e7a72986 100{
99a0ee66 101 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
4a9f83ff
MD
102 scm_t_uint32 w = 0L;
103 scm_t_uint32 c = 0L;
e7a72986
MD
104 int i, m;
105 for (i = 0; i < n; ++i)
106 {
107 m = i % 8;
108 if (m < 4)
109 w += seed[i] << (8 * m);
110 else
111 c += seed[i] << (8 * (m - 4));
112 }
8b3747f9 113 if ((w == 0 && c == 0) || (w == -1 && c == A - 1))
e7a72986 114 ++c;
99a0ee66
AW
115 istate->w = w;
116 istate->c = c;
e7a72986
MD
117}
118
99a0ee66
AW
119static scm_t_rstate *
120scm_i_copy_rstate (scm_t_rstate *state)
e7a72986 121{
92d8fd32
LC
122 scm_t_rstate *new_state;
123
a2a95453 124 new_state = scm_gc_malloc_pointerless (state->rng->rstate_size,
92d8fd32 125 "random-state");
a2a95453 126 return memcpy (new_state, state, state->rng->rstate_size);
e7a72986
MD
127}
128
77b13912
AR
129SCM_SYMBOL(scm_i_rstate_tag, "multiply-with-carry");
130
99a0ee66
AW
131static void
132scm_i_rstate_from_datum (scm_t_rstate *state, SCM value)
133#define FUNC_NAME "scm_i_rstate_from_datum"
77b13912 134{
99a0ee66 135 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
b606ff6a 136 scm_t_uint32 w, c;
77b13912
AR
137 long length;
138
139 SCM_VALIDATE_LIST_COPYLEN (SCM_ARG1, value, length);
140 SCM_ASSERT (length == 3, value, SCM_ARG1, FUNC_NAME);
141 SCM_ASSERT (scm_is_eq (SCM_CAR (value), scm_i_rstate_tag),
142 value, SCM_ARG1, FUNC_NAME);
b606ff6a
AW
143 SCM_VALIDATE_UINT_COPY (SCM_ARG1, SCM_CADR (value), w);
144 SCM_VALIDATE_UINT_COPY (SCM_ARG1, SCM_CADDR (value), c);
77b13912 145
99a0ee66
AW
146 istate->w = w;
147 istate->c = c;
77b13912
AR
148}
149#undef FUNC_NAME
150
99a0ee66
AW
151static SCM
152scm_i_rstate_to_datum (scm_t_rstate *state)
77b13912 153{
99a0ee66 154 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
77b13912 155 return scm_list_3 (scm_i_rstate_tag,
99a0ee66
AW
156 scm_from_uint32 (istate->w),
157 scm_from_uint32 (istate->c));
77b13912
AR
158}
159
e7a72986
MD
160\f
161/*
162 * Random number library functions
163 */
164
92c2555f 165scm_t_rstate *
cc95e00a 166scm_c_make_rstate (const char *seed, int n)
5ee11b7c 167{
92d8fd32
LC
168 scm_t_rstate *state;
169
170 state = scm_gc_malloc_pointerless (scm_the_rng.rstate_size,
171 "random-state");
a2a95453
AW
172 state->rng = &scm_the_rng;
173 state->normal_next = 0.0;
174 state->rng->init_rstate (state, seed, n);
5ee11b7c
MD
175 return state;
176}
177
77b13912 178scm_t_rstate *
99a0ee66 179scm_c_rstate_from_datum (SCM datum)
77b13912
AR
180{
181 scm_t_rstate *state;
182
183 state = scm_gc_malloc_pointerless (scm_the_rng.rstate_size,
184 "random-state");
a2a95453
AW
185 state->rng = &scm_the_rng;
186 state->normal_next = 0.0;
187 state->rng->from_datum (state, datum);
77b13912
AR
188 return state;
189}
2ade72d7 190
92c2555f 191scm_t_rstate *
9b741bb6 192scm_c_default_rstate ()
2ade72d7 193#define FUNC_NAME "scm_c_default_rstate"
9b741bb6 194{
c5f268f8 195 SCM state = SCM_VARIABLE_REF (scm_var_random_state);
2ade72d7
DH
196 if (!SCM_RSTATEP (state))
197 SCM_MISC_ERROR ("*random-state* contains bogus random state", SCM_EOL);
9b741bb6
MD
198 return SCM_RSTATE (state);
199}
2ade72d7
DH
200#undef FUNC_NAME
201
9b741bb6 202
a2a95453 203double
92c2555f 204scm_c_uniform01 (scm_t_rstate *state)
e7a72986 205{
a2a95453
AW
206 double x = (double) state->rng->random_bits (state) / (double) 0xffffffffUL;
207 return ((x + (double) state->rng->random_bits (state))
5a92ddfd 208 / (double) 0xffffffffUL);
e7a72986
MD
209}
210
211double
92c2555f 212scm_c_normal01 (scm_t_rstate *state)
e7a72986 213{
a2a95453 214 if (state->normal_next != 0.0)
e7a72986 215 {
a2a95453
AW
216 double ret = state->normal_next;
217
218 state->normal_next = 0.0;
219
220 return ret;
e7a72986
MD
221 }
222 else
223 {
224 double r, a, n;
e7a72986 225
9b741bb6
MD
226 r = sqrt (-2.0 * log (scm_c_uniform01 (state)));
227 a = 2.0 * M_PI * scm_c_uniform01 (state);
e7a72986
MD
228
229 n = r * sin (a);
a2a95453 230 state->normal_next = r * cos (a);
e7a72986
MD
231
232 return n;
233 }
234}
235
236double
92c2555f 237scm_c_exp1 (scm_t_rstate *state)
e7a72986 238{
9b741bb6 239 return - log (scm_c_uniform01 (state));
e7a72986
MD
240}
241
242unsigned char scm_masktab[256];
243
b606ff6a
AW
244scm_t_uint32
245scm_c_random (scm_t_rstate *state, scm_t_uint32 m)
e7a72986 246{
b606ff6a 247 scm_t_uint32 r, mask;
e7a72986
MD
248 mask = (m < 0x100
249 ? scm_masktab[m]
250 : (m < 0x10000
5a92ddfd 251 ? scm_masktab[m >> 8] << 8 | 0xff
e7a72986 252 : (m < 0x1000000
5a92ddfd
MD
253 ? scm_masktab[m >> 16] << 16 | 0xffff
254 : scm_masktab[m >> 24] << 24 | 0xffffff)));
a2a95453 255 while ((r = state->rng->random_bits (state) & mask) >= m);
e7a72986
MD
256 return r;
257}
258
ea7f6344
MD
259/*
260 SCM scm_c_random_bignum (scm_t_rstate *state, SCM m)
261
262 Takes a random state (source of random bits) and a bignum m.
263 Returns a bignum b, 0 <= b < m.
264
265 It does this by allocating a bignum b with as many base 65536 digits
266 as m, filling b with random bits (in 32 bit chunks) up to the most
267 significant 1 in m, and, finally checking if the resultant b is too
268 large (>= m). If too large, we simply repeat the process again. (It
269 is important to throw away all generated random bits if b >= m,
270 otherwise we'll end up with a distorted distribution.)
271
272*/
273
e7a72986 274SCM
92c2555f 275scm_c_random_bignum (scm_t_rstate *state, SCM m)
e7a72986 276{
969d3bd0 277 SCM result = scm_i_mkbig ();
969d3bd0 278 const size_t m_bits = mpz_sizeinbase (SCM_I_BIG_MPZ (m), 2);
b606ff6a
AW
279 /* how many bits would only partially fill the last scm_t_uint32? */
280 const size_t end_bits = m_bits % (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
281 scm_t_uint32 *random_chunks = NULL;
282 const scm_t_uint32 num_full_chunks =
283 m_bits / (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
284 const scm_t_uint32 num_chunks = num_full_chunks + ((end_bits) ? 1 : 0);
969d3bd0
RB
285
286 /* we know the result will be this big */
287 mpz_realloc2 (SCM_I_BIG_MPZ (result), m_bits);
288
289 random_chunks =
b606ff6a 290 (scm_t_uint32 *) scm_gc_calloc (num_chunks * sizeof (scm_t_uint32),
969d3bd0
RB
291 "random bignum chunks");
292
372691d8 293 do
e7a72986 294 {
b606ff6a
AW
295 scm_t_uint32 *current_chunk = random_chunks + (num_chunks - 1);
296 scm_t_uint32 chunks_left = num_chunks;
969d3bd0
RB
297
298 mpz_set_ui (SCM_I_BIG_MPZ (result), 0);
299
300 if (end_bits)
301 {
302 /* generate a mask with ones in the end_bits position, i.e. if
303 end_bits is 3, then we'd have a mask of ...0000000111 */
a2a95453 304 const scm_t_uint32 rndbits = state->rng->random_bits (state);
b606ff6a
AW
305 int rshift = (sizeof (scm_t_uint32) * SCM_CHAR_BIT) - end_bits;
306 scm_t_uint32 mask = ((scm_t_uint32)-1) >> rshift;
307 scm_t_uint32 highest_bits = rndbits & mask;
969d3bd0
RB
308 *current_chunk-- = highest_bits;
309 chunks_left--;
310 }
311
312 while (chunks_left)
313 {
b606ff6a 314 /* now fill in the remaining scm_t_uint32 sized chunks */
a2a95453 315 *current_chunk-- = state->rng->random_bits (state);
969d3bd0
RB
316 chunks_left--;
317 }
318 mpz_import (SCM_I_BIG_MPZ (result),
319 num_chunks,
320 -1,
b606ff6a 321 sizeof (scm_t_uint32),
969d3bd0
RB
322 0,
323 0,
324 random_chunks);
372691d8
MD
325 /* if result >= m, regenerate it (it is important to regenerate
326 all bits in order not to get a distorted distribution) */
327 } while (mpz_cmp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (m)) >= 0);
969d3bd0 328 scm_gc_free (random_chunks,
b606ff6a 329 num_chunks * sizeof (scm_t_uint32),
969d3bd0 330 "random bignum chunks");
8db9cc6c 331 return scm_i_normbig (result);
e7a72986
MD
332}
333
334/*
335 * Scheme level representation of random states.
336 */
337
92c2555f 338scm_t_bits scm_tc16_rstate;
e7a72986
MD
339
340static SCM
92c2555f 341make_rstate (scm_t_rstate *state)
e7a72986 342{
23a62151 343 SCM_RETURN_NEWSMOB (scm_tc16_rstate, state);
e7a72986
MD
344}
345
e7a72986 346
e7a72986
MD
347/*
348 * Scheme level interface.
349 */
350
cc95e00a 351SCM_GLOBAL_VARIABLE_INIT (scm_var_random_state, "*random-state*", scm_seed_to_random_state (scm_from_locale_string ("URL:http://stat.fsu.edu/~geo/diehard.html")));
e7a72986 352
a1ec6916 353SCM_DEFINE (scm_random, "random", 1, 1, 0,
1bbd0b84 354 (SCM n, SCM state),
34d19ef6 355 "Return a number in [0, N).\n"
d928e0b4 356 "\n"
9401323e
NJ
357 "Accepts a positive integer or real n and returns a\n"
358 "number of the same type between zero (inclusive) and\n"
359 "N (exclusive). The values returned have a uniform\n"
d928e0b4
GB
360 "distribution.\n"
361 "\n"
3b644514
MG
362 "The optional argument @var{state} must be of the type produced\n"
363 "by @code{seed->random-state}. It defaults to the value of the\n"
364 "variable @var{*random-state*}. This object is used to maintain\n"
365 "the state of the pseudo-random-number generator and is altered\n"
366 "as a side effect of the random operation.")
1bbd0b84 367#define FUNC_NAME s_scm_random
e7a72986
MD
368{
369 if (SCM_UNBNDP (state))
86d31dfe 370 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 371 SCM_VALIDATE_RSTATE (2, state);
e11e83f3 372 if (SCM_I_INUMP (n))
e7a72986 373 {
9defb641
AW
374 unsigned long m = (unsigned long) SCM_I_INUM (n);
375 SCM_ASSERT_RANGE (1, n, SCM_I_INUM (n) > 0);
376#if SCM_SIZEOF_UNSIGNED_LONG <= 4
377 return scm_from_uint32 (scm_c_random (SCM_RSTATE (state),
378 (scm_t_uint32) m));
379#elif SCM_SIZEOF_UNSIGNED_LONG <= 8
380 if (m <= SCM_T_UINT32_MAX)
381 return scm_from_uint32 (scm_c_random (SCM_RSTATE (state),
382 (scm_t_uint32) m));
383 else
384 {
385 scm_t_uint64 upper, lower;
386
387 upper = scm_c_random (SCM_RSTATE (state), (scm_t_uint32) (m >> 32));
388 lower = scm_c_random (SCM_RSTATE (state), SCM_T_UINT32_MAX);
389 return scm_from_uint64 ((upper << 32) | lower);
390 }
391#else
392#error "Cannot deal with this platform's unsigned long size"
393#endif
e7a72986 394 }
34d19ef6 395 SCM_VALIDATE_NIM (1, n);
e7a72986 396 if (SCM_REALP (n))
d9a67fc4
MV
397 return scm_from_double (SCM_REAL_VALUE (n)
398 * scm_c_uniform01 (SCM_RSTATE (state)));
969d3bd0 399
a55c2b68
MV
400 if (!SCM_BIGP (n))
401 SCM_WRONG_TYPE_ARG (1, n);
9b741bb6 402 return scm_c_random_bignum (SCM_RSTATE (state), n);
e7a72986 403}
1bbd0b84 404#undef FUNC_NAME
e7a72986 405
a1ec6916 406SCM_DEFINE (scm_copy_random_state, "copy-random-state", 0, 1, 0,
1bbd0b84 407 (SCM state),
3b644514 408 "Return a copy of the random state @var{state}.")
1bbd0b84 409#define FUNC_NAME s_scm_copy_random_state
e7a72986
MD
410{
411 if (SCM_UNBNDP (state))
86d31dfe 412 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 413 SCM_VALIDATE_RSTATE (1, state);
a2a95453 414 return make_rstate (SCM_RSTATE (state)->rng->copy_rstate (SCM_RSTATE (state)));
e7a72986 415}
1bbd0b84 416#undef FUNC_NAME
e7a72986 417
a1ec6916 418SCM_DEFINE (scm_seed_to_random_state, "seed->random-state", 1, 0, 0,
1bbd0b84 419 (SCM seed),
3b644514 420 "Return a new random state using @var{seed}.")
1bbd0b84 421#define FUNC_NAME s_scm_seed_to_random_state
5ee11b7c 422{
8824ac88 423 SCM res;
5ee11b7c
MD
424 if (SCM_NUMBERP (seed))
425 seed = scm_number_to_string (seed, SCM_UNDEFINED);
34d19ef6 426 SCM_VALIDATE_STRING (1, seed);
cc95e00a
MV
427 res = make_rstate (scm_c_make_rstate (scm_i_string_chars (seed),
428 scm_i_string_length (seed)));
8824ac88
MV
429 scm_remember_upto_here_1 (seed);
430 return res;
431
5ee11b7c 432}
1bbd0b84 433#undef FUNC_NAME
5ee11b7c 434
99a0ee66
AW
435SCM_DEFINE (scm_datum_to_random_state, "datum->random-state", 1, 0, 0,
436 (SCM datum),
1d454874
AW
437 "Return a new random state using @var{datum}, which should have\n"
438 "been obtailed from @code{random-state->datum}.")
99a0ee66 439#define FUNC_NAME s_scm_datum_to_random_state
77b13912 440{
99a0ee66 441 return make_rstate (scm_c_rstate_from_datum (datum));
77b13912
AR
442}
443#undef FUNC_NAME
444
99a0ee66 445SCM_DEFINE (scm_random_state_to_datum, "random-state->datum", 1, 0, 0,
77b13912 446 (SCM state),
99a0ee66
AW
447 "Return a datum representation of @var{state} that may be\n"
448 "written out and read back with the Scheme reader.")
449#define FUNC_NAME s_scm_random_state_to_datum
77b13912
AR
450{
451 SCM_VALIDATE_RSTATE (1, state);
a2a95453 452 return SCM_RSTATE (state)->rng->to_datum (SCM_RSTATE (state));
77b13912
AR
453}
454#undef FUNC_NAME
455
a1ec6916 456SCM_DEFINE (scm_random_uniform, "random:uniform", 0, 1, 0,
1bbd0b84 457 (SCM state),
1e6808ea
MG
458 "Return a uniformly distributed inexact real random number in\n"
459 "[0,1).")
1bbd0b84 460#define FUNC_NAME s_scm_random_uniform
e7a72986
MD
461{
462 if (SCM_UNBNDP (state))
86d31dfe 463 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 464 SCM_VALIDATE_RSTATE (1, state);
d9a67fc4 465 return scm_from_double (scm_c_uniform01 (SCM_RSTATE (state)));
e7a72986 466}
1bbd0b84 467#undef FUNC_NAME
e7a72986 468
a1ec6916 469SCM_DEFINE (scm_random_normal, "random:normal", 0, 1, 0,
1bbd0b84 470 (SCM state),
1e6808ea
MG
471 "Return an inexact real in a normal distribution. The\n"
472 "distribution used has mean 0 and standard deviation 1. For a\n"
473 "normal distribution with mean m and standard deviation d use\n"
474 "@code{(+ m (* d (random:normal)))}.")
1bbd0b84 475#define FUNC_NAME s_scm_random_normal
afe5177e
GH
476{
477 if (SCM_UNBNDP (state))
86d31dfe 478 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 479 SCM_VALIDATE_RSTATE (1, state);
d9a67fc4 480 return scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
afe5177e 481}
1bbd0b84 482#undef FUNC_NAME
afe5177e 483
e7a72986 484static void
46d25cff 485vector_scale_x (SCM v, double c)
e7a72986 486{
46d25cff 487 size_t n;
4057a3e0 488 if (scm_is_simple_vector (v))
46d25cff 489 {
4057a3e0 490 n = SCM_SIMPLE_VECTOR_LENGTH (v);
46d25cff 491 while (n-- > 0)
4057a3e0 492 SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n)) *= c;
46d25cff 493 }
e7a72986 494 else
46d25cff
MV
495 {
496 /* must be a f64vector. */
4057a3e0
MV
497 scm_t_array_handle handle;
498 size_t i, len;
499 ssize_t inc;
500 double *elts;
501
502 elts = scm_f64vector_writable_elements (v, &handle, &len, &inc);
503
504 for (i = 0; i < len; i++, elts += inc)
505 *elts *= c;
c8857a4d
MV
506
507 scm_array_handle_release (&handle);
46d25cff 508 }
e7a72986
MD
509}
510
511static double
512vector_sum_squares (SCM v)
513{
514 double x, sum = 0.0;
46d25cff 515 size_t n;
4057a3e0 516 if (scm_is_simple_vector (v))
46d25cff 517 {
4057a3e0 518 n = SCM_SIMPLE_VECTOR_LENGTH (v);
46d25cff
MV
519 while (n-- > 0)
520 {
4057a3e0 521 x = SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n));
46d25cff
MV
522 sum += x * x;
523 }
524 }
e7a72986 525 else
46d25cff
MV
526 {
527 /* must be a f64vector. */
4057a3e0
MV
528 scm_t_array_handle handle;
529 size_t i, len;
530 ssize_t inc;
531 const double *elts;
532
533 elts = scm_f64vector_elements (v, &handle, &len, &inc);
534
535 for (i = 0; i < len; i++, elts += inc)
46d25cff 536 {
4057a3e0 537 x = *elts;
46d25cff
MV
538 sum += x * x;
539 }
4057a3e0 540
c8857a4d 541 scm_array_handle_release (&handle);
46d25cff 542 }
e7a72986
MD
543 return sum;
544}
545
e7a72986
MD
546/* For the uniform distribution on the solid sphere, note that in
547 * this distribution the length r of the vector has cumulative
548 * distribution r^n; i.e., u=r^n is uniform [0,1], so r can be
549 * generated as r=u^(1/n).
550 */
a1ec6916 551SCM_DEFINE (scm_random_solid_sphere_x, "random:solid-sphere!", 1, 1, 0,
1bbd0b84 552 (SCM v, SCM state),
6efaeb35
KR
553 "Fills @var{vect} with inexact real random numbers the sum of\n"
554 "whose squares is less than 1.0. Thinking of @var{vect} as\n"
555 "coordinates in space of dimension @var{n} @math{=}\n"
556 "@code{(vector-length @var{vect})}, the coordinates are\n"
557 "uniformly distributed within the unit @var{n}-sphere.")
1bbd0b84 558#define FUNC_NAME s_scm_random_solid_sphere_x
e7a72986 559{
e7a72986 560 if (SCM_UNBNDP (state))
86d31dfe 561 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 562 SCM_VALIDATE_RSTATE (2, state);
e7a72986 563 scm_random_normal_vector_x (v, state);
46d25cff
MV
564 vector_scale_x (v,
565 pow (scm_c_uniform01 (SCM_RSTATE (state)),
f160e709 566 1.0 / scm_c_generalized_vector_length (v))
46d25cff 567 / sqrt (vector_sum_squares (v)));
e7a72986
MD
568 return SCM_UNSPECIFIED;
569}
1bbd0b84 570#undef FUNC_NAME
e7a72986 571
a1ec6916 572SCM_DEFINE (scm_random_hollow_sphere_x, "random:hollow-sphere!", 1, 1, 0,
1bbd0b84 573 (SCM v, SCM state),
d928e0b4
GB
574 "Fills vect with inexact real random numbers\n"
575 "the sum of whose squares is equal to 1.0.\n"
9401323e 576 "Thinking of vect as coordinates in space of\n"
d928e0b4 577 "dimension n = (vector-length vect), the coordinates\n"
9401323e 578 "are uniformly distributed over the surface of the\n"
72dd0a03 579 "unit n-sphere.")
1bbd0b84 580#define FUNC_NAME s_scm_random_hollow_sphere_x
e7a72986 581{
e7a72986 582 if (SCM_UNBNDP (state))
86d31dfe 583 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 584 SCM_VALIDATE_RSTATE (2, state);
e7a72986 585 scm_random_normal_vector_x (v, state);
46d25cff 586 vector_scale_x (v, 1 / sqrt (vector_sum_squares (v)));
e7a72986
MD
587 return SCM_UNSPECIFIED;
588}
1bbd0b84 589#undef FUNC_NAME
e7a72986 590
1bbd0b84 591
a1ec6916 592SCM_DEFINE (scm_random_normal_vector_x, "random:normal-vector!", 1, 1, 0,
1bbd0b84 593 (SCM v, SCM state),
d928e0b4
GB
594 "Fills vect with inexact real random numbers that are\n"
595 "independent and standard normally distributed\n"
64ba8e85 596 "(i.e., with mean 0 and variance 1).")
1bbd0b84 597#define FUNC_NAME s_scm_random_normal_vector_x
e7a72986 598{
4057a3e0
MV
599 long i;
600 scm_t_array_handle handle;
601 scm_t_array_dim *dim;
46d25cff 602
e7a72986 603 if (SCM_UNBNDP (state))
86d31dfe 604 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 605 SCM_VALIDATE_RSTATE (2, state);
4057a3e0 606
c8857a4d 607 scm_generalized_vector_get_handle (v, &handle);
4057a3e0
MV
608 dim = scm_array_handle_dims (&handle);
609
610 if (scm_is_vector (v))
46d25cff 611 {
4057a3e0
MV
612 SCM *elts = scm_array_handle_writable_elements (&handle);
613 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
614 *elts = scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
46d25cff 615 }
e7a72986 616 else
46d25cff
MV
617 {
618 /* must be a f64vector. */
4057a3e0
MV
619 double *elts = scm_array_handle_f64_writable_elements (&handle);
620 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
621 *elts = scm_c_normal01 (SCM_RSTATE (state));
46d25cff 622 }
4057a3e0 623
c8857a4d
MV
624 scm_array_handle_release (&handle);
625
e7a72986
MD
626 return SCM_UNSPECIFIED;
627}
1bbd0b84 628#undef FUNC_NAME
e7a72986 629
a1ec6916 630SCM_DEFINE (scm_random_exp, "random:exp", 0, 1, 0,
1bbd0b84 631 (SCM state),
1e6808ea
MG
632 "Return an inexact real in an exponential distribution with mean\n"
633 "1. For an exponential distribution with mean u use (* u\n"
634 "(random:exp)).")
1bbd0b84 635#define FUNC_NAME s_scm_random_exp
e7a72986
MD
636{
637 if (SCM_UNBNDP (state))
86d31dfe 638 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 639 SCM_VALIDATE_RSTATE (1, state);
d9a67fc4 640 return scm_from_double (scm_c_exp1 (SCM_RSTATE (state)));
e7a72986 641}
1bbd0b84 642#undef FUNC_NAME
e7a72986
MD
643
644void
645scm_init_random ()
646{
647 int i, m;
648 /* plug in default RNG */
92c2555f 649 scm_t_rng rng =
e7a72986 650 {
92c2555f 651 sizeof (scm_t_i_rstate),
99a0ee66
AW
652 scm_i_uniform32,
653 scm_i_init_rstate,
654 scm_i_copy_rstate,
655 scm_i_rstate_from_datum,
656 scm_i_rstate_to_datum
e7a72986
MD
657 };
658 scm_the_rng = rng;
659
e841c3e0 660 scm_tc16_rstate = scm_make_smob_type ("random-state", 0);
e7a72986
MD
661
662 for (m = 1; m <= 0x100; m <<= 1)
663 for (i = m >> 1; i < m; ++i)
664 scm_masktab[i] = m - 1;
665
a0599745 666#include "libguile/random.x"
e7a72986
MD
667
668 scm_add_feature ("random");
669}
89e00824
ML
670
671/*
672 Local Variables:
673 c-file-style: "gnu"
674 End:
675*/