| 1 | ;; Quasi-random sequences in arbitrary dimensions. |
|---|
| 2 | ;; Liam Healy, Sun Jul 16 2006 - 15:54 |
|---|
| 3 | ;; Time-stamp: <2008-03-09 19:29:16EDT quasi.lisp> |
|---|
| 4 | ;; $Id$ |
|---|
| 5 | |
|---|
| 6 | (in-package :gsl) |
|---|
| 7 | |
|---|
| 8 | (defclass quasi-random-number-generator (gsl-random) |
|---|
| 9 | ((dimension :initarg :dimension :accessor qr-dimension)) |
|---|
| 10 | (:documentation "A generator of quasi-random numbers.")) |
|---|
| 11 | |
|---|
| 12 | (defparameter *default-quasi-random-number-generator* nil) |
|---|
| 13 | |
|---|
| 14 | (defgo-s (quasi-random-number-generator dimension type) |
|---|
| 15 | make-quasi-random-number-generator free nil 2) |
|---|
| 16 | |
|---|
| 17 | (defun make-quasi-random-number-generator |
|---|
| 18 | (dimension |
|---|
| 19 | &optional (type *default-quasi-random-number-generator*) |
|---|
| 20 | (generator t)) |
|---|
| 21 | "Make a random number generator; by default it is allocated on creation." |
|---|
| 22 | (let ((instance |
|---|
| 23 | (make-instance |
|---|
| 24 | 'quasi-random-number-generator |
|---|
| 25 | :type type |
|---|
| 26 | :dimension dimension |
|---|
| 27 | :generator generator))) |
|---|
| 28 | (if (eq generator t) (alloc instance) instance))) |
|---|
| 29 | |
|---|
| 30 | (defmfun alloc ((generator quasi-random-number-generator)) |
|---|
| 31 | "gsl_qrng_alloc" |
|---|
| 32 | (((rng-type generator) :pointer) ((qr-dimension generator) :uint)) |
|---|
| 33 | :type :method |
|---|
| 34 | :c-return (ptr :pointer) |
|---|
| 35 | :return ((progn (setf (generator generator) ptr) generator)) |
|---|
| 36 | :documentation ; FDL |
|---|
| 37 | "Instatiate a random number generator of specified type. |
|---|
| 38 | For example, create an instance of the Tausworthe |
|---|
| 39 | generator: (rng-alloc *taus*). |
|---|
| 40 | The generator is automatically initialized with the default seed, |
|---|
| 41 | *default-seed*. This is zero by default but can be changed |
|---|
| 42 | either directly or by using the environment variable GSL_RNG_SEED.") |
|---|
| 43 | |
|---|
| 44 | (defmfun free ((generator quasi-random-number-generator)) |
|---|
| 45 | "gsl_qrng_free" (((generator generator) :pointer)) |
|---|
| 46 | :type :method |
|---|
| 47 | :c-return :void |
|---|
| 48 | :after ((setf (generator generator) nil)) |
|---|
| 49 | :documentation ; FDL |
|---|
| 50 | "Free all the memory associated with the generator.") |
|---|
| 51 | |
|---|
| 52 | (defmfun init (generator) |
|---|
| 53 | "gsl_qrng_init" (((generator generator) :pointer)) |
|---|
| 54 | :c-return :void |
|---|
| 55 | :documentation ; FDL |
|---|
| 56 | "Reinitializes the generator q to its starting point. |
|---|
| 57 | Note that quasi-random sequences do not use a seed and always produce |
|---|
| 58 | the same set of values.") |
|---|
| 59 | |
|---|
| 60 | (defmfun qrng-get (generator return-vector) |
|---|
| 61 | "gsl_qrng_get" |
|---|
| 62 | (((generator generator) :pointer) ((gsl-array return-vector) :pointer)) |
|---|
| 63 | :documentation ; FDL |
|---|
| 64 | "Store the next point from the sequence generator q |
|---|
| 65 | in the array x. The space available for x must match the |
|---|
| 66 | dimension of the generator. The point x will lie in the range |
|---|
| 67 | 0 < x_i < 1 for each x_i." |
|---|
| 68 | :invalidate (return-vector)) |
|---|
| 69 | |
|---|
| 70 | (defmfun rng-name ((instance quasi-random-number-generator)) |
|---|
| 71 | "gsl_qrng_name" (((generator instance) :pointer)) |
|---|
| 72 | :type :method |
|---|
| 73 | :c-return :string) |
|---|
| 74 | |
|---|
| 75 | (defmfun rng-state ((instance quasi-random-number-generator)) |
|---|
| 76 | "gsl_qrng_state" (((generator instance) :pointer)) |
|---|
| 77 | :c-return :pointer |
|---|
| 78 | :type :method |
|---|
| 79 | :export nil |
|---|
| 80 | :index gsl-random-state) |
|---|
| 81 | |
|---|
| 82 | (defmfun rng-size ((instance quasi-random-number-generator)) |
|---|
| 83 | "gsl_qrng_size" (((generator instance) :pointer)) |
|---|
| 84 | :c-return size |
|---|
| 85 | :type :method |
|---|
| 86 | :export nil |
|---|
| 87 | :index gsl-random-state) |
|---|
| 88 | |
|---|
| 89 | (defmfun copy |
|---|
| 90 | ((destination quasi-random-number-generator) |
|---|
| 91 | (source quasi-random-number-generator)) |
|---|
| 92 | "gsl_qrng_memcpy" |
|---|
| 93 | (((generator destination) :pointer) ((generator source) :pointer)) |
|---|
| 94 | :type :method |
|---|
| 95 | :documentation ; FDL |
|---|
| 96 | "Copy the quasi-random sequence generator src into the |
|---|
| 97 | pre-existing generator dest, making dest into an exact copy |
|---|
| 98 | of src. The two generators must be of the same type.") |
|---|
| 99 | |
|---|
| 100 | (defmfun clone-generator ((instance quasi-random-number-generator)) |
|---|
| 101 | "gsl_qrng_clone" (((generator instance) :pointer)) |
|---|
| 102 | :c-return :pointer |
|---|
| 103 | :type :method |
|---|
| 104 | :documentation ; FDL |
|---|
| 105 | "Create a new generator which is an exact copy of the original. |
|---|
| 106 | Don't use; use #'make-random-number-generator, #'copy instead.") |
|---|
| 107 | |
|---|
| 108 | (def-rng-type *niederreiter2* |
|---|
| 109 | ;; FDL |
|---|
| 110 | "Described in Bratley, Fox, Niederreiter, |
|---|
| 111 | ACM Trans. Model. Comp. Sim. 2, 195 (1992). It is |
|---|
| 112 | valid up to 12 dimensions." |
|---|
| 113 | "gsl_qrng_niederreiter_2") |
|---|
| 114 | |
|---|
| 115 | (eval-when (:load-toplevel :execute) |
|---|
| 116 | (setf *default-quasi-random-number-generator* |
|---|
| 117 | (make-quasi-random-number-generator 2 *niederreiter2*))) |
|---|
| 118 | |
|---|
| 119 | (def-rng-type *sobol* |
|---|
| 120 | ;; FDL |
|---|
| 121 | "This generator uses the Sobol sequence described in Antonov, Saleev, |
|---|
| 122 | USSR Comput. Maths. Math. Phys. 19, 252 (1980). It is valid up to |
|---|
| 123 | 40 dimensions." |
|---|
| 124 | "gsl_qrng_sobol") |
|---|
| 125 | |
|---|
| 126 | ;;; Examples and unit test |
|---|
| 127 | #| |
|---|
| 128 | (make-tests quasi-random-number-generators |
|---|
| 129 | ;; This example is given in the GSL documentation |
|---|
| 130 | (letm ((gen (quasi-random-number-generator 2 *sobol*)) |
|---|
| 131 | (vec (vector-double-float 2))) |
|---|
| 132 | (loop repeat 5 |
|---|
| 133 | do (qrng-get gen vec) |
|---|
| 134 | append (coerce (data vec) 'list)))) |
|---|
| 135 | |# |
|---|
| 136 | |
|---|
| 137 | (LISP-UNIT:DEFINE-TEST QUASI-RANDOM-NUMBER-GENERATORS |
|---|
| 138 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 139 | (LIST |
|---|
| 140 | (LIST 0.5d0 0.5d0 0.75d0 0.25d0 0.25d0 0.75d0 0.375d0 |
|---|
| 141 | 0.375d0 0.875d0 0.875d0)) |
|---|
| 142 | (MULTIPLE-VALUE-LIST |
|---|
| 143 | (LETM |
|---|
| 144 | ((GEN (QUASI-RANDOM-NUMBER-GENERATOR 2 *SOBOL*)) |
|---|
| 145 | (VEC (VECTOR-DOUBLE-FLOAT 2))) |
|---|
| 146 | (LOOP REPEAT 5 DO (QRNG-GET GEN VEC) APPEND |
|---|
| 147 | (COERCE (DATA VEC) 'LIST)))))) |
|---|
| 148 | |
|---|