Answered by:
Constraining Bayesian Network using Jagged Array
Question

Hi, all~Rookie trying to mess with inference here……
I was trying to express that a[0]=a[1]&a[2]&a[3], a[1] == a[4], each has a Bernoulli prior of 0.5. I want to see what happens if a[0] is observed to be false.
But the mighty engine says that this model has zero probability. I notice that if I use something like using(Variable.If(b)){ var a = Variable.Bernoulli(0.99999);} would be a work around, but I don't know how……
using System;
using System.Collections.Generic;
using System.Text;
using MicrosoftResearch.Infer.Models;
using MicrosoftResearch.Infer;
using MicrosoftResearch.Infer.Distributions;
using MicrosoftResearch.Infer.Maths;
using PruneDynamicSlicing.Dependency.Interface;
using PruneDynamicSlicing.Dependency.Implementation;
using System.Collections;
namespace ProbInfer
{
class ProbInfer
{
static void Main(string[] args)
{
Variable<int> size = Variable.New<int>();
VariableArray<bool> array = Variable.Array<bool>(new Range(size));
size.ObservedValue = 5;
int[][] parents = new int[5][] { new int[] { 1, 2, 3 }, new int[] { 4 }, new int[] { }, new int[] { }, new int[] { } };
int[] index = new int[] { 3, 1, 0, 0, 0 };
Variable<int> outersize = Variable.New<int>();
Range outer = new Range(outersize);
VariableArray<int> innersize = Variable.Array<int>(outer);
Range inner = new Range(innersize[outer]);
outersize.ObservedValue = size.ObservedValue;
innersize.ObservedValue = index;
VariableArray<VariableArray<int>, int[][]> parentsArray = Variable.Array(Variable.Array<int>(inner), outer);
using (Variable.ForEach(outer))
{
using (Variable.ForEach(inner))
{
parentsArray[outer][inner] = Variable.New<int>();
}
}
parentsArray.ObservedValue = parents;
using (Variable.ForEach(array.Range)) { array[array.Range] = Variable.Bernoulli(0.5); }
using (ForEachBlock block = Variable.ForEach(outer))
{
VariableArray<bool> probs = Variable.Subarray<bool>(array, parentsArray[outer]);
Variable<bool> allTrue = Variable.AllTrue(probs);
Variable.ConstrainEqual(array[block.Index], allTrue);
}
Variable.ConstrainFalse(array[0]);
InferenceEngine engine = new InferenceEngine();
Console.WriteLine(engine.Infer(array));
return;}}}
Thanks a lot.
Friday, May 18, 2012 3:18 AM
Answers

For an array of length zero, AllTrue returns true. Thus your model is effectively constraining all variables to be true. You need to eliminate some of these constraints. By the way, this code is redundant:
using (Variable.ForEach(outer)) { using (Variable.ForEach(inner)) { parentsArray[outer][inner] = Variable.New<int>(); } }
Once you create a VariableArray, all elements are already created (they are just not given any distribution). Edited by Tom MinkaMicrosoft employee, Owner Friday, May 18, 2012 12:21 PM
 Marked as answer by Rex Xia Saturday, May 19, 2012 11:43 AM
Friday, May 18, 2012 12:01 PMOwner 
Hi Rex,
Look carefully at your ForEachBlock. You iterate over the Range "outer", the size of which is 5. The first two iterations do exactly what you want. However, the third iteration constrains array[2] to AllTrue of an empty array, which is 1.0! The fourth and fifth iterations of the block do the same with array[3] and array[4]. And since array[1] is constrained to be equal to array[4], it is also inferred as Bernoulli(1). Now, when you do Variable.ConstrainFalse(array[0]), you actually say:
false = array[0] = array[1] & array[2] & array[3] = true & true & true = true <!>
I think what you actually want is to loop only twice here. For example:Range i = new Range(2); using (ForEachBlock block = Variable.ForEach(i)) { VariableArray<bool> probs = Variable.Subarray<bool>(array, parentsArray[block.Index]); Variable<bool> allTrue = Variable.AllTrue(probs); Variable.ConstrainEqual(array[block.Index], allTrue); }
Thanks,
Yordan Marked as answer by Rex Xia Saturday, May 19, 2012 11:43 AM
Friday, May 18, 2012 12:10 PM 
The Equals method is not overloaded by Infer.NET so it does not work in model expressions. Your idea will work if you say: using(Variable.IfNot(innersize[outer] == 0))
 Marked as answer by Rex Xia Saturday, May 19, 2012 11:42 AM
