locked
Range is already open in a ForEach or Switch block

    Question

  • I am continuing the Markov Mixture model implementation by adding cluster variable to the model. There are few major changes.

    (1) At the top level, I have Dirichlet prior over clusters and cluster probability parameter:

    ProbClusterPrior = Variable.New<Dirichlet>();
    ProbCluster = Variable<Vector>.Random(ProbClusterPrior).Named("ProbCluster");
    ProbCluster.SetValueRange(C);

    The Range "C" is a range over the clusters.

    (2) The model changes in the existing variables such that initial states and transition matrices are cluster specific. Essentially, the variables, variable arrays essentially get one more dimension on top - a cluster:

    // set init
    ProbInitPrior = Variable.Array<Dirichlet>(C);
    ProbInit = Variable.Array<Vector>(C).Named("ProbInit");
    ProbInit[C] = Variable<Vector>.Random(ProbInitPrior[C]).Named("ProbInit");
    ProbInit.SetValueRange(C);
    
    // set trans prob. table
    CPTTransPrior = Variable.Array(Variable.Array<Dirichlet>(K), C);
    CPTTrans = Variable.Array(Variable.Array<Vector>(K), C).Named("CPTTrans");
    CPTTrans[C][K] = Variable<Vector>.Random(CPTTransPrior[C][K]);
    CPTTrans.SetValueRange(C);

    (3) Also, I have a new variable array has been introduced to hold information about which cluster a sequence belongs to:

    Z = Variable.Array<int>(N);

    (4) The new model looks like this:

    using (Variable.ForEach(N))
    {
      Z[N] = Variable.Discrete(ProbCluster);
    
      using (var block = Variable.ForEach(T))
      {
        var t = block.Index;
    
        using (Variable.If(t == 0))
        using (Variable.Switch(Z[N]))
          States[N][T].SetTo(Variable.Discrete(ProbInit[Z[N]]));
    
        var previousState = States[N][t - 1];
    
        using (Variable.If(t > 0))
        using (Variable.Switch(previousState))
        using (Variable.Switch(Z[N]))
          States[N][T].SetTo(Variable.Discrete(CPTTrans[Z[N]][previousState]));
      }
    }


    The Infer.NET compiler apparently is not happy about the double "Switch" block and prints an error message:

    Unhandled Exception:
    System.InvalidOperationException: Range 'C' is already open in a ForEach or Switch block
      at MicrosoftResearch.Infer.Models.ForEachBlock.CheckRangeCanBeOpened (MicrosoftResearch.Infer.Models.Range range) [0x00079] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MicrosoftResearch.Infer.Models.SwitchBlock.OpenBlock () [0x00000] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MicrosoftResearch.Infer.Models.SwitchBlock..ctor (MicrosoftResearch.Infer.Models.Variable`1[T] conditionVariable, MicrosoftResearch.Infer.Models.Range range) [0x00010] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MicrosoftResearch.Infer.Models.Variable.Switch (MicrosoftResearch.Infer.Models.Variable`1[T] i) [0x00007] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MarkovMixtureModel.MarkovMixtureModel..ctor (System.Int32 NumClusters, System.Int32 NumChains, System.Int32 ChainLength, System.Int32 NumStates) [0x002cb] in /Users/vlad/Projects/MarkovMixtureModel/MarkovMixtureModel/MarkovMixtureModel.cs:89 
      at MarkovMixtureModel.Program.TestMarkovMixtureModel () [0x001e8] in /Users/vlad/Projects/MarkovMixtureModel/MarkovMixtureModel/Program.cs:83 
      at MarkovMixtureModel.Program.Main (System.String[] args) [0x00001] in /Users/vlad/Projects/MarkovMixtureModel/MarkovMixtureModel/Program.cs:15 
    [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Range 'C' is already open in a ForEach or Switch block
      at MicrosoftResearch.Infer.Models.ForEachBlock.CheckRangeCanBeOpened (MicrosoftResearch.Infer.Models.Range range) [0x00079] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MicrosoftResearch.Infer.Models.SwitchBlock.OpenBlock () [0x00000] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MicrosoftResearch.Infer.Models.SwitchBlock..ctor (MicrosoftResearch.Infer.Models.Variable`1[T] conditionVariable, MicrosoftResearch.Infer.Models.Range range) [0x00010] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MicrosoftResearch.Infer.Models.Variable.Switch (MicrosoftResearch.Infer.Models.Variable`1[T] i) [0x00007] in <1c09b726d63a41118a8cecdae81e3110>:0 
      at MarkovMixtureModel.MarkovMixtureModel..ctor (System.Int32 NumClusters, System.Int32 NumChains, System.Int32 ChainLength, System.Int32 NumStates) [0x002cb] in /Users/vlad/Projects/MarkovMixtureModel/MarkovMixtureModel/MarkovMixtureModel.cs:89 
      at MarkovMixtureModel.Program.TestMarkovMixtureModel () [0x001e8] in /Users/vlad/Projects/MarkovMixtureModel/MarkovMixtureModel/Program.cs:83 
      at MarkovMixtureModel.Program.Main (System.String[] args) [0x00001] in /Users/vlad/Projects/MarkovMixtureModel/MarkovMixtureModel/Program.cs:15 

    I think I see the issue: the two switches cannot work at the same time on the variable that is indexed by the two switch variable. Is that correct? How can I go around this issue?

    For other changes, I also added symmetry breaking code for the "Z" variable array. The array is initialized with random cluster assignments, as in Gaussian Mixture model case.

    I will appreciate pointers to solve the problem. Thanks!

    • Edited by usptact Wednesday, March 7, 2018 8:56 AM
    Wednesday, March 7, 2018 8:43 AM

Answers

  • You only need to invoke SetValueRange on the variable object, not every element.
    • Marked as answer by usptact Thursday, March 8, 2018 5:08 PM
    Thursday, March 8, 2018 2:57 PM
    Owner

All replies

  • If the ValueRange of CPTTrans is C, that means the ValueRange of States is also C.  Is that what you meant? 
    Wednesday, March 7, 2018 12:40 PM
    Owner
  • My understanding is that each CPTTrans[i] must have the ValueRange that is K. Similarly, the ValueRange for each States[i] must be Kl.

    For CPTTrans[i] I did this:

    for (int i = 0; i < NumClusters; i++)
      CPTTrans[i].SetValueRange(K);

    And similarly for States[i]:

    for (int i = 0; i < NumChains; i++)
      States[i].SetValueRange(K);

    Is this correct way of doing this?

    If I have an array of arrays, such as CPTTrans, can I just do this?

    CPTTrans.SetValueRange(K);

    I admit that I don't fully understand what SetValueRange does.

    Wednesday, March 7, 2018 6:34 PM
  • You only need to invoke SetValueRange on the variable object, not every element.
    • Marked as answer by usptact Thursday, March 8, 2018 5:08 PM
    Thursday, March 8, 2018 2:57 PM
    Owner
  • Thank you, Tom! The model inference works just fine.

    For those interested in the full source code, it is posted on GitHub:

    https ://github.com/usptact/MarkovMixtureModel

    Thursday, March 8, 2018 5:09 PM