From fadc4c87a0d5cd7949623e7430f24337caaec05c Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sun, 6 Oct 2013 18:21:46 +0200 Subject: [PATCH] Samples: extend F# distribution samples to Sample module, random walk --- src/FSharp/Distributions.fs | 8 ++++ src/FSharpExamples/RandomAndDistributions.fsx | 37 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/FSharp/Distributions.fs b/src/FSharp/Distributions.fs index e5e5aa03..f32a0765 100644 --- a/src/FSharp/Distributions.fs +++ b/src/FSharp/Distributions.fs @@ -35,6 +35,14 @@ open MathNet.Numerics.Random [] module Sample = + let transform f dist : System.Random -> 'T = fun rng -> f (dist rng) + let transform2 f dist1 dist2 : System.Random -> 'T = fun rng -> f (dist1 rng) (dist2 rng) + let transform3 f dist1 dist2 dist3 : System.Random -> 'T = fun rng -> f (dist1 rng) (dist2 rng) (dist3 rng) + + let transformSeq f dist : System.Random -> 'T seq = fun rng -> dist rng |> Seq.map f + let transformSeq2 f dist1 dist2 : System.Random -> 'T seq = fun rng -> Seq.zip (dist1 rng) (dist2 rng) |> Seq.map (fun (d1, d2) -> f d1 d2) + let transformSeq3 f dist1 dist2 dist3 : System.Random -> 'T seq = fun rng -> Seq.zip3 (dist1 rng) (dist2 rng) (dist3 rng) |> Seq.map (fun (d1, d2, d3) -> f d1 d2 d3) + /// Bernoulli with probability (p). let bernoulli p rng = Bernoulli.Sample(rng, p) let bernoulliSeq p rng = Bernoulli.Samples(rng, p) diff --git a/src/FSharpExamples/RandomAndDistributions.fsx b/src/FSharpExamples/RandomAndDistributions.fsx index 30567bd6..d56d4ff3 100644 --- a/src/FSharpExamples/RandomAndDistributions.fsx +++ b/src/FSharpExamples/RandomAndDistributions.fsx @@ -71,7 +71,7 @@ boolean argument at creation, or by setting `Control.ThreadSafeRandomNumberGener *) let a = Random.system () -let b = Random.systemSeed (Random.timeSeed()) +let b = Random.systemSeed (RandomSeed.Time()) let b2 = Random.systemSeed someGuidSeed let c = Random.crypto () let d = Random.mersenneTwister () @@ -134,6 +134,41 @@ let x = Hypergeometric.Sample(h, 100, 20, 5) (** +Specifically for F# there is also a `Sample` module that allow a somewhat +more functional view on the distributions by allowing them to be curried such that +the random source is passed in as last arguments. This way distributions can +be combined and transformed arbitrarily: + +*) + +/// Transform a sample distribution +let s1 rng = tanh (Sample.normal 2.0 0.5 rng) + +/// Alternative way where we transform the function instead of its result +let s1alt rng = Sample.transform tanh (Sample.normal 2.0 0.5) rng + +/// Alternative way that works exactly the same but operates on functions generating sequences +let s1seq rng = Sample.transformSeq tanh (Sample.normalSeq 2.0 0.5) rng + +/// The same with multiple distributions: +let s2 rng = (Sample.normal 2.0 1.5 rng) * (Sample.cauchy 2.0 0.5 rng) +let s2alt rng = Sample.transform2 (*) (Sample.normal 2.0 1.5) (Sample.cauchy 2.0 0.5) rng +let s2seq rng = Sample.transformSeq2 (*) (Sample.normalSeq 2.0 1.5) (Sample.cauchySeq 2.0 0.5) rng + +Seq.take 10 (s2seq (Random.system())) |> Seq.toArray + +(** + +Let's do some random walks, using distributions and random sources defined above: + +*) + +Seq.scan (+) 0.0 (normal.Samples()) |> Seq.take 10 |> Seq.toArray +Seq.scan (+) 0.0 (Sample.normalSeq 0.0 0.5 a) |> Seq.take 10 |> Seq.toArray +Seq.scan (+) 0.0 (s1seq a) |> Seq.take 10 |> Seq.toArray + +(** + Distributions can not just be used to generate random samples. You can use them to evaluate distribution properties or functions with the given parametrization.