Saturday, May 19, 2012 9:54 AMOwner
All replies

For an array of length zero, AllTrue returns true. Thus your model is effectively constraining all variables to be true. You need to eliminate some of these constraints. By the way, this code is redundant:
using (Variable.ForEach(outer)) { using (Variable.ForEach(inner)) { parentsArray[outer][inner] = Variable.New<int>(); } }
Once you create a VariableArray, all elements are already created (they are just not given any distribution). Edited by Tom MinkaMicrosoft employee, Owner Friday, May 18, 2012 12:21 PM
 Marked as answer by Rex Xia Saturday, May 19, 2012 11:43 AM
Friday, May 18, 2012 12:01 PMOwner 
Hi Rex,
Look carefully at your ForEachBlock. You iterate over the Range "outer", the size of which is 5. The first two iterations do exactly what you want. However, the third iteration constrains array[2] to AllTrue of an empty array, which is 1.0! The fourth and fifth iterations of the block do the same with array[3] and array[4]. And since array[1] is constrained to be equal to array[4], it is also inferred as Bernoulli(1). Now, when you do Variable.ConstrainFalse(array[0]), you actually say:
false = array[0] = array[1] & array[2] & array[3] = true & true & true = true <!>
I think what you actually want is to loop only twice here. For example:Range i = new Range(2); using (ForEachBlock block = Variable.ForEach(i)) { VariableArray<bool> probs = Variable.Subarray<bool>(array, parentsArray[block.Index]); Variable<bool> allTrue = Variable.AllTrue(probs); Variable.ConstrainEqual(array[block.Index], allTrue); }
Thanks,
Yordan Marked as answer by Rex Xia Saturday, May 19, 2012 11:43 AM
Friday, May 18, 2012 12:10 PM 
Hi Yordan,
Thank you very much for your reply. I was wondering what this code would look like if I do not have the information about the array length?
What if I have no idea the length of each variable's dependency? I used this code to build a constraint network based on a text input. Should I still use Variable.AllTrue?
Best,
Rex
Saturday, May 19, 2012 5:32 AM 
Thanks Tom, I think I know why this constraint has glitch.
using (ForEachBlock block = Variable.ForEach(outer)) { using (Variable.IfNot(parentsArray[outer].Range.Size.Equals(0))) { VariableArray<bool> probs = Variable.Subarray<bool>(array, parentsArray[outer]); Variable<bool> allTrue = Variable.AllTrue(probs); Variable.ConstrainEqual(array[block.Index], allTrue); } }
I modified this part but still have the same error message ...
Saturday, May 19, 2012 5:50 AM 
Hi Yordan,
I tried to modify the part but still messed up, the result says still zero probability...
using (ForEachBlock block = Variable.ForEach(outer)) { using (Variable.IfNot(parentsArray[outer].Range.Size.Equals(0))) { VariableArray<bool> probs = Variable.Subarray<bool>(array, parentsArray[outer]); Variable<bool> allTrue = Variable.AllTrue(probs); Variable.ConstrainEqual(array[block.Index], allTrue); } }
Something wrong with my assertion of a nonzero length dependency?
Best,
Rex
Saturday, May 19, 2012 5:52 AM 
The Equals method is not overloaded by Infer.NET so it does not work in model expressions. Your idea will work if you say: using(Variable.IfNot(innersize[outer] == 0))
 Marked as answer by Rex Xia Saturday, May 19, 2012 11:42 AM
Saturday, May 19, 2012 9:54 AMOwner