locked
I can't figure out arrays in F# (Migrated from community.research.microsoft.com) RRS feed

  • Question

  • nbeckman posted on 06-28-2010 2:58 PM

    Hello!

    I am finally trying to switch my code from using arrays of Random Variables to using the VariableArray types and operators in Infer.NET. The trouble is, I am having issues with converting the code I see in the C# examples into F#, which it the language my program uses. And unfortunately, I find the functions defined in the wrapper functions to be rather difficult to understand...

    I am basically trying to do two things with arrays. The first I believe it pretty simple. I would like an array of Bernoulli random variables, and I'd like to initialize each element of the array such that the prior probability is one of my choosing (potentially different for each element of the array). I've tried the following code:

     

    let all_node_range = new Range(List.length nodes) in 

    let array = Variable.Array<bool>(all_node_range) in

    let pps: float list = nodePriorProbs nodes in    // find the prior for each node based on metadata

     

    let pp_const = Variable.Constant<float>(List.toArray pps) in

    let () = maps.unique_perms.set_Item(all_node_range,Variable.Bernoulli(pp_const.get_Item(all_node_range))) in

    ......

     

     

    So in other worlds, I am using the method Variable<T>.get_Item to replace the following code that I see in the C# examples:

    pp_const[all_node_range]

    since this syntax does not work in F#. Unfortunately, this does not work, and I get a runtime exception:

    Unhandled Exception: System.ArgumentException: VariableArray<double> vdouble[]0 cannot be indexed by index0. Perhaps you omitted index0 as an argument to the constructor?

    Parameter name: index

       at MicrosoftResearch.Infer.Models.Range.CheckCompatible(IModelExpression index, IVariableArray array) in C:\infernetBuilds\12-11-2009_17-18\Compiler\Infer\Models\Range.cs:line 171

     

     

    Additionally, elsewhere in my code I create other arrays whose contents are created by using the Variable operators, and I now suspect that I have written them incorrectly as well. For example, take the following code written in C#:

    new_constraint_array[new_range] = array1[new_range] & array2[new_range];

     

    Is this equivalent to the following, in F# syntax?

    let () = new_constraint_array.set_Item(new_range, array1.get_Item(new_range) &&& array2.get_Item(new_range)) in

    ...

     

    Thanks very much,

    Nels

    Friday, June 3, 2011 5:53 PM

Answers

  • nbeckman replied on 07-01-2010 9:07 AM

    Thanks John. You advice worked!

    Nels

    Friday, June 3, 2011 5:53 PM

All replies

  • nbeckman replied on 06-28-2010 4:53 PM

    Okay, well at least one part of the Exception message should have been obvious to me: the part about checking the constructor. If I add the range to my call to Variable.Constant, I no longer get the exception. In other words, the following change seems to work:

    ...

    let pp_const = Variable.Constant<float>(List.toArray pps,all_node_range) in

    let () = maps.unique_perms.set_Item(all_node_range,Variable.Bernoulli(pp_const.get_Item(all_node_range))) in

    ...

     

    Still, the question in my mind is, "Am I doing what I think I'm doing with get_Item and set_Item?" 

    Thanks,

    Nels

    Friday, June 3, 2011 5:53 PM
  • John Guiver replied on 06-29-2010 11:37 AM

    Hi Nels

    I am confused by your use of get_Item, so if what I suggest below misses the mark, perhaps you could expand on this.

    Going back to your original question, " I would like an array of Bernoulli random variables, and I'd like to initialize each element of the array such that the prior probability is one of my choosing (potentially different for each element of the array). ": the following code shows how to do this. Basically, you specify an Infer.NET random variable array of type Bernoulli. We cannot infer over a domain type Bernoulli, but we can set the observed value of this array at 'run-time' to an array of Bernoullis of your choosing. Your array random variable can then be defined from these priors using the Random factor.

    Best regards

    John

     #light
    open MicrosoftResearch.Infer.Models
    open MicrosoftResearch.Infer.Distributions
    open MicrosoftResearch.Infer

    // The model
    let
    range = new Range(3)
    let priors = Variable.Array<Bernoulli>(range)
    let array = Variable.Array<bool>(range)
    array.[range] <- Variable.Random<bool,Bernoulli>(priors.[range])

    // The inference
    priors.ObservedValue <- [|new Bernoulli(0.1); new Bernoulli(0.2); new Bernoulli(0.3);|]
    let engine = new InferenceEngine()
    let arrayMarg = engine.Infer<Bernoulli[]>(array)
    printf "%A" arrayMarg

    Friday, June 3, 2011 5:53 PM
  • nbeckman replied on 06-29-2010 12:30 PM

    Thank-you John,

     

    The truth is, I am no statistics expert and so I tend to get some of the terminology wrong, Bernoulli vs. Boolean in this case. But, I believe your code is doing what I want to achieve. I did not realize that the syntax ".[]" could be used in F#, so that's a good starting point. I'll make your suggested changes and see how things work out.

     

    Thanks for your help,

    Nels

    Friday, June 3, 2011 5:53 PM
  • nbeckman replied on 07-01-2010 9:07 AM

    Thanks John. You advice worked!

    Nels

    Friday, June 3, 2011 5:53 PM