using System; using Moserware.Numerics; namespace Moserware.Skills { /// /// Container for a player's rating. /// public class Rating { private const int ConservativeStandardDeviationMultiplier = 3; private readonly double _ConservativeStandardDeviationMultiplier; private readonly double _Mean; private readonly double _StandardDeviation; /// /// Constructs a rating. /// /// The statistical mean value of the rating (also known as μ). /// The standard deviation of the rating (also known as σ). public Rating(double mean, double standardDeviation) : this(mean, standardDeviation, ConservativeStandardDeviationMultiplier) { } /// /// Constructs a rating. /// /// The statistical mean value of the rating (also known as μ). /// The standard deviation (the spread) of the rating (also known as σ). /// The number of s to subtract from the to achieve a conservative rating. public Rating(double mean, double standardDeviation, double conservativeStandardDeviationMultiplier) { _Mean = mean; _StandardDeviation = standardDeviation; _ConservativeStandardDeviationMultiplier = conservativeStandardDeviationMultiplier; } /// /// The statistical mean value of the rating (also known as μ). /// public double Mean { get { return _Mean; } } /// /// The standard deviation (the spread) of the rating. This is also known as σ. /// public double StandardDeviation { get { return _StandardDeviation; } } /// /// A conservative estimate of skill based on the mean and standard deviation. /// public double ConservativeRating { get { return _Mean - ConservativeStandardDeviationMultiplier*_StandardDeviation; } } public static Rating GetPartialUpdate(Rating prior, Rating fullPosterior, double updatePercentage) { var priorGaussian = new GaussianDistribution(prior.Mean, prior.StandardDeviation); var posteriorGaussian = new GaussianDistribution(fullPosterior.Mean, fullPosterior.StandardDeviation); // From a clarification email from Ralf Herbrich: // "the idea is to compute a linear interpolation between the prior and posterior skills of each player // ... in the canonical space of parameters" double precisionDifference = posteriorGaussian.Precision - priorGaussian.Precision; double partialPrecisionDifference = updatePercentage*precisionDifference; double precisionMeanDifference = posteriorGaussian.PrecisionMean - priorGaussian.PrecisionMean; double partialPrecisionMeanDifference = updatePercentage*precisionMeanDifference; GaussianDistribution partialPosteriorGaussion = GaussianDistribution.FromPrecisionMean( priorGaussian.PrecisionMean + partialPrecisionMeanDifference, priorGaussian.Precision + partialPrecisionDifference); return new Rating(partialPosteriorGaussion.Mean, partialPosteriorGaussion.StandardDeviation, prior._ConservativeStandardDeviationMultiplier); } public override string ToString() { // As a debug helper, display a localized rating: return String.Format( "μ={0:0.0000}, σ={1:0.0000}", Mean, StandardDeviation); } } }