Browse Source

Samples: migrate F# random & distributions to FSharp.Formatting style

pull/163/head
Christoph Ruegg 13 years ago
parent
commit
6fb602cc0b
  1. 28
      src/FSharp/Random.fs
  2. 155
      src/FSharpExamples/RandomAndDistributions.fsx

28
src/FSharp/Random.fs

@ -33,18 +33,8 @@ namespace MathNet.Numerics.Random
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Random =
/// Provides a time-dependent seed value (default behavior of System.Random)
/// WARNING: There is no randomness in this seed and quick repeated calls can cause
/// the same seed value. Do not use for cryptography!
let timeSeed () = RandomSeed.Time()
/// Provides a seed based on unique GUIDs
/// WARNING: There is only low randomness in this seed, but at least quick repeated
/// calls will result in different seed values. Do not use for cryptography!
let seed () = RandomSeed.Guid()
/// Creates a default .Net system pRNG with a custom seed based on uinque GUIDs
let system () = new System.Random(seed())
let system () = new System.Random(RandomSeed.Guid())
let systemSeed seed = new System.Random(seed)
#if PORTABLE
@ -55,43 +45,43 @@ module Random =
#endif
/// Creates a Mersenne Twister 19937 pRNG with a custom seed based on uinque GUIDs
let mersenneTwister () = new MersenneTwister(seed()) :> System.Random
let mersenneTwister () = new MersenneTwister() :> System.Random
let mersenneTwisterSeed (seed:int) = new MersenneTwister(seed) :> System.Random
let mersenneTwisterWith seed threadSafe = new MersenneTwister(seed, threadSafe) :> System.Random
/// Creates a multiply-with-carry Xorshift (Xn = a * Xn−3 + c mod 2^32) pRNG with a custom seed based on uinque GUIDs
let xorshift () = new Xorshift(seed()) :> System.Random
let xorshift () = new Xorshift() :> System.Random
let xorshiftSeed (seed:int) = new Xorshift(seed) :> System.Random
let xorshiftWith seed threadSafe = new Xorshift(seed, threadSafe) :> System.Random
let xorshiftCustom seed threadSafe a c x1 x2 = new Xorshift(seed, threadSafe, a, c, x1, x2) :> System.Random
/// Creates a Wichmann-Hill’s 1982 combined multiplicative congruential pRNG with a custom seed based on uinque GUIDs
let wh1982 () = new WH1982(seed()) :> System.Random
let wh1982 () = new WH1982() :> System.Random
let wh1982Seed (seed:int) = new WH1982(seed) :> System.Random
let wh1982With seed threadSafe = new WH1982(seed, threadSafe) :> System.Random
/// Creates a Wichmann-Hill’s 2006 combined multiplicative congruential pRNG with a custom seed based on uinque GUIDs
let wh2006 () = new WH2006(seed()) :> System.Random
let wh2006 () = new WH2006() :> System.Random
let wh2006Seed (seed:int) = new WH2006(seed) :> System.Random
let wh2006With seed threadSafe = new WH2006(seed, threadSafe) :> System.Random
/// Creates a Parallel Additive Lagged Fibonacci pRNG with a custom seed based on uinque GUIDs
let palf () = new Palf(seed()) :> System.Random
let palf () = new Palf() :> System.Random
let palfSeed (seed:int) = new Palf(seed) :> System.Random
let palfWith seed threadSafe = new Palf(seed, threadSafe, 418, 1279) :> System.Random
let palfCustom seed threadSafe shortLag longLag = new Palf(seed, threadSafe, shortLag, longLag) :> System.Random
/// Creates a Multiplicative congruential generator using a modulus of 2^59 and a multiplier of 13^13 pRNG with a custom seed based on uinque GUIDs
let mcg59 () = new Mcg59(seed()) :> System.Random
let mcg59 () = new Mcg59() :> System.Random
let mcg59Seed (seed:int) = new Mcg59(seed) :> System.Random
let mcg59With seed threadSafe = new Mcg59(seed, threadSafe) :> System.Random
/// Creates a Multiplicative congruential generator using a modulus of 2^31-1 and a multiplier of 1132489760 pRNG with a custom seed based on uinque GUIDs
let mcg31m1 () = new Mcg31m1(seed()) :> System.Random
let mcg31m1 () = new Mcg31m1() :> System.Random
let mcg31m1Seed (seed:int) = new Mcg31m1(seed) :> System.Random
let mcg31m1With seed threadSafe = new Mcg31m1(seed, threadSafe) :> System.Random
/// Creates a 32-bit combined multiple recursive generator with 2 components of order 3 pRNG with a custom seed based on uinque GUIDs
let mrg32k3a () = new Mrg32k3a(seed()) :> System.Random
let mrg32k3a () = new Mrg32k3a() :> System.Random
let mrg32k3aSeed (seed:int) = new Mrg32k3a(seed) :> System.Random
let mrg32k3aWith seed threadSafe = new Mrg32k3a(seed, threadSafe) :> System.Random

