Mercurial > lasercutter
view src/clojure/contrib/test_contrib/probabilities/examples_finite_distributions.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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3 ;;4 ;; Probability distribution application examples5 ;;6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9 (ns10 #^{:author "Konrad Hinsen"11 :skip-wiki true12 :doc "Examples for finite probability distribution"}13 clojure.contrib.probabilities.examples-finite-distributions14 (:use [clojure.contrib.probabilities.finite-distributions15 :only (uniform prob cond-prob join-with dist-m choose16 normalize certainly cond-dist-m normalize-cond)])17 (:use [clojure.contrib.monads18 :only (domonad with-monad m-seq m-chain m-lift)])19 (:require clojure.contrib.accumulators))21 ;; Simple examples using dice23 ; A single die is represented by a uniform distribution over the24 ; six possible outcomes.25 (def die (uniform #{1 2 3 4 5 6}))27 ; The probability that the result is odd...28 (prob odd? die)29 ; ... or greater than four.30 (prob #(> % 4) die)32 ; The sum of two dice33 (def two-dice (join-with + die die))34 (prob #(> % 6) two-dice)36 ; The sum of two dice using a monad comprehension37 (assert (= two-dice38 (domonad dist-m39 [d1 die40 d2 die]41 (+ d1 d2))))43 ; The two values separately, but as an ordered pair44 (domonad dist-m45 [d1 die46 d2 die]47 (if (< d1 d2) (list d1 d2) (list d2 d1)))49 ; The conditional probability for two dice yielding X if X is odd:50 (cond-prob odd? two-dice)52 ; A two-step experiment: throw a die, and then add 1 with probability 1/253 (domonad dist-m54 [d die55 x (choose (/ 1 2) d56 :else (inc d))]57 x)59 ; The sum of n dice60 (defn dice [n]61 (domonad dist-m62 [ds (m-seq (replicate n die))]63 (apply + ds)))65 (assert (= two-dice (dice 2)))67 (dice 3)70 ;; Construct an empirical distribution from counters72 ; Using an ordinary counter:73 (def dist174 (normalize75 (clojure.contrib.accumulators/add-items76 clojure.contrib.accumulators/empty-counter77 (for [_ (range 1000)] (rand-int 5)))))79 ; Or, more efficiently, using a counter that already keeps track of its total:80 (def dist281 (normalize82 (clojure.contrib.accumulators/add-items83 clojure.contrib.accumulators/empty-counter-with-total84 (for [_ (range 1000)] (rand-int 5)))))87 ;; The Monty Hall game88 ;; (see http://en.wikipedia.org/wiki/Monty_Hall_problem for a description)90 ; The set of doors. In the classical variant, there are three doors,91 ; but the code can also work with more than three doors.92 (def doors #{:A :B :C})94 ; A simulation of the game, step by step:95 (domonad dist-m96 [; The prize is hidden behind one of the doors.97 prize (uniform doors)98 ; The player make his initial choice.99 choice (uniform doors)100 ; The host opens a door which is neither the prize door nor the101 ; one chosen by the player.102 opened (uniform (disj doors prize choice))103 ; If the player stays with his initial choice, the game ends and the104 ; following line should be commented out. It describes the switch from105 ; the initial choice to a door that is neither the opened one nor106 ; his original choice.107 choice (uniform (disj doors opened choice))108 ]109 ; If the chosen door has the prize behind it, the player wins.110 (if (= choice prize) :win :loose))113 ;; Tree growth simulation114 ;; Adapted from the code in:115 ;; Martin Erwig and Steve Kollmansberger,116 ;; "Probabilistic Functional Programming in Haskell",117 ;; Journal of Functional Programming, Vol. 16, No. 1, 21-34, 2006118 ;; http://web.engr.oregonstate.edu/~erwig/papers/abstracts.html#JFP06a120 ; A tree is represented by two attributes: its state (alive, hit, fallen),121 ; and its height (an integer). A new tree starts out alive and with zero height.122 (def new-tree {:state :alive, :height 0})124 ; An evolution step in the simulation modifies alive trees only. They can125 ; either grow by one (90% probability), be hit by lightning and then stop126 ; growing (4% probability), or fall down (6% probability).127 (defn evolve-1 [tree]128 (let [{s :state h :height} tree]129 (if (= s :alive)130 (choose 0.9 (assoc tree :height (inc (:height tree)))131 0.04 (assoc tree :state :hit)132 :else {:state :fallen, :height 0})133 (certainly tree))))135 ; Multiple evolution steps can be chained together with m-chain,136 ; since each step's input is the output of the previous step.137 (with-monad dist-m138 (defn evolve [n tree]139 ((m-chain (replicate n evolve-1)) tree)))141 ; Try it for zero, one, or two steps.142 (evolve 0 new-tree)143 (evolve 1 new-tree)144 (evolve 2 new-tree)146 ; We can also get a distribution of the height only:147 (with-monad dist-m148 ((m-lift 1 :height) (evolve 2 new-tree)))152 ;; Bayesian inference153 ;;154 ;; Suppose someone has three dice, one with six faces, one with eight, and155 ;; one with twelve. This person throws one die and gives us the number,156 ;; but doesn't tell us which die it was. What are the Bayesian probabilities157 ;; for each of the three dice, given the observation we have?159 ; A function that returns the distribution of a dice with n faces.160 (defn die-n [n] (uniform (range 1 (inc n))))162 ; The three dice in the game with their distributions. With this map, we163 ; can easily calculate the probability for an observation under the164 ; condition that a particular die was used.165 (def dice {:six (die-n 6)166 :eight (die-n 8)167 :twelve (die-n 12)})169 ; The only prior knowledge is that one of the three dice is used, so we170 ; have no better than a uniform distribution to start with.171 (def prior (uniform (keys dice)))173 ; Add a single observation to the information contained in the174 ; distribution. Adding an observation consists of175 ; 1) Draw a die from the prior distribution.176 ; 2) Draw an observation from the distribution of that die.177 ; 3) Eliminate (replace by nil) the trials that do not match the observation.178 ; 4) Normalize the distribution for the non-nil values.179 (defn add-observation [prior observation]180 (normalize-cond181 (domonad cond-dist-m182 [die prior183 number (get dice die)184 :when (= number observation) ]185 die)))187 ; Add one observation.188 (add-observation prior 1)190 ; Add three consecutive observations.191 (-> prior (add-observation 1)192 (add-observation 3)193 (add-observation 7))195 ; We can also add multiple observations in a single trial, but this196 ; is slower because more combinations have to be taken into account.197 ; With Bayesian inference, it is most efficient to eliminate choices198 ; as early as possible.199 (defn add-observations [prior observations]200 (with-monad cond-dist-m201 (let [n-nums #(m-seq (replicate (count observations) (get dice %)))]202 (normalize-cond203 (domonad204 [die prior205 nums (n-nums die)206 :when (= nums observations)]207 die)))))209 (add-observations prior [1 3 7])