none
Mixing continous and integer variables

    问题

  • Hi,

    As part of my effort learning how to use Infer.Net for solving an interesting problem, I am struggling with a part of my model, which involves both continous and integer variables. The part that causes me trouble has the following form:

    cpObservations[range] = distances[range] + 0.2 * n+ Variable.GaussianFromMeanAndVariance(0, 0.02);

    where cpObservations (observed) and distances are Gaussian variables, and n is supposed to be a fixed integer, whose value is to be estimated by the model data.

    I don't know how to properly represent and implement n. I have played around with a custom factor implementing a rounding operation on a gaussian variable, but I have had no real success so far. Either my approach is wrong or my knowledge about how to implement the exact factor messages is insufficient.

    Any ideas how to proceed? I would be happy for any feedback

    Thank you

    Henrik Kjær Nielsen

    2012年3月18日 19:09

答案

  • Apologies for the delay in replying - it's been a busy week.

    Would this do what you want?

    John

    		static void Main(string[] args)
    		{
    			// The model
    			var nMults = Variable.New<int>();
    			var nRange = new Range(nMults);
    
    			var n = Variable.DiscreteUniform(nRange);
    			var multiplier = Variable.Array<double>(nRange);
    
    			var nData = Variable.New<int>();
    			var range = new Range(nData);
    
    			var distances = Variable.Array<double>(range);
    			distances[range] = Variable.GaussianFromMeanAndPrecision(0, 1).ForEach(range);
    			var cpObservations = Variable.Array<double>(range);
    
    			using (Variable.Switch(n))
    			{
    				var mult = multiplier[n];
    				cpObservations[range] = distances[range] * mult + Variable.GaussianFromMeanAndVariance(0, 0.02);
    			}
    
    			// The data
    			var observedData = new double[] { 0.5, 0.6, 0.7 };
    			int numMults = 6;
    			var mults = Enumerable.Range(1, numMults).Select(i => (double)i).ToArray();
    
    			nMults.ObservedValue = numMults;
    			multiplier.ObservedValue = mults;
    			nData.ObservedValue = observedData.Length;
    			cpObservations.ObservedValue = observedData;
    
    			var engine = new InferenceEngine();
    			Console.WriteLine(engine.Infer(n));
    			Console.WriteLine(engine.Infer(distances));
    
    		}

    2012年3月30日 17:21

全部回复

  • Apologies for the delay in replying - it's been a busy week.

    Would this do what you want?

    John

    		static void Main(string[] args)
    		{
    			// The model
    			var nMults = Variable.New<int>();
    			var nRange = new Range(nMults);
    
    			var n = Variable.DiscreteUniform(nRange);
    			var multiplier = Variable.Array<double>(nRange);
    
    			var nData = Variable.New<int>();
    			var range = new Range(nData);
    
    			var distances = Variable.Array<double>(range);
    			distances[range] = Variable.GaussianFromMeanAndPrecision(0, 1).ForEach(range);
    			var cpObservations = Variable.Array<double>(range);
    
    			using (Variable.Switch(n))
    			{
    				var mult = multiplier[n];
    				cpObservations[range] = distances[range] * mult + Variable.GaussianFromMeanAndVariance(0, 0.02);
    			}
    
    			// The data
    			var observedData = new double[] { 0.5, 0.6, 0.7 };
    			int numMults = 6;
    			var mults = Enumerable.Range(1, numMults).Select(i => (double)i).ToArray();
    
    			nMults.ObservedValue = numMults;
    			multiplier.ObservedValue = mults;
    			nData.ObservedValue = observedData.Length;
    			cpObservations.ObservedValue = observedData;
    
    			var engine = new InferenceEngine();
    			Console.WriteLine(engine.Infer(n));
    			Console.WriteLine(engine.Infer(distances));
    
    		}

    2012年3月30日 17:21
  • Hi John,

    Thank you for your feedback. This was exactly what I needed...

    As a side note, I have a few comments regarding Infer.NET based on my rather limited experience so far. Maybe my comments are not all relevant or already taken care of:

    1. When working with indexes in relation to ranges and vectors, I sometimes run into type issues like: "Argument type 'Microsoft.Infer.Models.Variable<int>' is not assignable to parameter type 'int'". Is there no way to cast a 'Microsoft.Infer.Models.Variable<int>' to an 'int' ?

    2. A part of my model had the following construction:

    using (ForEachBlock ddBlock = Variable.ForEach(ddRange))
                {
                    ddAmbiguities[ddRange] = sdAmbiguities[ddBlock.Index + 1] - sdAmbiguities[ddBlock.Index];
                }

    This however causes a compiler error: "Variable 'sdAmbiguities_use' appears twice in the same function call. This will lead to inaccurate inference."
    But the two sdAmbiguities are different variables, and there should be nothing wrong in the above statement. However, the following slightly arkward reformulation seems to do the trick:

    using (ForEachBlock ddBlock = Variable.ForEach(ddRange))
                {
                    ddAmbiguities[ddRange] = (sdAmbiguities[ddBlock.Index + 1] - 0) - (sdAmbiguities[ddBlock.Index] - 0);
                }

    Maybe this could be fixed in a later release.

    3. May I suggest that the model source code generated by Infer.NET simply adds the "partial" keyword in the class declaration (as in: public partial class Model_EP : IGeneratedAlgorithm). This would allow for having various helper functions (data set handling, custom functions etc) in a separate file and use these with the pre-compiled model code without having to merge source code after each re-compilation of the model.

    Best regards

    Henrik Kjær Nielsen

    2012年4月1日 11:18
  • 1. It doesn't make sense to cast a Variable<int> into an int, since the Variable may be random.  If the Variable is constant or observed, you can get its ObservedValue.  For Ranges, there is a special property SizeAsInt that reads the ObservedValue property of its size variable.

    2. This is a bug.  Thanks for finding it.

    3. Good suggestion.  I'll look into it.

    2012年4月4日 16:53
  • Infer.NET 2.5 has fixed the above bug, and the generated code now has the "partial" keyword as you suggested.

    2012年10月4日 10:17