155
src/FSharpExamples/RandomAndDistributions.fsx

@ -1,32 +1,29 @@
// <copyright file="RandomAndDistributions.fsx" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2013 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
(**
Math.NET Numerics: Random Numbers and Probability Distributions
===============================================================
The .Net base class library provides a pseudo-random number generator
for non-cryptography use in the form of the `System.Numerics` class.
Math.NET Numerics provides a few alternatives with different characteristics
in randomness, bias, sequence length and performance. All these classes
inherit from System.Random so you can use them as a replacement for
System.Random even in third-party code.
All random number generators generate numbers in a more-or-less uniform
distribution. Often you need to sample random numbers with a different
distribution, e.g. a Gaussian. You can do that with one of the distribution
classes, or in F# also using the `Sample` module. The distribution classes
also provide a lot of other functionality around probability distributions,
like parameter estimation or evaluating the commulative distribution function.
Initializtation
---------------
We need to reference Math.NET Numerics and the F# modules, and open
the namespaces for random numbers and probability distributions:
*)
#r "../../out/lib/Net40/MathNet.Numerics.dll"
#r "../../out/lib/Net40/MathNet.Numerics.FSharp.dll"
@ -34,13 +31,48 @@
open MathNet.Numerics.Random
open MathNet.Numerics.Distributions
// generate some seeds for random values (NOT intended for cryptography!)
let someGuidSeed = Random.seed ()
let someTimeSeed = Random.timeSeed ()
(**
Random Number Generators
------------------------
Other than for cryptographic random numbers where you'd never want to provide
a seed, all pseudo-random numbers can be initialized with a custom seed.
The same seed causes the same number sequence to be generated, which can be
very useful if you need results to be reproducible, e.g. in testing/verification.
If no seed is provided, System.Random uses a time based seed equivalent to the
one below. This means that all instances created within a short timeframe
(which typically spans around a thousand CPU clock cycles) will generate
exactly the same sequence. This can happen easily e.g. in parallel computing
and is often unwanted. That's why all number generators created using
Math.NET Numerics routines are by default initialized with a seed that combines
the time with a Guid (which are supposed to be generated uniquely, worldwide).
*)
let someTimeSeed = RandomSeed.Time()
let someGuidSeed = RandomSeed.Guid()
(**
Random number generators can be created using the `Random` module. Most functions
optionally accept a manual seed when using the variant with the Seed-suffix.
Some of them, like xor-shift, also have a variant with a Custom-suffix that
allow to pass additional parameters specific to that generator.
Note that the generators should be reused when generating multiple numbers.
If you'd create a new generator each time, the numbers it generates would be
exactly as random as your seed - and thus not very random at all.
However, generators are not automatically thread-safe. They *are* thread-safe
in Math.NET Numerics by default, but that can be disabled either using a
boolean argument at creation, or by setting `Control.ThreadSafeRandomNumberGenerators`.
*)
// some pseudo random number generators (listing incomplete; all of them are cast to the common base type, System.Random)
let a = Random.system ()
let b = Random.systemSeed (Random.timeSeed())
let b2 = Random.systemSeed someGuidSeed
let c = Random.crypto ()
let d = Random.mersenneTwister ()
let e = Random.mersenneTwisterWith 1000 true (* thread-safe *)
@ -49,7 +81,7 @@ let g = Random.xorshiftCustom someTimeSeed false 916905990L 13579L 362436069L 77
let h = Random.wh2006 ()
let i = Random.palf ()
// generate some uniform random values
// Generate some uniform random values
let values = (
a.Next(),
b.NextFullRangeInt32(),
@ -59,6 +91,20 @@ let values = (
f.NextDecimal()
)
(**
Probability Distributions
-------------------------
Non-uniform probability distributions can be created using their normal constructor,
some also offer static functions if there are multiple ways to parametrize them.
Since probability distributions can also be sampled to generate random numbers
with the configured distribution, all constructors optionally accept a random generator
as last argument.
*)
// some probability distributions
let normal = Normal.WithMeanVariance(3.0, 1.5, g)
let exponential = Exponential(2.4)
@ -67,7 +113,7 @@ let cauchy = Cauchy(0.0, 1.0, Random.mrg32k3aWith 10 false)
let poisson = Poisson(3.0)
let geometric = Geometric(0.8, Random.system())
// generate some random samples from these distributions
// sample some random rumbers from these distributions
let continuous = [
yield normal.Sample()
yield exponential.Sample()
@ -79,17 +125,20 @@ let discrete = [
geometric.Sample()
]
// direct sampling (without creating a configurable distribution object)
// direct sampling (without creating a distribution object)
let u = Normal.Sample(Random.system(), 2.0, 4.0)
let v = Laplace.Samples(Random.mersenneTwister(), 1.0, 3.0) |> Seq.take 100 |> List.ofSeq
let w = Rayleigh.Sample(c, 1.5)
let x = Hypergeometric.Sample(h, 100, 20, 5)
// probability distribution functions of the normal dist we configured above
let nd = normal.Density(4.0) (* pdf *)
let ndLn = normal.DensityLn(4.0) (* ln(pdf) *)
let nc = normal.CumulativeDistribution(4.0) (* cdf *)
let nic = normal.InverseCumulativeDistribution(0.7) (* invcdf *)
(**
Distributions can not just be used to generate random samples.
You can use them to evaluate distribution properties or functions
with the given parametrization.
*)
// distribution properties of the gamma dist we configured above
let gammaStats = (
@ -100,3 +149,27 @@ let gammaStats = (
gamma.Skewness,
gamma.Mode
)
// probability distribution functions of the normal dist we configured above
let nd = normal.Density(4.0) (* pdf *)
let ndLn = normal.DensityLn(4.0) (* ln(pdf) *)
let nc = normal.CumulativeDistribution(4.0) (* cdf *)
let nic = normal.InverseCumulativeDistribution(0.7) (* invcdf *)
// Distribution functions can also be evaluated without creating an object,
// but then you have to pass in the distribution parameters as first arguments:
let nd2 = Normal.PDF(3.0, sqrt 1.5, 4.0)
let ndLn2 = Normal.PDFLn(3.0, sqrt 1.5, 4.0)
let nc2 = Normal.CDF(3.0, sqrt 1.5, 4.0)
let nic2 = Normal.InvCDF(3.0, sqrt 1.5, 0.7)
(**
Some of the distributions also have routines for maximum-likelihood parameter
estimation from a set of samples:
*)
let estimation = LogNormal.Estimate([| 2.0; 1.5; 2.1; 1.2; 3.0; 2.4; 1.8 |])
let mean, variance = estimation.Mean, estimation.Variance
let moreSamples = estimation.Samples() |> Seq.take 10 |> Seq.toArray

Loading…
Cancel
Save