| 1 | ;; Monte Carlo Integration |
|---|
| 2 | ;; Liam Healy Sat Feb 3 2007 - 17:42 |
|---|
| 3 | ;; Time-stamp: <2008-03-09 19:29:43EDT monte-carlo.lisp> |
|---|
| 4 | ;; $Id$ |
|---|
| 5 | |
|---|
| 6 | (in-package :gsl) |
|---|
| 7 | |
|---|
| 8 | ;;;;**************************************************************************** |
|---|
| 9 | ;;;; PLAIN Monte Carlo |
|---|
| 10 | ;;;;**************************************************************************** |
|---|
| 11 | |
|---|
| 12 | (cffi:defcstruct plain-state |
|---|
| 13 | (dim size) |
|---|
| 14 | (x :pointer)) |
|---|
| 15 | |
|---|
| 16 | (defgo-s (monte-carlo-plain dim) monte-carlo-plain-alloc monte-carlo-plain-free) |
|---|
| 17 | |
|---|
| 18 | (defmfun monte-carlo-plain-alloc (dim) |
|---|
| 19 | "gsl_monte_plain_alloc" |
|---|
| 20 | ((dim size)) |
|---|
| 21 | :c-return :pointer |
|---|
| 22 | :export nil |
|---|
| 23 | :index (letm monte-carlo-plain) |
|---|
| 24 | :documentation ; FDL |
|---|
| 25 | "Allocate and initialize a workspace for Monte Carlo |
|---|
| 26 | integration in dim dimensions.") |
|---|
| 27 | |
|---|
| 28 | (defmfun monte-carlo-plain-init (integrator-state) |
|---|
| 29 | "gsl_monte_plain_init" |
|---|
| 30 | ((integrator-state :pointer)) |
|---|
| 31 | :documentation ; FDL |
|---|
| 32 | "Initialize a previously allocated integration state. |
|---|
| 33 | This allows an existing workspace to be reused for different |
|---|
| 34 | integrations.") |
|---|
| 35 | |
|---|
| 36 | (defmfun monte-carlo-plain-free (integrator-state) |
|---|
| 37 | "gsl_monte_plain_free" |
|---|
| 38 | ((integrator-state :pointer)) |
|---|
| 39 | :c-return :void |
|---|
| 40 | :export nil |
|---|
| 41 | :index (letm monte-carlo-plain) |
|---|
| 42 | :documentation ; FDL |
|---|
| 43 | "Frees the memory associated with the integrator.") |
|---|
| 44 | |
|---|
| 45 | (defmfun monte-carlo-integrate-plain |
|---|
| 46 | (function lower-limits upper-limits calls generator state) |
|---|
| 47 | "gsl_monte_plain_integrate" |
|---|
| 48 | ((function :pointer) |
|---|
| 49 | ((gsl-array lower-limits) :pointer) ((gsl-array upper-limits) :pointer) |
|---|
| 50 | ((dim0 lower-limits) size) (calls size) |
|---|
| 51 | ((generator generator) :pointer) |
|---|
| 52 | (state :pointer) |
|---|
| 53 | (result :double) (abserr :double)) |
|---|
| 54 | :documentation ; FDL |
|---|
| 55 | "Uses the plain Monte Carlo algorithm to integrate the |
|---|
| 56 | function f over the hypercubic region defined by the |
|---|
| 57 | lower and upper limits in the arrays 'lower-limits and |
|---|
| 58 | 'upper-limits, each a gsl-vector of length dim. |
|---|
| 59 | The integration uses a fixed number |
|---|
| 60 | of function calls calls, and obtains random sampling points using |
|---|
| 61 | the random number generator 'generator. A previously allocated workspace |
|---|
| 62 | 'state must be supplied. The result of the integration is returned |
|---|
| 63 | with an estimated absolute error.") |
|---|
| 64 | |
|---|
| 65 | ;;;;**************************************************************************** |
|---|
| 66 | ;;;; MISER |
|---|
| 67 | ;;;;**************************************************************************** |
|---|
| 68 | |
|---|
| 69 | ;;; The MISER algorithm of Press and Farrar is based on recursive |
|---|
| 70 | ;;; stratified sampling. This technique aims to reduce the overall |
|---|
| 71 | ;;; integration error by concentrating integration points in the |
|---|
| 72 | ;;; regions of highest variance. |
|---|
| 73 | |
|---|
| 74 | (cffi:defcstruct miser-state |
|---|
| 75 | (min-calls size) |
|---|
| 76 | (min-calls-per-bisection size) |
|---|
| 77 | (dither :double) |
|---|
| 78 | (estimate-frac :double) |
|---|
| 79 | (alpha :double) |
|---|
| 80 | (dim size) |
|---|
| 81 | (estimate-style :int) |
|---|
| 82 | (depth :int) |
|---|
| 83 | (verbose :int) |
|---|
| 84 | (x :pointer) |
|---|
| 85 | (xmid :pointer) |
|---|
| 86 | (sigma-l :pointer) |
|---|
| 87 | (sigma-r :pointer) |
|---|
| 88 | (fmax-l :pointer) |
|---|
| 89 | (fmax-r :pointer) |
|---|
| 90 | (fmin-l :pointer) |
|---|
| 91 | (fmin-r :pointer) |
|---|
| 92 | (fsum-l :pointer) |
|---|
| 93 | (fsum-r :pointer) |
|---|
| 94 | (fsum2-l :pointer) |
|---|
| 95 | (fsum2-r :pointer) |
|---|
| 96 | (hits-l :pointer) |
|---|
| 97 | (hits-r :pointer)) |
|---|
| 98 | |
|---|
| 99 | (defgo-s (monte-carlo-miser dim) monte-carlo-miser-alloc monte-carlo-miser-free) |
|---|
| 100 | |
|---|
| 101 | (defmfun monte-carlo-miser-alloc (dim) |
|---|
| 102 | "gsl_monte_miser_alloc" |
|---|
| 103 | ((dim size)) |
|---|
| 104 | :c-return :pointer |
|---|
| 105 | :export nil |
|---|
| 106 | :index (letm monte-carlo-miser) |
|---|
| 107 | :documentation ; FDL |
|---|
| 108 | "Allocate and initialize a workspace for Monte Carlo integration in |
|---|
| 109 | dim dimensions. The workspace is used to maintain |
|---|
| 110 | the state of the integration. Returns a pointer to miser-state.") |
|---|
| 111 | |
|---|
| 112 | (defmfun monte-carlo-miser-init (integrator-state) |
|---|
| 113 | "gsl_monte_miser_init" |
|---|
| 114 | ((integrator-state :pointer)) |
|---|
| 115 | :documentation ; FDL |
|---|
| 116 | "Initialize a previously allocated integration state. |
|---|
| 117 | This allows an existing workspace to be reused for different |
|---|
| 118 | integrations.") |
|---|
| 119 | |
|---|
| 120 | (defmfun monte-carlo-miser-free (integrator-state) |
|---|
| 121 | "gsl_monte_miser_free" |
|---|
| 122 | ((integrator-state :pointer)) |
|---|
| 123 | :c-return :void |
|---|
| 124 | :export nil |
|---|
| 125 | :index (letm monte-carlo-miser) |
|---|
| 126 | :documentation ; FDL |
|---|
| 127 | "Frees the memory associated with the integrator.") |
|---|
| 128 | |
|---|
| 129 | (export 'miser-parameter) |
|---|
| 130 | (defmacro miser-parameter (workspace parameter) |
|---|
| 131 | ;; FDL |
|---|
| 132 | "Get or set with setf the parameter value for the MISER Monte Carlo |
|---|
| 133 | integration method." |
|---|
| 134 | ;; (miser-parameter ws min-calls) |
|---|
| 135 | ;; (setf (miser-parameter ws min-calls) 300) |
|---|
| 136 | `(foreign-slot-value ,workspace 'miser-state ',parameter)) |
|---|
| 137 | |
|---|
| 138 | (defmfun monte-carlo-integrate-miser |
|---|
| 139 | (function lower-limits upper-limits calls generator state) |
|---|
| 140 | "gsl_monte_miser_integrate" |
|---|
| 141 | ((function :pointer) |
|---|
| 142 | ((gsl-array lower-limits) :pointer) ((gsl-array upper-limits) :pointer) |
|---|
| 143 | ((dim0 lower-limits) size) (calls size) |
|---|
| 144 | ((generator generator) :pointer) |
|---|
| 145 | (state :pointer) |
|---|
| 146 | (result :double) (abserr :double)) |
|---|
| 147 | :documentation ; FDL |
|---|
| 148 | "Uses the miser Monte Carlo algorithm to integrate the |
|---|
| 149 | function f over the hypercubic region defined by the |
|---|
| 150 | lower and upper limits in the arrays 'lower-limits and |
|---|
| 151 | 'upper-limits, each a gsl-vector of the samelength |
|---|
| 152 | The integration uses a fixed number |
|---|
| 153 | of function calls calls, and obtains random sampling points using |
|---|
| 154 | the random number generator 'generator. A previously allocated workspace |
|---|
| 155 | 'state must be supplied. The result of the integration is returned |
|---|
| 156 | with an estimated absolute error.") |
|---|
| 157 | |
|---|
| 158 | ;;;;**************************************************************************** |
|---|
| 159 | ;;;; VEGAS |
|---|
| 160 | ;;;;**************************************************************************** |
|---|
| 161 | |
|---|
| 162 | ;;; The vegas algorithm of Lepage is based on importance sampling. It |
|---|
| 163 | ;;; samples points from the probability distribution described by the |
|---|
| 164 | ;;; function |f|, so that the points are concentrated in the regions |
|---|
| 165 | ;;; that make the largest contribution to the integral. |
|---|
| 166 | |
|---|
| 167 | (cffi:defcstruct vegas-state |
|---|
| 168 | ;; grid |
|---|
| 169 | (dim size) |
|---|
| 170 | (bins-max size) |
|---|
| 171 | (bins :uint) ; uint |
|---|
| 172 | (boxes :uint) ; these are both counted along the axes |
|---|
| 173 | (xi :pointer) |
|---|
| 174 | (xin :pointer) |
|---|
| 175 | (delx :pointer) |
|---|
| 176 | (weight :pointer) |
|---|
| 177 | (vol :double) |
|---|
| 178 | (x :pointer) |
|---|
| 179 | (bin :pointer) |
|---|
| 180 | (box :pointer) |
|---|
| 181 | (d :pointer) ; distribution |
|---|
| 182 | ;; control variables |
|---|
| 183 | (alpha :double) |
|---|
| 184 | (mode :int) |
|---|
| 185 | (verbose :int) |
|---|
| 186 | (iterations :uint) |
|---|
| 187 | (stage :int) |
|---|
| 188 | ;; scratch variables preserved between calls to vegas1/2/3 |
|---|
| 189 | (jac :double) |
|---|
| 190 | (wtd-int-sum :double) |
|---|
| 191 | (sum-wgts :double) |
|---|
| 192 | (chi-sum :double) |
|---|
| 193 | (chisq :double) |
|---|
| 194 | (result :double) |
|---|
| 195 | (sigma :double) |
|---|
| 196 | (it-start :uint) |
|---|
| 197 | (it-num :uint) |
|---|
| 198 | (samples :uint) |
|---|
| 199 | (calls-per-box :uint) |
|---|
| 200 | (ostream :pointer)) |
|---|
| 201 | |
|---|
| 202 | (defgo-s (monte-carlo-vegas dim) monte-carlo-vegas-alloc monte-carlo-vegas-free) |
|---|
| 203 | |
|---|
| 204 | (defmfun monte-carlo-vegas-alloc (dim) |
|---|
| 205 | "gsl_monte_vegas_alloc" |
|---|
| 206 | ((dim size)) |
|---|
| 207 | :c-return :pointer |
|---|
| 208 | :export nil |
|---|
| 209 | :index (letm monte-carlo-vegas) |
|---|
| 210 | :documentation ; FDL |
|---|
| 211 | "Allocate and initialize a workspace for Monte Carlo integration in |
|---|
| 212 | dim dimensions. The workspace is used to maintain |
|---|
| 213 | the state of the integration. Returns a pointer to vegas-state.") |
|---|
| 214 | |
|---|
| 215 | (defmfun monte-carlo-vegas-init (integrator-state) |
|---|
| 216 | "gsl_monte_vegas_init" |
|---|
| 217 | ((integrator-state :pointer)) |
|---|
| 218 | :documentation ; FDL |
|---|
| 219 | "Initialize a previously allocated integration state. |
|---|
| 220 | This allows an existing workspace to be reused for different |
|---|
| 221 | integrations.") |
|---|
| 222 | |
|---|
| 223 | (defmfun monte-carlo-vegas-free (integrator-state) |
|---|
| 224 | "gsl_monte_vegas_free" |
|---|
| 225 | ((integrator-state :pointer)) |
|---|
| 226 | :c-return :void |
|---|
| 227 | :export nil |
|---|
| 228 | :index (letm monte-carlo-vegas) |
|---|
| 229 | :documentation ; FDL |
|---|
| 230 | "Frees the memory associated with the integrator.") |
|---|
| 231 | |
|---|
| 232 | (export 'vegas-parameter) |
|---|
| 233 | (defmacro vegas-parameter (workspace parameter) |
|---|
| 234 | ;; FDL |
|---|
| 235 | "Get or set with setf the parameter value for the VEGAS Monte Carlo |
|---|
| 236 | integration method." |
|---|
| 237 | ;; (vegas-parameter ws bins-max) |
|---|
| 238 | ;; (setf (vegas-parameter ws bins-max) 300) |
|---|
| 239 | `(foreign-slot-value ,workspace 'vegas-state ',parameter)) |
|---|
| 240 | |
|---|
| 241 | (defmfun monte-carlo-integrate-vegas |
|---|
| 242 | (function lower-limits upper-limits calls generator state) |
|---|
| 243 | "gsl_monte_vegas_integrate" |
|---|
| 244 | ((function :pointer) |
|---|
| 245 | ((gsl-array lower-limits) :pointer) ((gsl-array upper-limits) :pointer) |
|---|
| 246 | ((dim0 lower-limits) size) (calls size) |
|---|
| 247 | ((generator generator) :pointer) |
|---|
| 248 | (state :pointer) |
|---|
| 249 | (result :double) (abserr :double)) |
|---|
| 250 | :documentation ; FDL |
|---|
| 251 | "Uses the vegas Monte Carlo algorithm to integrate the |
|---|
| 252 | function f over the dim-dimensional hypercubic region |
|---|
| 253 | defined by the lower and upper limits in the arrays x1 and |
|---|
| 254 | xu, each of size dim. The integration uses a fixed number |
|---|
| 255 | of function calls calls, and obtains random sampling points using |
|---|
| 256 | the random number generator r. A previously allocated workspace |
|---|
| 257 | s must be supplied. The result of the integration is returned |
|---|
| 258 | with an estimated absolute error. The result |
|---|
| 259 | and its error estimate are based on a weighted average of independent |
|---|
| 260 | samples. The chi-squared per degree of freedom for the weighted average |
|---|
| 261 | is returned via the state struct component, s->chisq, and must be |
|---|
| 262 | consistent with 1 for the weighted average to be reliable.") |
|---|
| 263 | |
|---|
| 264 | ;;;;**************************************************************************** |
|---|
| 265 | ;;;; Callback definition |
|---|
| 266 | ;;;;**************************************************************************** |
|---|
| 267 | |
|---|
| 268 | (cffi:defcstruct monte-function |
|---|
| 269 | (function :pointer) |
|---|
| 270 | (dimensions size) |
|---|
| 271 | (parameters :pointer)) |
|---|
| 272 | |
|---|
| 273 | (export 'def-mc-function) |
|---|
| 274 | (defmacro def-mc-function (name dimensions) |
|---|
| 275 | `(def-single-function ,name :double :pointer monte-function |
|---|
| 276 | ((dimensions ,dimensions)))) |
|---|
| 277 | |
|---|
| 278 | ;;;;**************************************************************************** |
|---|
| 279 | ;;;; Examples and unit test |
|---|
| 280 | ;;;;**************************************************************************** |
|---|
| 281 | |
|---|
| 282 | ;;; Example from Sec. 23.5 |
|---|
| 283 | ;;; This is a function that occurs in random walk studies. |
|---|
| 284 | |
|---|
| 285 | (defun monte-carlo-g (arg) |
|---|
| 286 | (with-c-double (arg x y z) |
|---|
| 287 | (* (/ (expt pi 3)) |
|---|
| 288 | (/ (- 1 (* (cos x) (cos y) (cos z))))))) |
|---|
| 289 | |
|---|
| 290 | (def-mc-function monte-carlo-g 3) |
|---|
| 291 | |
|---|
| 292 | (defun random-walk-plain-example (&optional (nsamples 500000)) |
|---|
| 293 | (letm ((ws (monte-carlo-plain 3)) |
|---|
| 294 | (lower (vector-double-float #(0.0d0 0.0d0 0.0d0))) |
|---|
| 295 | (upper (vector-double-float (vector pi pi pi))) |
|---|
| 296 | (rng (random-number-generator *mt19937* 0))) |
|---|
| 297 | (monte-carlo-integrate-plain monte-carlo-g lower upper nsamples rng ws))) |
|---|
| 298 | |
|---|
| 299 | (defun random-walk-miser-example (&optional (nsamples 500000)) |
|---|
| 300 | (letm ((ws (monte-carlo-miser 3)) |
|---|
| 301 | (lower (vector-double-float #(0.0d0 0.0d0 0.0d0))) |
|---|
| 302 | (upper (vector-double-float (vector pi pi pi))) |
|---|
| 303 | (rng (random-number-generator *mt19937* 0))) |
|---|
| 304 | (monte-carlo-integrate-miser monte-carlo-g lower upper nsamples rng ws))) |
|---|
| 305 | |
|---|
| 306 | (defun random-walk-vegas-example (&optional (nsamples 500000)) |
|---|
| 307 | (letm ((ws (monte-carlo-vegas 3)) |
|---|
| 308 | (lower (vector-double-float #(0.0d0 0.0d0 0.0d0))) |
|---|
| 309 | (upper (vector-double-float (vector pi pi pi))) |
|---|
| 310 | (rng (random-number-generator *mt19937* 0))) |
|---|
| 311 | (monte-carlo-integrate-vegas monte-carlo-g lower upper nsamples rng ws))) |
|---|
| 312 | |
|---|
| 313 | #| |
|---|
| 314 | (make-tests monte-carlo |
|---|
| 315 | (random-walk-plain-example) |
|---|
| 316 | (random-walk-miser-example) |
|---|
| 317 | (random-walk-vegas-example)) |
|---|
| 318 | |# |
|---|
| 319 | |
|---|
| 320 | (LISP-UNIT:DEFINE-TEST MONTE-CARLO |
|---|
| 321 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 322 | (LIST 1.4122087033540667d0 0.013435861456267064d0) |
|---|
| 323 | (MULTIPLE-VALUE-LIST (RANDOM-WALK-PLAIN-EXAMPLE))) |
|---|
| 324 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 325 | (LIST 1.3895297058825096d0 0.0050106269732269415d0) |
|---|
| 326 | (MULTIPLE-VALUE-LIST (RANDOM-WALK-MISER-EXAMPLE))) |
|---|
| 327 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 328 | (LIST 1.3931632739551914d0 1.4981164744582692d-4) |
|---|
| 329 | (MULTIPLE-VALUE-LIST (RANDOM-WALK-VEGAS-EXAMPLE)))) |
|---|
| 330 | |
|---|