Mercurial > lasercutter
view src/clojure/contrib/probabilities/monte_carlo.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 ;; Monte-Carlo algorithms3 ;; by Konrad Hinsen4 ;; last updated May 3, 20096 ;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use7 ;; and distribution terms for this software are covered by the Eclipse8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)9 ;; which can be found in the file epl-v10.html at the root of this10 ;; distribution. By using this software in any fashion, you are11 ;; agreeing to be bound by the terms of this license. You must not12 ;; remove this notice, or any other, from this software.14 (ns15 ^{:author "Konrad Hinsen"16 :doc "Monte-Carlo method support18 Monte-Carlo methods transform an input random number stream19 (usually having a continuous uniform distribution in the20 interval [0, 1)) into a random number stream whose distribution21 satisfies certain conditions (usually the expectation value22 is equal to some desired quantity). They are thus23 transformations from one probability distribution to another one.25 This library represents a Monte-Carlo method by a function that26 takes as input the state of a random number stream with27 uniform distribution (see28 clojure.contrib.probabilities.random-numbers) and returns a29 vector containing one sample value of the desired output30 distribution and the final state of the input random number31 stream. Such functions are state monad values and can be32 composed using operations defined in clojure.contrib.monads."}33 clojure.contrib.probabilities.monte-carlo34 (:refer-clojure :exclude (deftype))35 (:use [clojure.contrib.macros :only (const)])36 (:use [clojure.contrib.types :only (deftype)])37 (:use [clojure.contrib.stream-utils :only (defstream stream-next)])38 (:use [clojure.contrib.monads39 :only (with-monad state-m m-lift m-seq m-fmap)])40 (:require [clojure.contrib.generic.arithmetic :as ga])41 (:require [clojure.contrib.accumulators :as acc]))43 ;; Random number transformers and random streams44 ;;45 ;; A random number transformer is a function that takes a random stream46 ;; state as input and returns the next value from the transformed stream47 ;; plus the new state of the input stream. Random number transformers48 ;; are thus state monad values.49 ;;50 ;; Distributions are implemented as random number transformers that51 ;; transform a uniform distribution in the interval [0, 1) to the52 ;; desired distribution. Composition of such distributions allows53 ;; the realization of any kind of Monte-Carlo algorithm. The result54 ;; of such a composition is always again a distribution.55 ;;56 ;; Random streams are defined by a random number transformer and an57 ;; input random number stream. If the randon number transformer represents58 ;; a distribution, the input stream must have a uniform distribution59 ;; in the interval [0, 1).61 ; Random stream definition62 (deftype ::random-stream random-stream63 "Define a random stream by a distribution and the state of a64 random number stream with uniform distribution in [0, 1)."65 {:arglists '([distribution random-stream-state])}66 (fn [d rs] (list d rs)))68 (defstream ::random-stream69 [[d rs]]70 (let [[r nrs] (d rs)]71 [r (random-stream d nrs)]))73 ; Rejection of values is used in the construction of distributions74 (defn reject75 "Return the distribution that results from rejecting the values from76 dist that do not satisfy predicate p."77 [p dist]78 (fn [rs]79 (let [[r nrs] (dist rs)]80 (if (p r)81 (recur nrs)82 [r nrs]))))84 ; Draw a value from a discrete distribution given as a map from85 ; values to probabilities.86 ; (see clojure.contrib.probabilities.finite-distributions)87 (with-monad state-m88 (defn discrete89 "A discrete distribution, defined by a map dist mapping values90 to probabilities. The sum of probabilities must be one."91 [dist]92 (letfn [(pick-at-level [l dist-items]93 (let [[[x p] & rest-dist] dist-items]94 (if (> p l)95 x96 (recur (- l p) rest-dist))))]97 (m-fmap #(pick-at-level % (seq dist)) stream-next))))99 ; Uniform distribution in an finite half-open interval100 (with-monad state-m101 (defn interval102 [a b]103 "Transform a sequence of uniform random numbers in the interval [0, 1)104 into a sequence of uniform random numbers in the interval [a, b)."105 (let [d (- b a)106 f (if (zero? a)107 (if (= d 1)108 identity109 (fn [r] (* d r)))110 (if (= d 1)111 (fn [r] (+ a r))112 (fn [r] (+ a (* d r)))))]113 (m-fmap f stream-next))))115 ; Normal (Gaussian) distribution116 (defn normal117 "Transform a sequence urs of uniform random number in the interval [0, 1)118 into a sequence of normal random numbers with mean mu and standard119 deviation sigma."120 [mu sigma]121 ; This function implements the Kinderman-Monahan ratio method:122 ; A.J. Kinderman & J.F. Monahan123 ; Computer Generation of Random Variables Using the Ratio of Uniform Deviates124 ; ACM Transactions on Mathematical Software 3(3) 257-260, 1977125 (fn [rs]126 (let [[u1 rs] (stream-next rs)127 [u2* rs] (stream-next rs)128 u2 (- 1. u2*)129 s (const (* 4 (/ (. Math exp (- 0.5)) (. Math sqrt 2.))))130 z (* s (/ (- u1 0.5) u2))131 zz (+ (* 0.25 z z) (. Math log u2))]132 (if (> zz 0)133 (recur rs)134 [(+ mu (* sigma z)) rs]))))136 ; Lognormal distribution137 (with-monad state-m138 (defn lognormal139 "Transform a sequence of uniform random numbesr in the interval [0, 1)140 into a sequence of lognormal random numbers with mean mu and standard141 deviation sigma."142 [mu sigma]143 (m-fmap #(. Math exp %) (normal mu sigma))))145 ; Exponential distribution146 (with-monad state-m147 (defn exponential148 "Transform a sequence of uniform random numbers in the interval [0, 1)149 into a sequence of exponential random numbers with parameter lambda."150 [lambda]151 (when (<= lambda 0)152 (throw (IllegalArgumentException.153 "exponential distribution requires a positive argument")))154 (let [neg-inv-lambda (- (/ lambda))155 ; remove very small numbers to prevent log from returning -Infinity156 not-too-small (reject #(< % 1e-323) stream-next)]157 (m-fmap #(* (. Math log %) neg-inv-lambda) not-too-small))))159 ; Another implementation of the normal distribution. It uses the160 ; Box-Muller transform, but discards one of the two result values161 ; at each cycle because the random number transformer interface cannot162 ; handle two outputs at the same time.163 (defn normal-box-muller164 "Transform a sequence of uniform random numbers in the interval [0, 1)165 into a sequence of normal random numbers with mean mu and standard166 deviation sigma."167 [mu sigma]168 (fn [rs]169 (let [[u1 rs] (stream-next rs)170 [u2 rs] (stream-next rs)171 v1 (- (* 2.0 u1) 1.0)172 v2 (- (* 2.0 u2) 1.0)173 s (+ (* v1 v1) (* v2 v2))174 ls (. Math sqrt (/ (* -2.0 (. Math log s)) s))175 x1 (* v1 ls)176 x2 (* v2 ls)]177 (if (or (>= s 1) (= s 0))178 (recur rs)179 [x1 rs]))))181 ; Finite samples from a distribution182 (with-monad state-m184 (defn sample185 "Return the distribution of samples of length n from the186 distribution dist"187 [n dist]188 (m-seq (replicate n dist)))190 (defn sample-reduce191 "Returns the distribution of the reduction of f over n samples from the192 distribution dist."193 ([f n dist]194 (if (zero? n)195 (m-result (f))196 (let [m-f (m-lift 2 f)197 sample (replicate n dist)]198 (reduce m-f sample))))199 ([f val n dist]200 (let [m-f (m-lift 2 f)201 m-val (m-result val)202 sample (replicate n dist)]203 (reduce m-f m-val sample))))205 (defn sample-sum206 "Return the distribution of the sum over n samples from the207 distribution dist."208 [n dist]209 (sample-reduce ga/+ n dist))211 (defn sample-mean212 "Return the distribution of the mean over n samples from the213 distribution dist"214 [n dist]215 (let [div-by-n (m-lift 1 #(ga/* % (/ n)))]216 (div-by-n (sample-sum n dist))))218 (defn sample-mean-variance219 "Return the distribution of the mean-and-variance (a vector containing220 the mean and the variance) over n samples from the distribution dist"221 [n dist]222 (let [extract (m-lift 1 (fn [mv] [(:mean mv) (:variance mv)]))]223 (extract (sample-reduce acc/add acc/empty-mean-variance n dist))))225 )227 ; Uniform distribution inside an n-sphere228 (with-monad state-m229 (defn n-sphere230 "Return a uniform distribution of n-dimensional vectors inside an231 n-sphere of radius r."232 [n r]233 (let [box-dist (sample n (interval (- r) r))234 sq #(* % %)235 r-sq (sq r)236 vec-sq #(apply + (map sq %))237 sphere-dist (reject #(> (vec-sq %) r-sq) box-dist)238 as-vectors (m-lift 1 vec)]239 (as-vectors sphere-dist))))