Answered by:
TrueSkill: draw option
Question

The simplest TrueSkill model involving two players is fairly easy to implement. I am following the MBML book online (http://mbmlbook.com/TrueSkill_Extensions_to_the_core_model.html) and tried to implement also the draw outcome (Figure 3.33). The draw introduces a margin that separates win regions for two players according to players' performances in a particular game.
My first idea was to write the three cases like this:
using (Variable.ForEach(n)) { using (Variable.If(Abs(Jperfs[n]  Fperfs[n]) < 2*drawMargin)) { outcomes[n] = 0; } using (Variable.If(Jperfs[n] > Fperfs[n] + drawMargin)) { outcomes[n] = 1; // Jill wins } using (Variable.If(Fperfs[n] > Jperfs[n] + drawMargin)) { outcomes[n] = 2; // Fred wins } }
Only to realize that Infer.NET does not support Abs (absolute value of difference). Or does it?
My next model implementation was bit more involved in testing the cases:
using (Variable.ForEach(n)) { using (Variable.If(Jperfs[n] > Fperfs[n])) { var JillWins = Jperfs[n]  Fperfs[n]  drawMargin; using (Variable.If(JillWins > 0)) outcomes[n] = 1; using (Variable.IfNot(JillWins > 0)) outcomes[n] = 0; } using (Variable.If(Fperfs[n] > Jperfs[n])) { var FredWins = Fperfs[n]  Jperfs[n]  drawMargin; using (Variable.If(FredWins > 0)) outcomes[n] = 2; using (Variable.IfNot(FredWins > 0)) outcomes[n] = 0; } }
Unfortunately this rewrote model does not compile. The compiler complains about not being able to do difference operation. I tried both Expectation and VMP inference engines; in both cases the model failed to compile.
The data and model variable are implemented as:
int[] outcomes_data = new int[] { 1, // Jill wins 1, // Jill wins 1, // Jill wins 1, // Jill wins 1, // Jill wins 2, // Fred wins 2, // Fred wins 0, // Draw 0}; // Draw int numGames = outcomes_data.Length; Range n = new Range(numGames); // prior beliefs on skill var Jskill = Variable.GaussianFromMeanAndVariance(120, 5 * 5); var Fskill = Variable.GaussianFromMeanAndVariance(100, 40 * 40); // performance for 1+ games for Jill var Jperfs = Variable.Array<double>(n); Jperfs[n] = Variable.GaussianFromMeanAndVariance(Jskill, 5 * 5).ForEach(n); // performance for 1+ games for Fred var Fperfs = Variable.Array<double>(n); Fperfs[n] = Variable.GaussianFromMeanAndVariance(Fskill, 5 * 5).ForEach(n); var drawMargin = Variable.GammaFromMeanAndVariance(1.0, 10.0); // game outcomes (0  Draw; 1  Jill wins; 2  Fred wins) var outcomes = Variable.Array<int>(n);
As in the two person variant, I tried to infer the skill marginal for the two players:
// attaching data outcomes.ObservedValue = outcomes_data; InferenceEngine engine = new InferenceEngine(new VariationalMessagePassing()); Gaussian JskillMarginal = engine.Infer<Gaussian>(Jskill); Gaussian FskillMarginal = engine.Infer<Gaussian>(Fskill); Console.WriteLine("Jskill marginal = {0}", JskillMarginal); Console.WriteLine("Fskill marginal = {0}", FskillMarginal);
What can be the issue with my model? Did I overlook something?
Thanks
 Edited by usptact Tuesday, November 14, 2017 12:01 AM
Monday, November 13, 2017 11:49 PM
Answers

I managed to get this working, at least past compilation error.
My first mistake was to declare and statistically define "drawMargin" as Gamma, not Gaussian. This is what made the compilation fail. But hey, why can't I have "drawMargin" to be Gamma distributed? I do want it to be positive.
After the first mistake was fixed, there was still an exception about "index" out of bounds (???). I ended up rewriting the model slightly:
using (Variable.ForEach(n)) { using (Variable.If(Jperfs[n] < Fperfs[n] + drawMargin  Jperfs[n] < Fperfs[n] + drawMargin)) outcomes[n] = 0; using (Variable.If(Jperfs[n] > Fperfs[n] + drawMargin)) outcomes[n] = 1; using (Variable.If(Fperfs[n] > Jperfs[n] + drawMargin)) outcomes[n] = 2; }
The first case looks bit ugly but it is essentially negation of the 2nd and 3rd case (negation of "A and B" is "not A or not B"). It would've been nicer to write something like Abs(Jperfs[n]  Fperfs[n]) < 2*drawMargin.
One last remark: As I mentioned above, I want "drawMargin" to be positive. So I added the statement:
Variable.ConstrainPositive(drawMargin);
If I remove it, the inference still works and the marginals look the same (when this statement is removed). I am unsure why it works...
Leaving it here for a future traveler.
Tuesday, November 14, 2017 5:47 PM
All replies

Here is the error message:
MicrosoftResearch.Infer.CompilationFailedException occurred HResult=0x80131500 Message=MessageTransform failed with 12 error(s) and 0 warning(s): Error 0: This model is not supported with VariationalMessagePassing due to Factor.IsPositive(bool isPositive, double x). Try using a different algorithm or expressing the model differently in Factor.IsPositive(vdouble17) Details: [0] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [1] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [2] System.ArgumentException: Bernoulli is not of type bool for argument 1 of method IsPositiveOp.XAverageLogarithm(bool isPositive = Bernoulli) Error 1: This model is not supported with VariationalMessagePassing due to Factor.Difference(double difference, double a, double b). Try using a different algorithm or expressing the model differently in Factor.Difference(vdouble18, vdouble16__0_) Details: [0] System.ArgumentException: Gamma is not of type Gaussian for argument 2 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(Gaussian a = Gaussian, Gaussian b = Gamma) [1] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(double a = Gaussian, Gaussian b = Gamma) [2] System.ArgumentException: Gamma is not of type double for argument 2 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(Gaussian a = Gaussian, double b = Gamma) [3] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(double a = Gaussian, double b = Gamma) Error 2: This model is not supported with VariationalMessagePassing due to Factor.Difference(double difference, double a, double b). Try using a different algorithm or expressing the model differently in Factor.Difference(vdouble18, vdouble16__0_) Details: [0] System.ArgumentException: Gamma is not of type Gaussian for argument 2 of method DoubleMinusVmpOp.AAverageLogarithm(Gaussian Difference = Gaussian, Gaussian b = Gamma) [1] System.ArgumentException: Gamma is not of type double for argument 2 of method DoubleMinusVmpOp.AAverageLogarithm(Gaussian Difference = Gaussian, double b = Gamma) [2] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.AAverageLogarithm(double Difference = Gaussian, Gaussian b = Gamma) [3] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.AAverageLogarithm(double Difference = Gaussian, double b = Gamma) Error 3: This model is not supported with VariationalMessagePassing due to Factor.Difference(double difference, double a, double b). Try using a different algorithm or expressing the model differently in Factor.Difference(vdouble18, vdouble16__0_) Details: [0] System.ArgumentException: Gamma is not assignable from Gaussian for result of method DoubleMinusVmpOp.BAverageLogarithm [1] System.ArgumentException: Gaussian is not of type double for argument 2 of method DoubleMinusVmpOp.BAverageLogarithm(Gaussian Difference = Gaussian, double a = Gaussian) [2] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.BAverageLogarithm(double Difference = Gaussian, Gaussian a = Gaussian) [3] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.BAverageLogarithm(double Difference = Gaussian, double a = Gaussian) Error 4: This model is not supported with VariationalMessagePassing due to Factor.IsPositive(bool isPositive, double x). Try using a different algorithm or expressing the model differently in Factor.IsPositive(vdouble19_uses[0]) Details: [0] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [1] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [2] System.ArgumentException: Bernoulli is not of type bool for argument 1 of method IsPositiveOp.XAverageLogarithm(bool isPositive = Bernoulli) Error 5: This model is not supported with VariationalMessagePassing due to Factor.IsPositive(bool isPositive, double x). Try using a different algorithm or expressing the model differently in Factor.IsPositive(vdouble19_uses[1]) Details: [0] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [1] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [2] System.ArgumentException: Bernoulli is not of type bool for argument 1 of method IsPositiveOp.XAverageLogarithm(bool isPositive = Bernoulli) Error 6: This model is not supported with VariationalMessagePassing due to Factor.IsPositive(bool isPositive, double x). Try using a different algorithm or expressing the model differently in Factor.IsPositive(vdouble22) Details: [0] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [1] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [2] System.ArgumentException: Bernoulli is not of type bool for argument 1 of method IsPositiveOp.XAverageLogarithm(bool isPositive = Bernoulli) Error 7: This model is not supported with VariationalMessagePassing due to Factor.Difference(double difference, double a, double b). Try using a different algorithm or expressing the model differently in Factor.Difference(vdouble23, vdouble16_2_0_) Details: [0] System.ArgumentException: Gamma is not of type Gaussian for argument 2 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(Gaussian a = Gaussian, Gaussian b = Gamma) [1] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(double a = Gaussian, Gaussian b = Gamma) [2] System.ArgumentException: Gamma is not of type double for argument 2 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(Gaussian a = Gaussian, double b = Gamma) [3] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.DifferenceAverageLogarithm(double a = Gaussian, double b = Gamma) Error 8: This model is not supported with VariationalMessagePassing due to Factor.Difference(double difference, double a, double b). Try using a different algorithm or expressing the model differently in Factor.Difference(vdouble23, vdouble16_2_0_) Details: [0] System.ArgumentException: Gamma is not of type Gaussian for argument 2 of method DoubleMinusVmpOp.AAverageLogarithm(Gaussian Difference = Gaussian, Gaussian b = Gamma) [1] System.ArgumentException: Gamma is not of type double for argument 2 of method DoubleMinusVmpOp.AAverageLogarithm(Gaussian Difference = Gaussian, double b = Gamma) [2] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.AAverageLogarithm(double Difference = Gaussian, Gaussian b = Gamma) [3] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.AAverageLogarithm(double Difference = Gaussian, double b = Gamma) Error 9: This model is not supported with VariationalMessagePassing due to Factor.Difference(double difference, double a, double b). Try using a different algorithm or expressing the model differently in Factor.Difference(vdouble23, vdouble16_2_0_) Details: [0] System.ArgumentException: Gamma is not assignable from Gaussian for result of method DoubleMinusVmpOp.BAverageLogarithm [1] System.ArgumentException: Gaussian is not of type double for argument 2 of method DoubleMinusVmpOp.BAverageLogarithm(Gaussian Difference = Gaussian, double a = Gaussian) [2] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.BAverageLogarithm(double Difference = Gaussian, Gaussian a = Gaussian) [3] System.ArgumentException: Gaussian is not of type double for argument 1 of method DoubleMinusVmpOp.BAverageLogarithm(double Difference = Gaussian, double a = Gaussian) Error 10: This model is not supported with VariationalMessagePassing due to Factor.IsPositive(bool isPositive, double x). Try using a different algorithm or expressing the model differently in Factor.IsPositive(vdouble24_uses[0]) Details: [0] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [1] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [2] System.ArgumentException: Bernoulli is not of type bool for argument 1 of method IsPositiveOp.XAverageLogarithm(bool isPositive = Bernoulli) Error 11: This model is not supported with VariationalMessagePassing due to Factor.IsPositive(bool isPositive, double x). Try using a different algorithm or expressing the model differently in Factor.IsPositive(vdouble24_uses[1]) Details: [0] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [1] System.ArgumentException: 'x' must not be a derived variable in method IsPositiveOp.XAverageLogarithm [2] System.ArgumentException: Bernoulli is not of type bool for argument 1 of method IsPositiveOp.XAverageLogarithm(bool isPositive = Bernoulli) Source=Infer.Compiler StackTrace: at MicrosoftResearch.Infer.ModelCompiler.GetTransformedDeclaration(ITypeDeclaration itd, MethodBase method, AttributeRegistry`2 inputAttributes) at MicrosoftResearch.Infer.ModelCompiler.CompileWithoutParams(ITypeDeclaration itd, MethodBase method, AttributeRegistry`2 inputAttributes) at MicrosoftResearch.Infer.InferenceEngine.Compile() at MicrosoftResearch.Infer.InferenceEngine.BuildAndCompile(Boolean inferOnlySpecifiedVars, IEnumerable`1 vars) at MicrosoftResearch.Infer.InferenceEngine.GetCompiledInferenceAlgorithm(Boolean inferOnlySpecifiedVars, IVariable var) at MicrosoftResearch.Infer.InferenceEngine.Infer[TReturn](IVariable var) at TrueSkill.MainClass.Main(String[] args) in C:\Users\vladislavsd\Documents\Visual Studio 2017\Projects\TrueSkill\TrueSkill\Program.cs:line 70
Tuesday, November 14, 2017 12:36 AM 
I managed to get this working, at least past compilation error.
My first mistake was to declare and statistically define "drawMargin" as Gamma, not Gaussian. This is what made the compilation fail. But hey, why can't I have "drawMargin" to be Gamma distributed? I do want it to be positive.
After the first mistake was fixed, there was still an exception about "index" out of bounds (???). I ended up rewriting the model slightly:
using (Variable.ForEach(n)) { using (Variable.If(Jperfs[n] < Fperfs[n] + drawMargin  Jperfs[n] < Fperfs[n] + drawMargin)) outcomes[n] = 0; using (Variable.If(Jperfs[n] > Fperfs[n] + drawMargin)) outcomes[n] = 1; using (Variable.If(Fperfs[n] > Jperfs[n] + drawMargin)) outcomes[n] = 2; }
The first case looks bit ugly but it is essentially negation of the 2nd and 3rd case (negation of "A and B" is "not A or not B"). It would've been nicer to write something like Abs(Jperfs[n]  Fperfs[n]) < 2*drawMargin.
One last remark: As I mentioned above, I want "drawMargin" to be positive. So I added the statement:
Variable.ConstrainPositive(drawMargin);
If I remove it, the inference still works and the marginals look the same (when this statement is removed). I am unsure why it works...
Leaving it here for a future traveler.
Tuesday, November 14, 2017 5:47 PM 
drawMargin cannot be Gamma since it leads to an expensive operation of adding Gamma with Gaussian.
You could also use Variable.IsBetween. I don't think you should be doubling drawMargin just because of Abs.
Tuesday, November 14, 2017 6:27 PMOwner