Update Gnulib to v0.0-6827-g39c3009; use the `dirfd' module.
[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
2af6e135
AR
244static inline scm_t_uint32
245scm_i_mask32 (scm_t_uint32 m)
e7a72986 246{
2af6e135 247 return (m < 0x100
e7a72986
MD
248 ? scm_masktab[m]
249 : (m < 0x10000
5a92ddfd 250 ? scm_masktab[m >> 8] << 8 | 0xff
e7a72986 251 : (m < 0x1000000
5a92ddfd
MD
252 ? scm_masktab[m >> 16] << 16 | 0xffff
253 : scm_masktab[m >> 24] << 24 | 0xffffff)));
2af6e135
AR
254}
255
256scm_t_uint32
257scm_c_random (scm_t_rstate *state, scm_t_uint32 m)
258{
259 scm_t_uint32 r, mask = scm_i_mask32 (m);
a2a95453 260 while ((r = state->rng->random_bits (state) & mask) >= m);
e7a72986
MD
261 return r;
262}
263
2af6e135
AR
264scm_t_uint64
265scm_c_random64 (scm_t_rstate *state, scm_t_uint64 m)
266{
267 scm_t_uint64 r;
268 scm_t_uint32 mask;
269
270 if (m <= SCM_T_UINT32_MAX)
271 return scm_c_random (state, (scm_t_uint32) m);
272
273 mask = scm_i_mask32 (m >> 32);
274 while ((r = ((scm_t_uint64) (state->rng->random_bits (state) & mask) << 32)
275 | state->rng->random_bits (state)) >= m)
276 ;
277 return r;
278}
279
ea7f6344
MD
280/*
281 SCM scm_c_random_bignum (scm_t_rstate *state, SCM m)
282
283 Takes a random state (source of random bits) and a bignum m.
284 Returns a bignum b, 0 <= b < m.
285
286 It does this by allocating a bignum b with as many base 65536 digits
287 as m, filling b with random bits (in 32 bit chunks) up to the most
288 significant 1 in m, and, finally checking if the resultant b is too
289 large (>= m). If too large, we simply repeat the process again. (It
290 is important to throw away all generated random bits if b >= m,
291 otherwise we'll end up with a distorted distribution.)
292
293*/
294
e7a72986 295SCM
92c2555f 296scm_c_random_bignum (scm_t_rstate *state, SCM m)
e7a72986 297{
969d3bd0 298 SCM result = scm_i_mkbig ();
969d3bd0 299 const size_t m_bits = mpz_sizeinbase (SCM_I_BIG_MPZ (m), 2);
b606ff6a
AW
300 /* how many bits would only partially fill the last scm_t_uint32? */
301 const size_t end_bits = m_bits % (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
302 scm_t_uint32 *random_chunks = NULL;
303 const scm_t_uint32 num_full_chunks =
304 m_bits / (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
305 const scm_t_uint32 num_chunks = num_full_chunks + ((end_bits) ? 1 : 0);
969d3bd0
RB
306
307 /* we know the result will be this big */
308 mpz_realloc2 (SCM_I_BIG_MPZ (result), m_bits);
309
310 random_chunks =
b606ff6a 311 (scm_t_uint32 *) scm_gc_calloc (num_chunks * sizeof (scm_t_uint32),
969d3bd0
RB
312 "random bignum chunks");
313
372691d8 314 do
e7a72986 315 {
b606ff6a
AW
316 scm_t_uint32 *current_chunk = random_chunks + (num_chunks - 1);
317 scm_t_uint32 chunks_left = num_chunks;
969d3bd0
RB
318
319 mpz_set_ui (SCM_I_BIG_MPZ (result), 0);
320
321 if (end_bits)
322 {
323 /* generate a mask with ones in the end_bits position, i.e. if
324 end_bits is 3, then we'd have a mask of ...0000000111 */
a2a95453 325 const scm_t_uint32 rndbits = state->rng->random_bits (state);
b606ff6a
AW
326 int rshift = (sizeof (scm_t_uint32) * SCM_CHAR_BIT) - end_bits;
327 scm_t_uint32 mask = ((scm_t_uint32)-1) >> rshift;
328 scm_t_uint32 highest_bits = rndbits & mask;
969d3bd0
RB
329 *current_chunk-- = highest_bits;
330 chunks_left--;
331 }
332
333 while (chunks_left)
334 {
b606ff6a 335 /* now fill in the remaining scm_t_uint32 sized chunks */
a2a95453 336 *current_chunk-- = state->rng->random_bits (state);
969d3bd0
RB
337 chunks_left--;
338 }
339 mpz_import (SCM_I_BIG_MPZ (result),
340 num_chunks,
341 -1,
b606ff6a 342 sizeof (scm_t_uint32),
969d3bd0
RB
343 0,
344 0,
345 random_chunks);
372691d8
MD
346 /* if result >= m, regenerate it (it is important to regenerate
347 all bits in order not to get a distorted distribution) */
348 } while (mpz_cmp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (m)) >= 0);
969d3bd0 349 scm_gc_free (random_chunks,
b606ff6a 350 num_chunks * sizeof (scm_t_uint32),
969d3bd0 351 "random bignum chunks");
8db9cc6c 352 return scm_i_normbig (result);
e7a72986
MD
353}
354
355/*
356 * Scheme level representation of random states.
357 */
358
92c2555f 359scm_t_bits scm_tc16_rstate;
e7a72986
MD
360
361static SCM
92c2555f 362make_rstate (scm_t_rstate *state)
e7a72986 363{
23a62151 364 SCM_RETURN_NEWSMOB (scm_tc16_rstate, state);
e7a72986
MD
365}
366
e7a72986 367
e7a72986
MD
368/*
369 * Scheme level interface.
370 */
371
cc95e00a 372SCM_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 373
a1ec6916 374SCM_DEFINE (scm_random, "random", 1, 1, 0,
1bbd0b84 375 (SCM n, SCM state),
34d19ef6 376 "Return a number in [0, N).\n"
d928e0b4 377 "\n"
9401323e
NJ
378 "Accepts a positive integer or real n and returns a\n"
379 "number of the same type between zero (inclusive) and\n"
380 "N (exclusive). The values returned have a uniform\n"
d928e0b4
GB
381 "distribution.\n"
382 "\n"
3b644514
MG
383 "The optional argument @var{state} must be of the type produced\n"
384 "by @code{seed->random-state}. It defaults to the value of the\n"
385 "variable @var{*random-state*}. This object is used to maintain\n"
386 "the state of the pseudo-random-number generator and is altered\n"
387 "as a side effect of the random operation.")
1bbd0b84 388#define FUNC_NAME s_scm_random
e7a72986
MD
389{
390 if (SCM_UNBNDP (state))
86d31dfe 391 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 392 SCM_VALIDATE_RSTATE (2, state);
e11e83f3 393 if (SCM_I_INUMP (n))
e7a72986 394 {
e25f3727 395 scm_t_bits m = (scm_t_bits) SCM_I_INUM (n);
9defb641 396 SCM_ASSERT_RANGE (1, n, SCM_I_INUM (n) > 0);
e25f3727 397#if SCM_SIZEOF_UINTPTR_T <= 4
9defb641
AW
398 return scm_from_uint32 (scm_c_random (SCM_RSTATE (state),
399 (scm_t_uint32) m));
e25f3727 400#elif SCM_SIZEOF_UINTPTR_T <= 8
2af6e135
AR
401 return scm_from_uint64 (scm_c_random64 (SCM_RSTATE (state),
402 (scm_t_uint64) m));
9defb641 403#else
e25f3727 404#error "Cannot deal with this platform's scm_t_bits size"
9defb641 405#endif
e7a72986 406 }
34d19ef6 407 SCM_VALIDATE_NIM (1, n);
e7a72986 408 if (SCM_REALP (n))
d9a67fc4
MV
409 return scm_from_double (SCM_REAL_VALUE (n)
410 * scm_c_uniform01 (SCM_RSTATE (state)));
969d3bd0 411
a55c2b68
MV
412 if (!SCM_BIGP (n))
413 SCM_WRONG_TYPE_ARG (1, n);
9b741bb6 414 return scm_c_random_bignum (SCM_RSTATE (state), n);
e7a72986 415}
1bbd0b84 416#undef FUNC_NAME
e7a72986 417
a1ec6916 418SCM_DEFINE (scm_copy_random_state, "copy-random-state", 0, 1, 0,
1bbd0b84 419 (SCM state),
3b644514 420 "Return a copy of the random state @var{state}.")
1bbd0b84 421#define FUNC_NAME s_scm_copy_random_state
e7a72986
MD
422{
423 if (SCM_UNBNDP (state))
86d31dfe 424 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 425 SCM_VALIDATE_RSTATE (1, state);
a2a95453 426 return make_rstate (SCM_RSTATE (state)->rng->copy_rstate (SCM_RSTATE (state)));
e7a72986 427}
1bbd0b84 428#undef FUNC_NAME
e7a72986 429
a1ec6916 430SCM_DEFINE (scm_seed_to_random_state, "seed->random-state", 1, 0, 0,
1bbd0b84 431 (SCM seed),
3b644514 432 "Return a new random state using @var{seed}.")
1bbd0b84 433#define FUNC_NAME s_scm_seed_to_random_state
5ee11b7c 434{
8824ac88 435 SCM res;
5ee11b7c
MD
436 if (SCM_NUMBERP (seed))
437 seed = scm_number_to_string (seed, SCM_UNDEFINED);
34d19ef6 438 SCM_VALIDATE_STRING (1, seed);
cc95e00a
MV
439 res = make_rstate (scm_c_make_rstate (scm_i_string_chars (seed),
440 scm_i_string_length (seed)));
8824ac88
MV
441 scm_remember_upto_here_1 (seed);
442 return res;
443
5ee11b7c 444}
1bbd0b84 445#undef FUNC_NAME
5ee11b7c 446
99a0ee66
AW
447SCM_DEFINE (scm_datum_to_random_state, "datum->random-state", 1, 0, 0,
448 (SCM datum),
1d454874 449 "Return a new random state using @var{datum}, which should have\n"
ffb62a43 450 "been obtained from @code{random-state->datum}.")
99a0ee66 451#define FUNC_NAME s_scm_datum_to_random_state
77b13912 452{
99a0ee66 453 return make_rstate (scm_c_rstate_from_datum (datum));
77b13912
AR
454}
455#undef FUNC_NAME
456
99a0ee66 457SCM_DEFINE (scm_random_state_to_datum, "random-state->datum", 1, 0, 0,
77b13912 458 (SCM state),
99a0ee66
AW
459 "Return a datum representation of @var{state} that may be\n"
460 "written out and read back with the Scheme reader.")
461#define FUNC_NAME s_scm_random_state_to_datum
77b13912
AR
462{
463 SCM_VALIDATE_RSTATE (1, state);
a2a95453 464 return SCM_RSTATE (state)->rng->to_datum (SCM_RSTATE (state));
77b13912
AR
465}
466#undef FUNC_NAME
467
a1ec6916 468SCM_DEFINE (scm_random_uniform, "random:uniform", 0, 1, 0,
1bbd0b84 469 (SCM state),
1e6808ea
MG
470 "Return a uniformly distributed inexact real random number in\n"
471 "[0,1).")
1bbd0b84 472#define FUNC_NAME s_scm_random_uniform
e7a72986
MD
473{
474 if (SCM_UNBNDP (state))
86d31dfe 475 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 476 SCM_VALIDATE_RSTATE (1, state);
d9a67fc4 477 return scm_from_double (scm_c_uniform01 (SCM_RSTATE (state)));
e7a72986 478}
1bbd0b84 479#undef FUNC_NAME
e7a72986 480
a1ec6916 481SCM_DEFINE (scm_random_normal, "random:normal", 0, 1, 0,
1bbd0b84 482 (SCM state),
1e6808ea
MG
483 "Return an inexact real in a normal distribution. The\n"
484 "distribution used has mean 0 and standard deviation 1. For a\n"
485 "normal distribution with mean m and standard deviation d use\n"
486 "@code{(+ m (* d (random:normal)))}.")
1bbd0b84 487#define FUNC_NAME s_scm_random_normal
afe5177e
GH
488{
489 if (SCM_UNBNDP (state))
86d31dfe 490 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 491 SCM_VALIDATE_RSTATE (1, state);
d9a67fc4 492 return scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
afe5177e 493}
1bbd0b84 494#undef FUNC_NAME
afe5177e 495
e7a72986 496static void
46d25cff 497vector_scale_x (SCM v, double c)
e7a72986 498{
46d25cff 499 size_t n;
4057a3e0 500 if (scm_is_simple_vector (v))
46d25cff 501 {
4057a3e0 502 n = SCM_SIMPLE_VECTOR_LENGTH (v);
46d25cff 503 while (n-- > 0)
4057a3e0 504 SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n)) *= c;
46d25cff 505 }
e7a72986 506 else
46d25cff
MV
507 {
508 /* must be a f64vector. */
4057a3e0
MV
509 scm_t_array_handle handle;
510 size_t i, len;
511 ssize_t inc;
512 double *elts;
513
514 elts = scm_f64vector_writable_elements (v, &handle, &len, &inc);
515
516 for (i = 0; i < len; i++, elts += inc)
517 *elts *= c;
c8857a4d
MV
518
519 scm_array_handle_release (&handle);
46d25cff 520 }
e7a72986
MD
521}
522
523static double
524vector_sum_squares (SCM v)
525{
526 double x, sum = 0.0;
46d25cff 527 size_t n;
4057a3e0 528 if (scm_is_simple_vector (v))
46d25cff 529 {
4057a3e0 530 n = SCM_SIMPLE_VECTOR_LENGTH (v);
46d25cff
MV
531 while (n-- > 0)
532 {
4057a3e0 533 x = SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n));
46d25cff
MV
534 sum += x * x;
535 }
536 }
e7a72986 537 else
46d25cff
MV
538 {
539 /* must be a f64vector. */
4057a3e0
MV
540 scm_t_array_handle handle;
541 size_t i, len;
542 ssize_t inc;
543 const double *elts;
544
545 elts = scm_f64vector_elements (v, &handle, &len, &inc);
546
547 for (i = 0; i < len; i++, elts += inc)
46d25cff 548 {
4057a3e0 549 x = *elts;
46d25cff
MV
550 sum += x * x;
551 }
4057a3e0 552
c8857a4d 553 scm_array_handle_release (&handle);
46d25cff 554 }
e7a72986
MD
555 return sum;
556}
557
e7a72986
MD
558/* For the uniform distribution on the solid sphere, note that in
559 * this distribution the length r of the vector has cumulative
560 * distribution r^n; i.e., u=r^n is uniform [0,1], so r can be
561 * generated as r=u^(1/n).
562 */
a1ec6916 563SCM_DEFINE (scm_random_solid_sphere_x, "random:solid-sphere!", 1, 1, 0,
1bbd0b84 564 (SCM v, SCM state),
6efaeb35
KR
565 "Fills @var{vect} with inexact real random numbers the sum of\n"
566 "whose squares is less than 1.0. Thinking of @var{vect} as\n"
567 "coordinates in space of dimension @var{n} @math{=}\n"
568 "@code{(vector-length @var{vect})}, the coordinates are\n"
569 "uniformly distributed within the unit @var{n}-sphere.")
1bbd0b84 570#define FUNC_NAME s_scm_random_solid_sphere_x
e7a72986 571{
e7a72986 572 if (SCM_UNBNDP (state))
86d31dfe 573 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 574 SCM_VALIDATE_RSTATE (2, state);
e7a72986 575 scm_random_normal_vector_x (v, state);
46d25cff
MV
576 vector_scale_x (v,
577 pow (scm_c_uniform01 (SCM_RSTATE (state)),
f160e709 578 1.0 / scm_c_generalized_vector_length (v))
46d25cff 579 / sqrt (vector_sum_squares (v)));
e7a72986
MD
580 return SCM_UNSPECIFIED;
581}
1bbd0b84 582#undef FUNC_NAME
e7a72986 583
a1ec6916 584SCM_DEFINE (scm_random_hollow_sphere_x, "random:hollow-sphere!", 1, 1, 0,
1bbd0b84 585 (SCM v, SCM state),
d928e0b4
GB
586 "Fills vect with inexact real random numbers\n"
587 "the sum of whose squares is equal to 1.0.\n"
9401323e 588 "Thinking of vect as coordinates in space of\n"
d928e0b4 589 "dimension n = (vector-length vect), the coordinates\n"
9401323e 590 "are uniformly distributed over the surface of the\n"
72dd0a03 591 "unit n-sphere.")
1bbd0b84 592#define FUNC_NAME s_scm_random_hollow_sphere_x
e7a72986 593{
e7a72986 594 if (SCM_UNBNDP (state))
86d31dfe 595 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 596 SCM_VALIDATE_RSTATE (2, state);
e7a72986 597 scm_random_normal_vector_x (v, state);
46d25cff 598 vector_scale_x (v, 1 / sqrt (vector_sum_squares (v)));
e7a72986
MD
599 return SCM_UNSPECIFIED;
600}
1bbd0b84 601#undef FUNC_NAME
e7a72986 602
1bbd0b84 603
a1ec6916 604SCM_DEFINE (scm_random_normal_vector_x, "random:normal-vector!", 1, 1, 0,
1bbd0b84 605 (SCM v, SCM state),
d928e0b4
GB
606 "Fills vect with inexact real random numbers that are\n"
607 "independent and standard normally distributed\n"
64ba8e85 608 "(i.e., with mean 0 and variance 1).")
1bbd0b84 609#define FUNC_NAME s_scm_random_normal_vector_x
e7a72986 610{
4057a3e0
MV
611 long i;
612 scm_t_array_handle handle;
613 scm_t_array_dim *dim;
46d25cff 614
e7a72986 615 if (SCM_UNBNDP (state))
86d31dfe 616 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 617 SCM_VALIDATE_RSTATE (2, state);
4057a3e0 618
c8857a4d 619 scm_generalized_vector_get_handle (v, &handle);
4057a3e0
MV
620 dim = scm_array_handle_dims (&handle);
621
622 if (scm_is_vector (v))
46d25cff 623 {
4057a3e0
MV
624 SCM *elts = scm_array_handle_writable_elements (&handle);
625 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
626 *elts = scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
46d25cff 627 }
e7a72986 628 else
46d25cff
MV
629 {
630 /* must be a f64vector. */
4057a3e0
MV
631 double *elts = scm_array_handle_f64_writable_elements (&handle);
632 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
633 *elts = scm_c_normal01 (SCM_RSTATE (state));
46d25cff 634 }
4057a3e0 635
c8857a4d
MV
636 scm_array_handle_release (&handle);
637
e7a72986
MD
638 return SCM_UNSPECIFIED;
639}
1bbd0b84 640#undef FUNC_NAME
e7a72986 641
a1ec6916 642SCM_DEFINE (scm_random_exp, "random:exp", 0, 1, 0,
1bbd0b84 643 (SCM state),
1e6808ea
MG
644 "Return an inexact real in an exponential distribution with mean\n"
645 "1. For an exponential distribution with mean u use (* u\n"
646 "(random:exp)).")
1bbd0b84 647#define FUNC_NAME s_scm_random_exp
e7a72986
MD
648{
649 if (SCM_UNBNDP (state))
86d31dfe 650 state = SCM_VARIABLE_REF (scm_var_random_state);
34d19ef6 651 SCM_VALIDATE_RSTATE (1, state);
d9a67fc4 652 return scm_from_double (scm_c_exp1 (SCM_RSTATE (state)));
e7a72986 653}
1bbd0b84 654#undef FUNC_NAME
e7a72986
MD
655
656void
657scm_init_random ()
658{
659 int i, m;
660 /* plug in default RNG */
92c2555f 661 scm_t_rng rng =
e7a72986 662 {
92c2555f 663 sizeof (scm_t_i_rstate),
99a0ee66
AW
664 scm_i_uniform32,
665 scm_i_init_rstate,
666 scm_i_copy_rstate,
667 scm_i_rstate_from_datum,
668 scm_i_rstate_to_datum
e7a72986
MD
669 };
670 scm_the_rng = rng;
671
e841c3e0 672 scm_tc16_rstate = scm_make_smob_type ("random-state", 0);
e7a72986
MD
673
674 for (m = 1; m <= 0x100; m <<= 1)
675 for (i = m >> 1; i < m; ++i)
676 scm_masktab[i] = m - 1;
677
a0599745 678#include "libguile/random.x"
e7a72986
MD
679
680 scm_add_feature ("random");
681}
89e00824
ML
682
683/*
684 Local Variables:
685 c-file-style: "gnu"
686 End:
687*/