root/trunk/random/generators.lisp

Revision 26, 10.0 kB (checked in by lhealy, 9 months ago)

Subversion version stamp.

  • Property svn:keywords set to Id
Line 
1;; Generators of random numbers.
2;; Liam Healy, Sat Jul 15 2006 - 14:43
3;; Time-stamp: <2008-02-17 12:15:46EST generators.lisp>
4;; $Id$
5
6(in-package :gsl)
7
8;;; Would it be useful to have a make-data like macro?
9
10(export '(make-random-number-generator))
11
12(defgeneric generator (object)
13  (:method ((object t))
14    (if (cffi:pointerp object)
15        object
16        (call-next-method)))
17  (:documentation "The foreign pointer to the GSL generator function."))
18
19(defclass gsl-random ()
20  ((type :initarg :type :reader rng-type)
21   (generator :initarg :generator :accessor generator)))
22
23(defclass random-number-generator (gsl-random)
24  ()
25  (:documentation "A generator of random numbers."))
26
27(defmethod print-object ((object gsl-random) stream)
28  (print-unreadable-object (object stream :type t :identity t)
29    (format stream "~a" (when (generator object) (rng-name object)))))
30
31(defun make-random-number-generator
32    (&optional (type *default-type*) (generator t))
33  "Make a random number generator; by default it is allocated on creation."
34  (let ((instance
35         (make-instance
36          'random-number-generator
37          :type type
38          :generator generator)))
39    (if (eq generator t) (alloc instance) instance)))
40
41(defgo-s (random-number-generator type value)
42         make-random-number-generator free rng-set 1)
43
44;;;;****************************************************************************
45;;;; Initialization
46;;;;****************************************************************************
47
48(defmfun alloc ((generator random-number-generator))
49  "gsl_rng_alloc" (((rng-type generator) :pointer))
50  :type :method
51  :c-return (ptr :pointer)
52  :return ((progn (setf (generator generator) ptr) generator))
53  :documentation                        ; FDL
54  "Instatiate a random number generator of specified type.
55   For example, create an instance of the Tausworthe
56   generator: (rng-alloc *taus*).
57   The generator is automatically initialized with the default seed,
58   *default-seed*.  This is zero by default but can be changed
59   either directly or by using the environment variable GSL_RNG_SEED.")
60
61(defmfun free ((generator random-number-generator))
62  "gsl_rng_free" (((generator generator) :pointer))
63  :type :method
64  :c-return :void
65  :after ((setf (generator generator) nil))
66  :documentation                        ; FDL
67  "Free all the memory associated with the generator.")
68
69;;;;****************************************************************************
70;;;; Seed
71;;;;****************************************************************************
72
73(cffi:defcvar ("gsl_rng_default_seed" *default-seed*) :ulong)
74(setf (documentation '*default-seed* 'variable)
75      "The default seed for random number generators.")
76(map-name '*default-seed* "gsl_rng_cmrg")
77(export '*default-seed*)
78
79(defmfun rng-set (rng-instance value)
80  "gsl_rng_set" (((generator rng-instance) :pointer) (value :ulong))
81  :c-return :void
82  :documentation                        ; FDL
83  "Initialize (or `seeds') the random number generator.  If
84   the generator is seeded with the same value of s on two different
85   runs, the same stream of random numbers will be generated by successive
86   calls to the routines below.  If different values of s are
87   supplied, then the generated streams of random numbers should be
88   completely different.  If the seed s is zero then the standard seed
89   from the original implementation is used instead.  For example, the
90   original Fortran source code for the *ranlux* generator used a seed
91   of 314159265, and so choosing s equal to zero reproduces this when
92   using *ranlux*.")
93
94;;;;****************************************************************************
95;;;; Sampling
96;;;;****************************************************************************
97
98(defmfun get-random-number (generator)
99  "gsl_rng_get" (((generator generator) :pointer))
100  :c-return :ulong
101  :documentation                        ; FDL
102  "Generate a random integer.  The
103   minimum and maximum values depend on the algorithm used, but all
104   integers in the range [min, max] are equally likely.  The
105   values of min and max can determined using the auxiliary
106   functions #'rng-max and #'rng-min.")
107
108(defmfun uniform (generator)
109  "gsl_rng_uniform" (((generator generator) :pointer))
110  :c-return :double
111  :documentation                        ; FDL
112  "A double precision floating point number uniformly
113   distributed in the range [0,1).  The range includes 0.0 but excludes 1.0.
114   The value is typically obtained by dividing the result of
115   #'rng-get by (+ (rng-max generator) 1.0) in double
116   precision.  Some generators compute this ratio internally so that they
117   can provide floating point numbers with more than 32 bits of randomness
118   (the maximum number of bits that can be portably represented in a single
119   :ulong.")
120
121(defmfun uniform>0 (generator)
122  "gsl_rng_uniform_pos" (((generator generator) :pointer))
123  :c-return :double
124  :documentation                        ; FDL
125  "Return a positive double precision floating point number
126   uniformly distributed in the range (0,1), excluding both 0.0 and 1.0.
127   The number is obtained by sampling the generator with the algorithm of
128   #'uniform until a non-zero value is obtained.  You can use
129   this function if you need to avoid a singularity at 0.0.")
130
131(defmfun uniform-fixnum (generator upperbound)
132  "gsl_rng_uniform_int" (((generator generator) :pointer) (upperbound :ulong))
133  :c-return :ulong
134  :documentation                        ; FDL
135  "Generate a random integer from 0 to upperbound-1 inclusive.
136   All integers in the range are equally likely, regardless
137   of the generator used.  An offset correction is applied so that zero is
138   always returned with the correct probability, for any minimum value of
139   the underlying generator.  If upperbound is larger than the range
140   of the generator then the function signals an error.")
141
142;;;;****************************************************************************
143;;;; Information functions about instances
144;;;;****************************************************************************
145
146(export 'rng-name)
147(defgeneric rng-name (rng-instance)
148  (:documentation                       ; FDL
149   "The name of the random number generator."))
150
151(defmfun rng-name ((rng-instance random-number-generator))
152  "gsl_rng_name" (((generator rng-instance) :pointer))
153  :type :method
154  :c-return :string)
155
156(defmfun rng-max (rng-instance)
157  "gsl_rng_max" (((generator rng-instance) :pointer))
158  :c-return :unsigned-long
159  :documentation "The largest value that #'get-random-number
160   can return.")
161
162(defmfun rng-min (rng-instance)
163  "gsl_rng_min" (((generator rng-instance) :pointer))
164  :c-return :unsigned-long
165  :documentation                        ; FDL
166  "The smallest value that #'get-random-number
167   can return.  Usually this value is zero.  There are some generators with
168   algorithms that cannot return zero, and for these generators the minimum
169   value is 1.")
170
171(export 'rng-state)
172(defgeneric rng-state (rng-instance)
173  (:documentation                       ; FDL
174   "A pointer to the state of generator."))
175
176(defmfun rng-state ((rng-instance random-number-generator))
177  "gsl_rng_state" (((generator rng-instance) :pointer))
178  :c-return :pointer
179  :type :method
180  :index gsl-random-state)
181
182(export 'rng-size)
183(defgeneric rng-size (rng-instance)
184  (:documentation                       ; FDL
185   "The size of the generator."))
186
187(defmfun rng-size ((rng-instance random-number-generator))
188  "gsl_rng_size" (((generator rng-instance) :pointer))
189  :c-return size
190  :type :method
191  :index gsl-random-state)
192
193(export 'gsl-random-state)
194(defun gsl-random-state (rng-instance)
195  "The complete state of a given random number generator, specified
196   as a vector of bytes."
197  (let* ((gen rng-instance)
198         (ans
199          (make-array (rng-size gen)
200                      :element-type '(unsigned-byte 8))))
201    (loop for i from 0 below (length ans)
202       do
203       (setf (aref ans i)
204             (mem-aref (rng-state gen) :uint8 i)))
205    ans))
206
207;;;;****************************************************************************
208;;;; Copying state
209;;;;****************************************************************************
210
211(defmfun copy
212    ((destination random-number-generator) (source random-number-generator))
213  "gsl_rng_memcpy"
214  (((generator destination) :pointer) ((generator source) :pointer))
215  :type :method
216  :documentation                        ; FDL
217  "Copy the random number generator source into the
218   pre-existing generator destination,
219   making destination into an exact copy
220   of source.  The two generators must be of the same type.")
221
222(export 'clone-generator)
223(defgeneric clone-generator (instance)
224  (:documentation                       ; FDL
225   "Create a new generator which is an exact copy of the original.
226   Don't use; use #'make-random-number-generator, #'copy instead."))
227
228(defmfun clone-generator ((instance random-number-generator))
229  "gsl_rng_clone" (((generator instance) :pointer))
230  :c-return :pointer
231  :type :method)
232
233(defmfun write-binary
234    ((object random-number-generator) stream)
235  "gsl_rng_fwrite"
236  ((stream :pointer) ((generator object) :pointer))
237  :type :method)
238
239(defmfun read-binary
240    ((object random-number-generator) stream)
241  "gsl_block_fread"
242  ((stream :pointer) ((pointer object) :pointer))
243  :type :method)
244
245;;;;****************************************************************************
246;;;; Examples and unit test
247;;;;****************************************************************************
248
249#|
250(make-tests random-number-generators
251 (letm ((rng (random-number-generator *mt19937* 0)))
252   (loop for i from 0 to 10
253         collect
254         (uniform-fixnum rng 1000)))
255 (letm ((rng (random-number-generator *cmrg* 0)))
256   (loop for i from 0 to 10 collect (uniform rng))))
257|#
258
259(LISP-UNIT:DEFINE-TEST RANDOM-NUMBER-GENERATORS
260  (LISP-UNIT::ASSERT-NUMERICAL-EQUAL
261   (LIST
262    (LIST 999 162 282 947 231 484 957 744 540 739 759))
263   (MULTIPLE-VALUE-LIST
264    (LETM ((RNG (RANDOM-NUMBER-GENERATOR *MT19937* 0)))
265      (LOOP FOR I FROM 0 TO 10 COLLECT
266            (UNIFORM-FIXNUM RNG 1000)))))
267  (LISP-UNIT::ASSERT-NUMERICAL-EQUAL
268   (LIST
269    (LIST 0.11177622997750353d0 0.9591667949963206d0
270          0.8415268011584537d0 0.9254037136795947d0
271          0.27540698474059205d0 0.7093040573919677d0
272          0.5541333041871588d0 0.8806957769583426d0
273          0.597139396982798d0 0.7518741133398722d0
274          0.9311084621265104d0))
275   (MULTIPLE-VALUE-LIST
276    (LETM ((RNG (RANDOM-NUMBER-GENERATOR *CMRG* 0)))
277      (LOOP FOR I FROM 0 TO 10 COLLECT
278            (UNIFORM RNG))))))
Note: See TracBrowser for help on using the browser.