dotnet / dotnet/infer

F# builders for simpler stochastic block syntax (DSL)

Open
#146 0 comments 3 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
1.6k
Forks
240
PR merge metrics
No merged PRs in 30d

Description

# F# builders for simpler stochastic block syntax (DSL)

I would like to share some helpers used in my F# scripts, either as a
suggestion for Infer.NET *FSharpWrapper.fs* or just a tip for F# folks.

The below F# module defines block builders for stochastic
`If`, `IfNot`, `Case`, `Switch`, `ForEach`, `Repeat`.

## The module

```fsharp
[]
module InferNetBlocks
open Microsoft.ML.Probabilistic.Models

/// The base builder literally wrapping a code block.
/// Derived builders have custom overrides, e.g. Run.
type BlockBuilder () =
member __.Delay (f) =
f
member __.Run (f) =
f ()
member __.Zero () =
()
member __.Return (x) =
x
member __.Combine (a, b) =
b a
member __.For (sequence, body) =
for item in sequence do
body item
member __.While (guard, body) =
while guard () do
body ()
member __.TryWith (body, handler) =
try body ()
with exn -> handler exn
member __.TryFinally (body, compensation) =
try body ()
finally compensation ()
member __.Using (disposable:#System.IDisposable, body) =
try body disposable
finally if not (isNull disposable) then disposable.Dispose ()

/// Creates a stochastic if statement when the variable is true.
/// Example: If variable { ... }
type If (variable) =
inherit BlockBuilder ()
member __.Run (f) =
use __ = Variable.If variable
f ()

/// Creates a stochastic if statement when the variable is false.
/// Example: IfNot variable { ... }
type IfNot (variable) =
inherit BlockBuilder ()
member __.Run (f) =
use __ = Variable.IfNot variable
f ()

/// Creates a stochastic case statement when the integer variable has the specified value.
/// Example: Case (variable, value) { ... }
type Case (variable, value) =
inherit BlockBuilder ()
member __.Run (f) =
use __ = Variable.Case (variable, value)
f ()

/// Creates a stochastic switch statement using the specified condition variable.
/// Example: Switch variable { ... }
type Switch (variable) =
inherit BlockBuilder ()
member __.Run (f) =
use __ = Variable.Switch variable
f ()

/// Creates a 'for each' block.
/// Example: ForEach range { ... }
type ForEach (range) =
inherit BlockBuilder ()
member __.Run (f) =
use __ = Variable.ForEach range
f ()

/// Creates a 'repeat' block.
/// Example: Repeat count { ... }
type Repeat (count) =
inherit BlockBuilder ()
member __.Run (f) =
use __ = Variable.Repeat count
f ()
```

## Examples with stochastic blocks

From my version of causality example (`ForEach`, `If`, `IfNot`):

```fsharp
// Loop over the data points
ForEach N {
If doB.[N] {
B.[N] <- Variable.Bernoulli probBIntervention
}
}

// First model: A causes B
If AcausesB {
ForEach N {
A.[N] <- Variable.Bernoulli 0.5
IfNot doB.[N] {
B.[N] <- Variable.NotEqual (A.[N], Variable.Bernoulli q)
}
}
}

// Second model: B causes A
IfNot AcausesB {
ForEach N {
IfNot doB.[N] {
B.[N] <- Variable.Bernoulli 0.5
}
A.[N] <- Variable.NotEqual (B.[N], Variable.Bernoulli q)
}
}
```

From my version of Gaussian mixture example (`ForEach`, `Switch`):

```fsharp
ForEach n {
z.[n] <- Variable.Discrete weights
Switch z.[n] {
data.[n] <- Variable.VectorGaussianFromMeanAndPrecision (means.[z.[n]], precs.[z.[n]])
}
}
```

From my version of "A Murder Mystery" (`Case`):

```fsharp
Case (murderer, Major) {
weapon.SetTo (Variable.Discrete (0.1, 0.9))
hair.SetTo (Variable.Bernoulli 0.5)
}
Case (murderer, Miss) {
weapon.SetTo (Variable.Discrete (0.8, 0.2))
hair.SetTo (Variable.Bernoulli 0.05)
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.