Imperative Statement Blocks in F#
The module Variable contains various functions to replace the imperative statement blocks in Infer.NET, these include ForeachBlock, SwitchBlock and IfBlock methods.
ForEach blocks
The Variable.ForeachBlock method which returns a ForEachBlock used for looping over a Range of values in a similar manner to a foreach loop in C#. This is
a function with the following type signature: Variable.ForEachBlock: RRange->(Range->unit)->unit
//using the Foreach Block let pixel = new Range(10) let bools = Variable.Array<bool>(pixel);
Variable.ForeachBlock pixel ( fun pixel -> bools.[pixel] <- Variable.Bernoulli(0.7) ||| Variable.Bernoulli(0.4)()) |
It should be noted that the Variable.ArrayInit method or the Variable.AssignVariableArray method can also be used to assign the values of a VariableArray as shown in the section Variable Arrays
Switch blocks
The Variable.SwitchBlock method which returns a SwitchBlock used for branching on the values of a variable. This is a function with the following type signature: Variable.SwitchBlock: Variable<int>->(Variable<int>->unit)->unit
//using the Switch Block
let mixtureSize = 2 let k2 = new Range(mixtureSize) let c = Variable.Discrete(k2, [|0.5;0.5|]) let means2 = Variable.Observed( [|1.0;2.0|], k2) let x = Variable.New<double>(); Variable.SwitchBlock c (fun _ -> let _ = x.SetTo(Variable.GaussianFromMeanAndVariance(means2.[c], 1.0)) () ) |
There is also another Switch construct which returns a Variable<'a> and can be used to initialise or set the values of VariableArrays. The function Variable.SwitchExpr has the following type signature: VVariable<int> -> (Variable<int>->Variable<'a>)->Variable<int>
//using the SwitchExpr Block
let means = Variable.ArrayInit k (fun k -> Variable.VectorGaussianFromMeanAndPrecision( new Vector(2,0.0), PositiveDefiniteMatrix.Identity(2))) let precs = Variable.ArrayInit k (fun k -> Variable.WishartFromShapeAndScale(1.0, PositiveDefiniteMatrix.Identity(2))) let weights = Variable.Dirichlet(k,[|1.0; 1.0|]) let n = new Range(100)
let z = Variable.ArrayInit n (fun i -> Variable.Discrete(weights)) let data = Variable.ArrayInit n (fun i -> Variable.SwitchExpr (z.[i]) (fun zi -> Variable.VectorGaussianFromMeanAndPrecision(means.[zi], precs.[zi]))) |
If Blocks
The Variable.IfBlock method returns an IfBlock for creating if then else statements which are dependant on the value of a Variable<bool> This is a function with type signature: Variable.IfBlock: Variable<bool>->(Variable<bool->unit)->Variable<bool->unit)->unit where, the first argument is a boolean variable, the second argument is a function to be applied if the Boolean Variable has value true and the third argument is a function to be applied if the Boolean Variable has value false. Here the If block is used in the Clinical trial tutorial shown below
// Data from a clinical trial let controlGroup = Variable.Observed<bool>([|false; false; true; false; false|]) let treatedGroup = Variable.Observed<bool>([|true; false; true; true; true |]) let i = controlGroup.Range let j = treatedGroup.Range // Prior on being an effective treatment let isEffective = Variable.Bernoulli(0.5).Named("isEffective"); let probIfTreated = ref (Variable.New<float>()) let probIfControl = ref (Variable.New<float>())
// If Block function let f1 (vb1: Variable<bool>) = probIfControl := Variable.Beta(1.0, 1.0).Named("probIfControl") let controlGroup = Variable.AssignVariableArray controlGroup i (fun i ->Variable.Bernoulli(!probIfControl)) let treatedGroup = Variable.AssignVariableArray treatedGroup j (fun j ->Variable.Bernoulli(!probIfTreated)) ()
// IfNot Block function let f2 (vb2: Variable<bool>) = let probAll = Variable.Beta(1.0, 1.0).Named("probAll") let controlGroup = Variable.AssignVariableArray controlGroup i (fun i ->Variable.Bernoulli(probAll)) let treatedGroup = Variable.AssignVariableArray treatedGroup j (fun j ->Variable.Bernoulli(probAll)) ()
// Call IfBlock let _ = Variable.IfBlock isEffective f1 f2 |