diff options
author | Chouser <chouser@n01se.net> | 2010-09-30 12:13:11 -0400 |
---|---|---|
committer | Chouser <chouser@n01se.net> | 2010-09-30 14:03:55 -0400 |
commit | 2e7ef0b12838b33f12e5c13ae41d4dd34a5469e8 (patch) | |
tree | 2fabe27d86925bff45e7b708d1c62507337b4482 /modules/probabilities | |
parent | 39c38227d21f8cb6139d68f361b516ce1f05f66e (diff) |
Restore examples lost during modules split, a6a92b9b3d2bfd9a56e1e5e9cfba706d1aeeaae5
Diffstat (limited to 'modules/probabilities')
-rw-r--r-- | modules/probabilities/src/examples/clojure/examples/finite_distributions.clj | 209 | ||||
-rw-r--r-- | modules/probabilities/src/examples/clojure/examples/monte_carlo.clj | 73 |
2 files changed, 282 insertions, 0 deletions
diff --git a/modules/probabilities/src/examples/clojure/examples/finite_distributions.clj b/modules/probabilities/src/examples/clojure/examples/finite_distributions.clj new file mode 100644 index 00000000..8a795e16 --- /dev/null +++ b/modules/probabilities/src/examples/clojure/examples/finite_distributions.clj @@ -0,0 +1,209 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Probability distribution application examples +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(ns + #^{:author "Konrad Hinsen" + :skip-wiki true + :doc "Examples for finite probability distribution"} + examples.finite-distributions + (:use [clojure.contrib.probabilities.finite-distributions + :only (uniform prob cond-prob join-with dist-m choose + normalize certainly cond-dist-m normalize-cond)]) + (:use [clojure.contrib.monads + :only (domonad with-monad m-seq m-chain m-lift)]) + (:require clojure.contrib.accumulators)) + +;; Simple examples using dice + +; A single die is represented by a uniform distribution over the +; six possible outcomes. +(def die (uniform #{1 2 3 4 5 6})) + +; The probability that the result is odd... +(prob odd? die) +; ... or greater than four. +(prob #(> % 4) die) + +; The sum of two dice +(def two-dice (join-with + die die)) +(prob #(> % 6) two-dice) + +; The sum of two dice using a monad comprehension +(assert (= two-dice + (domonad dist-m + [d1 die + d2 die] + (+ d1 d2)))) + +; The two values separately, but as an ordered pair +(domonad dist-m + [d1 die + d2 die] + (if (< d1 d2) (list d1 d2) (list d2 d1))) + +; The conditional probability for two dice yielding X if X is odd: +(cond-prob odd? two-dice) + +; A two-step experiment: throw a die, and then add 1 with probability 1/2 +(domonad dist-m + [d die + x (choose (/ 1 2) d + :else (inc d))] + x) + +; The sum of n dice +(defn dice [n] + (domonad dist-m + [ds (m-seq (replicate n die))] + (apply + ds))) + +(assert (= two-dice (dice 2))) + +(dice 3) + + +;; Construct an empirical distribution from counters + +; Using an ordinary counter: +(def dist1 + (normalize + (clojure.contrib.accumulators/add-items + clojure.contrib.accumulators/empty-counter + (for [_ (range 1000)] (rand-int 5))))) + +; Or, more efficiently, using a counter that already keeps track of its total: +(def dist2 + (normalize + (clojure.contrib.accumulators/add-items + clojure.contrib.accumulators/empty-counter-with-total + (for [_ (range 1000)] (rand-int 5))))) + + +;; The Monty Hall game +;; (see http://en.wikipedia.org/wiki/Monty_Hall_problem for a description) + +; The set of doors. In the classical variant, there are three doors, +; but the code can also work with more than three doors. +(def doors #{:A :B :C}) + +; A simulation of the game, step by step: +(domonad dist-m + [; The prize is hidden behind one of the doors. + prize (uniform doors) + ; The player make his initial choice. + choice (uniform doors) + ; The host opens a door which is neither the prize door nor the + ; one chosen by the player. + opened (uniform (disj doors prize choice)) + ; If the player stays with his initial choice, the game ends and the + ; following line should be commented out. It describes the switch from + ; the initial choice to a door that is neither the opened one nor + ; his original choice. + choice (uniform (disj doors opened choice)) + ] + ; If the chosen door has the prize behind it, the player wins. + (if (= choice prize) :win :loose)) + + +;; Tree growth simulation +;; Adapted from the code in: +;; Martin Erwig and Steve Kollmansberger, +;; "Probabilistic Functional Programming in Haskell", +;; Journal of Functional Programming, Vol. 16, No. 1, 21-34, 2006 +;; http://web.engr.oregonstate.edu/~erwig/papers/abstracts.html#JFP06a + +; A tree is represented by two attributes: its state (alive, hit, fallen), +; and its height (an integer). A new tree starts out alive and with zero height. +(def new-tree {:state :alive, :height 0}) + +; An evolution step in the simulation modifies alive trees only. They can +; either grow by one (90% probability), be hit by lightning and then stop +; growing (4% probability), or fall down (6% probability). +(defn evolve-1 [tree] + (let [{s :state h :height} tree] + (if (= s :alive) + (choose 0.9 (assoc tree :height (inc (:height tree))) + 0.04 (assoc tree :state :hit) + :else {:state :fallen, :height 0}) + (certainly tree)))) + +; Multiple evolution steps can be chained together with m-chain, +; since each step's input is the output of the previous step. +(with-monad dist-m + (defn evolve [n tree] + ((m-chain (replicate n evolve-1)) tree))) + +; Try it for zero, one, or two steps. +(evolve 0 new-tree) +(evolve 1 new-tree) +(evolve 2 new-tree) + +; We can also get a distribution of the height only: +(with-monad dist-m + ((m-lift 1 :height) (evolve 2 new-tree))) + + + +;; Bayesian inference +;; +;; Suppose someone has three dice, one with six faces, one with eight, and +;; one with twelve. This person throws one die and gives us the number, +;; but doesn't tell us which die it was. What are the Bayesian probabilities +;; for each of the three dice, given the observation we have? + +; A function that returns the distribution of a dice with n faces. +(defn die-n [n] (uniform (range 1 (inc n)))) + +; The three dice in the game with their distributions. With this map, we +; can easily calculate the probability for an observation under the +; condition that a particular die was used. +(def dice {:six (die-n 6) + :eight (die-n 8) + :twelve (die-n 12)}) + +; The only prior knowledge is that one of the three dice is used, so we +; have no better than a uniform distribution to start with. +(def prior (uniform (keys dice))) + +; Add a single observation to the information contained in the +; distribution. Adding an observation consists of +; 1) Draw a die from the prior distribution. +; 2) Draw an observation from the distribution of that die. +; 3) Eliminate (replace by nil) the trials that do not match the observation. +; 4) Normalize the distribution for the non-nil values. +(defn add-observation [prior observation] + (normalize-cond + (domonad cond-dist-m + [die prior + number (get dice die) + :when (= number observation) ] + die))) + +; Add one observation. +(add-observation prior 1) + +; Add three consecutive observations. +(-> prior (add-observation 1) + (add-observation 3) + (add-observation 7)) + +; We can also add multiple observations in a single trial, but this +; is slower because more combinations have to be taken into account. +; With Bayesian inference, it is most efficient to eliminate choices +; as early as possible. +(defn add-observations [prior observations] + (with-monad cond-dist-m + (let [n-nums #(m-seq (replicate (count observations) (get dice %)))] + (normalize-cond + (domonad + [die prior + nums (n-nums die) + :when (= nums observations)] + die))))) + +(add-observations prior [1 3 7]) diff --git a/modules/probabilities/src/examples/clojure/examples/monte_carlo.clj b/modules/probabilities/src/examples/clojure/examples/monte_carlo.clj new file mode 100644 index 00000000..4583dcf9 --- /dev/null +++ b/modules/probabilities/src/examples/clojure/examples/monte_carlo.clj @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Monte-Carlo application examples +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(ns + #^{:author "Konrad Hinsen" + :skip-wiki true + :doc "Examples for monte carlo methods"} + examples.monte-carlo + (:require [clojure.contrib.generic.collection :as gc]) + (:use [clojure.contrib.probabilities.random-numbers + :only (lcg rand-stream)]) + (:use [clojure.contrib.probabilities.finite-distributions + :only (uniform)]) + (:use [clojure.contrib.probabilities.monte-carlo + :only (random-stream discrete interval normal lognormal exponential + n-sphere + sample sample-sum sample-mean sample-mean-variance)] + :reload) + (:use [clojure.contrib.monads + :only (domonad state-m)])) + +; Create a linear congruential generator +(def urng (lcg 259200 7141 54773 1)) + +;; Use Clojure's built-in random number generator +;(def urng rand-stream) + +; Sample transformed distributions +(defn sample-distribution + [n rt] + (take n (gc/seq (random-stream rt urng)))) + +; Interval [-2, 2) +(sample-distribution 10 (interval -2 2)) +; Compare with a direct transformation +(= (sample-distribution 10 (interval -2 2)) + (map (fn [x] (- (* 4 x) 2)) (take 10 (gc/seq urng)))) + +; Normal distribution +(sample-distribution 10 (normal 0 1)) + +; Log-Normal distribution +(sample-distribution 10 (lognormal 0 1)) + +; Exponential distribution +(sample-distribution 10 (exponential 1)) + +; n-sphere distribution +(sample-distribution 10 (n-sphere 2 1)) + +; Discrete distribution +(sample-distribution 10 (discrete (uniform (range 1 7)))) + +; Compose distributions in the state monad +(def sum-two-dists + (domonad state-m + [r1 (interval -2 2) + r2 (normal 0 1)] + (+ r1 r2))) + +(sample-distribution 10 sum-two-dists) + +; Distribution transformations +(sample-distribution 5 (sample 2 (interval -2 2))) +(sample-distribution 10 (sample-sum 10 (interval -2 2))) +(sample-distribution 10 (sample-mean 10 (interval -2 2))) +(sample-distribution 10 (sample-mean-variance 10 (interval -2 2))) + |