Math.NET Numerics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

95 lines
2.5 KiB

module MathNet.Numerics.Probability
#nowarn "40"
open System
open System.Collections
open System.Collections.Generic
open MathNet.Numerics
type Outcome<'T> = {
Value: 'T
Probability : BigRational }
type RandomVariable<'T> = Outcome<'T> seq
// P(A AND B) = P(A | B) * P(B)
let private bind f dist =
dist
|> Seq.map (fun p1 ->
f p1.Value
|> Seq.map (fun p2 ->
{ Value = p2.Value;
Probability =
p1.Probability * p2.Probability}))
|> Seq.concat
/// Inject a value into the RandomVariable type
let private returnM value =
Seq.singleton { Value = value ; Probability = 1N/1N }
type RandomVariableBuilder() =
member this.Bind (r, f) = bind f r
member this.Return x = returnM x
member this.ReturnFrom x = x
let randomVariable = RandomVariableBuilder()
type CoinSide =
| Heads
| Tails
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module RandomVariable =
// Create some helpers
let toUniformDistribution seq =
let l = Seq.length seq
seq
|> Seq.map (fun e ->
{ Value = e;
Probability = 1N / bignum.FromInt l })
let probability dist =
dist
|> Seq.map (fun o -> o.Probability)
|> Seq.sum
let certainly = returnM
let impossible<'a> :'a RandomVariable = toUniformDistribution []
let fairDice sides = toUniformDistribution [1..sides]
let fairCoin = toUniformDistribution [Heads; Tails]
let filter predicate dist =
dist |> Seq.filter (fun o -> predicate o.Value)
let filterInAnyOrder items dist =
items
|> Seq.fold (fun d item -> filter (Seq.exists ((=) (item))) d) dist
/// Transforms a RandomVariable value by using a specified mapping function.
let map f dist =
dist
|> Seq.map (fun o -> { Value = f o.Value; Probability = o.Probability })
let selectOne values =
[for e in values -> e,values |> Seq.filter ((<>) e)]
|> toUniformDistribution
let rec selectMany n values =
match n with
| 0 -> certainly ([],values)
| _ ->
randomVariable {
let! (x,c1) = selectOne values
let! (xs,c2) = selectMany (n-1) c1
return x::xs,c2}
let select n values =
selectMany n values
|> map (fst >> List.rev)
let remove items = Seq.filter (fun v -> Seq.forall ((<>) v) items)