def testMultiplication(self): standard_normal = Gaussian(0, 1) shifted_gaussian = Gaussian(2, 3) product = standard_normal * shifted_gaussian self.assertAlmostEqual( 0.2, product.mean, None, "testMultiplication mean expected %.15f, got %.15f" % (0.2, product.mean), GaussianDistributionTest.ERROR_TOLERANCE) self.assertAlmostEqual( 3.0 / sqrt(10), product.stdev, None, "testMultiplication stdev expected %.15f, got %.15f" % (0.2, product.mean), GaussianDistributionTest.ERROR_TOLERANCE) m4s5 = Gaussian(4, 5) m6s7 = Gaussian(6, 7) product2 = m4s5 * m6s7 expectedMean = (4.0 * 7.0**2 + 6.0 * 5.0**2) / (5.0**2 + 7.0**2) self.assertAlmostEqual( expectedMean, product2.mean, None, "testMultiplication mean2 expected %.15f, got %.15f" % (expectedMean, product2.mean), GaussianDistributionTest.ERROR_TOLERANCE) expectedSigma = sqrt((5.0**2 * 7.0**2) / (5.0**2 + 7.0**2)) self.assertAlmostEqual( expectedSigma, product2.stdev, None, "testMultiplication stdev2 expected %.15f, got %.15f" % (expectedSigma, product2.stdev), GaussianDistributionTest.ERROR_TOLERANCE)
def __init__(self, mean, variance, variable): GaussianFactor.__init__(self, "Prior value going to %s" % variable) self.new_message = Gaussian(mean, sqrt(variance)) new_message = Message(Gaussian.from_precision_mean(0, 0), "message from %s to %s" % (self, variable)) self.create_variable_to_message_binding_with_message( variable, new_message)
def testDivision(self): product = Gaussian(0.2, 3.0 / sqrt(10)) standard_normal = Gaussian(0.0, 1.0) product_divided_by_standard_normal = product / standard_normal self.assertAlmostEqual( 2.0, product_divided_by_standard_normal.mean, None, "testDivision mean expected %.15f, got %.15f" % (2.0, product_divided_by_standard_normal.mean), GaussianDistributionTest.ERROR_TOLERANCE) self.assertAlmostEqual( 3.0, product_divided_by_standard_normal.stdev, None, "testDivision stdev expected %.15f, got %.15f" % (3.0, product_divided_by_standard_normal.stdev), GaussianDistributionTest.ERROR_TOLERANCE) product2 = Gaussian((4.0 * 7.0**2 + 6.0 * 5.0**2) / (5.0**2 + 7.0**2), sqrt((5.0**2 * 7.0**2) / (5.0**2 + 7.0**2))) m4s5 = Gaussian(4.0, 5.0) product2divided_by_m4s5 = product2 / m4s5 self.assertAlmostEqual( 6.0, product2divided_by_m4s5.mean, None, "testDivision mean2 expected %.15f, got %.15f" % (6.0, product2divided_by_m4s5.mean), GaussianDistributionTest.ERROR_TOLERANCE) self.assertAlmostEqual( 7.0, product2divided_by_m4s5.stdev, None, "testDivision stdev2 expected %.15f, got %.15f" % (7.0, product2divided_by_m4s5.stdev), GaussianDistributionTest.ERROR_TOLERANCE)
def log_normalization(self): marginal = self.variables[0].value message = self.messages[0].value message_from_variable = marginal / message return (-Gaussian.log_product_normalization(message_from_variable, message) + log(Gaussian.cumulative_to((message_from_variable.mean - self.epsilon) / message_from_variable.stdev)))
def testLogRatioNormalization(self): m1s2 = Gaussian(1.0, 2.0) m3s4 = Gaussian(3.0, 4.0) lrn = Gaussian.log_ratio_normalization(m1s2, m3s4) answer = 2.6157405972171204 self.assertAlmostEqual( answer, lrn, None, "testLogRatioNormalization lrn expected %.15f, got %.15f" % (answer, lrn), GaussianDistributionTest.ERROR_TOLERANCE)
def log_normalization(self): marginal = self.variables[0].value message = self.messages[0].value message_from_variable = marginal / message mean = message_from_variable.mean std = message_from_variable.stdev z = (Gaussian.cumulative_to((self.epsilon - mean) / std) - Gaussian.cumulative_to((-self.epsilon - mean) / std)) return -Gaussian.log_product_normalization(message_from_variable, message) + log(z)
def log_normalization(self): marginal = self.variables[0].value message = self.messages[0].value message_from_variable = marginal / message return ( -Gaussian.log_product_normalization(message_from_variable, message) + log( Gaussian.cumulative_to( (message_from_variable.mean - self.epsilon) / message_from_variable.stdev)))
def log_normalization(self): marginal = self.variables[0].value message = self.messages[0].value message_from_variable = marginal / message mean = message_from_variable.mean std = message_from_variable.stdev z = (Gaussian.cumulative_to( (self.epsilon - mean) / std) - Gaussian.cumulative_to( (-self.epsilon - mean) / std)) return -Gaussian.log_product_normalization(message_from_variable, message) + log(z)
def partial_update(self, prior, full_posterior, update_percentage): prior_gaussian = Gaussian(prior.mean, prior.stdev) posterior_gaussian = Gaussian(full_posterior.mean, full_posterior.stdev) partial_precision_diff = update_percentage * (posterior_gaussian.precision - prior_gaussian.precision) partial_precision_mean_diff = update_percentage * (posterior_gaussian.precision_mean - prior_gaussian.precision_mean) partial_posterior_gaussian = Gaussian.from_precision_mean( prior_gaussian.precision_mean + partial_precision_mean_diff, prior_gaussian.precision + partial_precision_diff) return Rating(partial_posterior_gaussian.mean, partial_posterior_gaussian.stdev)
def testLogProductNormalization(self): standard_normal = Gaussian(0, 1) lpn = Gaussian.log_product_normalization(standard_normal, standard_normal) answer = -1.2655121234846454 self.assertAlmostEqual(answer, lpn, None, "testLogProductNormalization lpn expected %.15f, got %.15f" % (answer, lpn), GaussianDistributionTest.ERROR_TOLERANCE) m1s2 = Gaussian(1.0, 2.0) m3s4 = Gaussian(3.0, 4.0) lpn2 = Gaussian.log_product_normalization(m1s2, m3s4) answer = -2.5168046699816684 self.assertAlmostEqual(answer, lpn2, None, "testLogProductNormalization lpn2 expected %.15f, got %.15f" % (answer, lpn2), GaussianDistributionTest.ERROR_TOLERANCE)
def testCumulativeTo(self): expected = 0.691462461274013 answer = Gaussian.cumulative_to(0.5) self.assertAlmostEqual( expected, answer, None, "testCumulativeTo expected %.15f, got %.15f" % (expected, answer), GaussianDistributionTest.ERROR_TOLERANCE)
def update_message_variable(self, message, variable): old_marginal = copy(variable.value) old_message = copy(message.value) message_from_var = old_marginal / old_message c = message_from_var.precision d = message_from_var.precision_mean sqrt_c = sqrt(c) d_on_sqrt_c = d / sqrt_c epsilon_times_sqrt_c = self.epsilon * sqrt_c d = message_from_var.precision_mean denom = 1.0 - w_exceeds_margin(d_on_sqrt_c, epsilon_times_sqrt_c) new_precision = c / denom new_precision_mean = (d + sqrt_c * v_exceeds_margin( d_on_sqrt_c, epsilon_times_sqrt_c)) / denom new_marginal = Gaussian.from_precision_mean(new_precision_mean, new_precision) new_message = (old_message * new_marginal) / old_marginal message.value = new_message variable.value = new_marginal return new_marginal - old_marginal
def create_variable_to_message_binding(self, variable): new_distribution = Gaussian.from_precision_mean(0.0, 0.0) binding = Factor.create_variable_to_message_binding_with_message( self, variable, Message(new_distribution, "message from %s to %s" % (self, variable))) return binding
def log_normalization(self): result = 0.0 for i in range(1, len(self.variables)): result += Gaussian.log_ratio_normalization(self.variables[i].value, self.messages[i].value) return result
def testAt(self): expected = 0.352065326764300 answer = Gaussian.at(0.5) self.assertAlmostEqual( expected, answer, None, "testAt expected %.15f, got %.15f" % (expected, answer), GaussianDistributionTest.ERROR_TOLERANCE)
def update_message_variable(self, message, variable): old_marginal = copy(variable.value) old_message = copy(message.value) message_from_var = old_marginal / old_message c = message_from_var.precision d = message_from_var.precision_mean sqrt_c = sqrt(c) d_on_sqrt_c = d / sqrt_c epsilon_times_sqrt_c = self.epsilon * sqrt_c d = message_from_var.precision_mean denom = 1.0 - w_exceeds_margin(d_on_sqrt_c, epsilon_times_sqrt_c) new_precision = c / denom new_precision_mean = (d + sqrt_c * v_exceeds_margin(d_on_sqrt_c, epsilon_times_sqrt_c)) / denom new_marginal = Gaussian.from_precision_mean(new_precision_mean, new_precision) new_message = (old_message * new_marginal) / old_marginal message.value = new_message variable.value = new_marginal return new_marginal - old_marginal
def testSubtraction(self): standard_normal = Gaussian(0.0, 1.0) abs_diff = standard_normal - standard_normal self.assertAlmostEqual( 0.0, abs_diff, None, "testAbsoluteDifference abs_diff expected %.15f, got %.15f" % (0.0, abs_diff), GaussianDistributionTest.ERROR_TOLERANCE) m1s2 = Gaussian(1.0, 2.0) m3s4 = Gaussian(3.0, 4.0) abs_diff2 = m1s2 - m3s4 answer = 0.4330127018922193 self.assertAlmostEqual( 0.0, abs_diff, None, "testAbsoluteDifference abs_diff2 expected %.15f, got %.15f" % (answer, abs_diff2), GaussianDistributionTest.ERROR_TOLERANCE)
def w_within_margin(team_performance_difference, draw_margin): team_performance_difference_abs = abs(team_performance_difference) denominator = (Gaussian.cumulative_to(draw_margin - team_performance_difference_abs) - Gaussian.cumulative_to(-draw_margin - team_performance_difference_abs)) if denominator < 2.222758749e-162: return 1.0 vt = v_within_margin(team_performance_difference_abs, draw_margin) return (vt ** 2 + ( (draw_margin - team_performance_difference_abs) * Gaussian.at(draw_margin - team_performance_difference_abs) - (-draw_margin - team_performance_difference_abs) * Gaussian.at(-draw_margin - team_performance_difference_abs)) / denominator)
def create_variable_to_message_binding(self, variable): new_distribution = Gaussian.from_precision_mean(0.0, 0.0) binding = Factor.create_variable_to_message_binding_with_message( self, variable, Message(new_distribution, "message from {} to {}".format(self, variable)) ) return binding
def v_within_margin(team_performance_difference, draw_margin): team_performance_difference_abs = abs(team_performance_difference) denominator = ( Gaussian.cumulative_to(draw_margin - team_performance_difference_abs) - Gaussian.cumulative_to(-draw_margin - team_performance_difference_abs)) if denominator < 2.222758749e-162: if team_performance_difference < 0.0: return -team_performance_difference - draw_margin return -team_performance_difference + draw_margin numerator = (Gaussian.at(-draw_margin - team_performance_difference_abs) - Gaussian.at(draw_margin - team_performance_difference_abs)) if team_performance_difference < 0.0: return -numerator / denominator return numerator / denominator
def w_within_margin(team_performance_difference, draw_margin): team_performance_difference_abs = abs(team_performance_difference) denominator = ( Gaussian.cumulative_to(draw_margin - team_performance_difference_abs) - Gaussian.cumulative_to(-draw_margin - team_performance_difference_abs)) if denominator < 2.222758749e-162: return 1.0 vt = v_within_margin(team_performance_difference_abs, draw_margin) return (vt**2 + ((draw_margin - team_performance_difference_abs) * Gaussian.at(draw_margin - team_performance_difference_abs) - (-draw_margin - team_performance_difference_abs) * Gaussian.at(-draw_margin - team_performance_difference_abs)) / denominator)
def testLogRatioNormalization(self): m1s2 = Gaussian(1.0, 2.0) m3s4 = Gaussian(3.0, 4.0) lrn = Gaussian.log_ratio_normalization(m1s2, m3s4) answer = 2.6157405972171204 self.assertAlmostEqual(answer, lrn, None, "testLogRatioNormalization lrn expected %.15f, got %.15f" % (answer, lrn), GaussianDistributionTest.ERROR_TOLERANCE)
def w_exceeds_margin(team_performance_difference, draw_margin): denominator = Gaussian.cumulative_to(team_performance_difference - draw_margin) if denominator < 2.222758749e-162: if team_performance_difference < 0.0: return 1.0 return 0.0 v_win = v_exceeds_margin(team_performance_difference, draw_margin) return v_win * (v_win + team_performance_difference - draw_margin)
def testLogProductNormalization(self): standard_normal = Gaussian(0, 1) lpn = Gaussian.log_product_normalization(standard_normal, standard_normal) answer = -1.2655121234846454 self.assertAlmostEqual( answer, lpn, None, "testLogProductNormalization lpn expected %.15f, got %.15f" % (answer, lpn), GaussianDistributionTest.ERROR_TOLERANCE) m1s2 = Gaussian(1.0, 2.0) m3s4 = Gaussian(3.0, 4.0) lpn2 = Gaussian.log_product_normalization(m1s2, m3s4) answer = -2.5168046699816684 self.assertAlmostEqual( answer, lpn2, None, "testLogProductNormalization lpn2 expected %.15f, got %.15f" % (answer, lpn2), GaussianDistributionTest.ERROR_TOLERANCE)
def update_message_variable(self, message, variable): old_marginal = copy(variable.value) old_message = message new_marginal = Gaussian.from_precision_mean( old_marginal.precision_mean + self.new_message.precision_mean - old_message.value.precision_mean, old_marginal.precision + self.new_message.precision - old_message.value.precision) variable.value = new_marginal new_message = self.new_message message.value = new_message return old_marginal - new_marginal
def __init__(self, teams, team_ranks, game_info): game_info = TrueSkillGameInfo.ensure_game_info(game_info) FactorGraph.__init__(self) self.prior_layer = PlayerPriorValuesToSkillsLayer(self, teams) self.game_info = game_info new_factory = VariableFactory(lambda: Gaussian.from_precision_mean(0.0, 0.0)) self.variable_factory = new_factory self.layers = [ self.prior_layer, PlayerSkillsToPerformancesLayer(self), PlayerPerformancesToTeamPerformancesLayer(self), IteratedTeamDifferencesInnerLayer(self, TeamPerformancesToTeamPerformanceDifferencesLayer(self), TeamDifferencesComparisonLayer(self, team_ranks)) ]
def __init__(self, teams, team_ranks, game_info): game_info = TrueSkillGameInfo.ensure_game_info(game_info) FactorGraph.__init__(self) self.prior_layer = PlayerPriorValuesToSkillsLayer(self, teams) self.game_info = game_info new_factory = VariableFactory( lambda: Gaussian.from_precision_mean(0.0, 0.0)) self.variable_factory = new_factory self.layers = [ self.prior_layer, PlayerSkillsToPerformancesLayer(self), PlayerPerformancesToTeamPerformancesLayer(self), IteratedTeamDifferencesInnerLayer( self, TeamPerformancesToTeamPerformanceDifferencesLayer(self), TeamDifferencesComparisonLayer(self, team_ranks)) ]
def __init__(self, initial_mean=DEFAULT_INITIAL_MEAN, stdev=DEFAULT_INITIAL_STANDARD_DEVIATION, beta=DEFAULT_BETA, dynamics_factor=DEFAULT_DYNAMICS_FACTOR, draw_probability=DEFAULT_DRAW_PROBABILITY, conservative_stdev_multiplier=DEFAULT_CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER): try: self.initial_mean = float(initial_mean) self.initial_stdev = float(stdev) self.beta = float(beta) self.dynamics_factor = float(dynamics_factor) self.draw_probability = float(draw_probability) self.conservative_stdev_multiplier = float(conservative_stdev_multiplier) self.draw_margin = float(Gaussian.inverse_cumulative_to(0.5 * (self.draw_probability + 1), 0, 1) * sqrt(1 + 1) * self.beta) except ValueError: raise ValueError("TrueSkillGameInfo arguments must be numeric")
def update_helper(self, weights, weights_squared, messages, variables): message0 = copy(messages[0].value) marginal0 = copy(variables[0].value) inverse_of_new_precision_sum = 0.0 another_inverse_of_new_precision_sum = 0.0 weighted_mean_sum = 0.0 another_weighted_mean_sum = 0.0 for i in range(len(weights_squared)): inverse_of_new_precision_sum += weights_squared[i] / ( variables[i + 1].value.precision - messages[i + 1].value.precision) diff = variables[i + 1].value / messages[i + 1].value another_inverse_of_new_precision_sum += weights_squared[ i] / diff.precision weighted_mean_sum += (weights[i] * (variables[i + 1].value.precision_mean - messages[i + 1].value.precision_mean) / (variables[i + 1].value.precision - messages[i + 1].value.precision)) another_weighted_mean_sum += weights[ i] * diff.precision_mean / diff.precision new_precision = 1.0 / inverse_of_new_precision_sum #another_new_precision = 1.0 / another_inverse_of_new_precision_sum new_precision_mean = new_precision * weighted_mean_sum #another_new_precision_mean = another_new_precision * another_weighted_mean_sum new_message = Gaussian.from_precision_mean(new_precision_mean, new_precision) old_marginal_without_message = marginal0 / message0 new_marginal = old_marginal_without_message * new_message messages[0].value = new_message variables[0].value = new_marginal final_diff = new_marginal - marginal0 return final_diff
def update_helper(self, message1, message2, variable1, variable2): message1_value = copy(message1.value) message2_value = copy(message2.value) marginal1 = copy(variable1.value) marginal2 = copy(variable2.value) a = self.precision / (self.precision + marginal2.precision - message2_value.precision) new_message = Gaussian.from_precision_mean( a * (marginal2.precision_mean - message2_value.precision_mean), a * (marginal2.precision - message2_value.precision)) old_marginal_without_message = marginal1 / message1_value new_marginal = old_marginal_without_message * new_message message1.value = new_message variable1.value = new_marginal return new_marginal - marginal1
def __init__( self, initial_mean=DEFAULT_INITIAL_MEAN, stdev=DEFAULT_INITIAL_STANDARD_DEVIATION, beta=DEFAULT_BETA, dynamics_factor=DEFAULT_DYNAMICS_FACTOR, draw_probability=DEFAULT_DRAW_PROBABILITY, conservative_stdev_multiplier=DEFAULT_CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER ): try: self.initial_mean = float(initial_mean) self.initial_stdev = float(stdev) self.beta = float(beta) self.dynamics_factor = float(dynamics_factor) self.draw_probability = float(draw_probability) self.conservative_stdev_multiplier = float( conservative_stdev_multiplier) self.draw_margin = float( Gaussian.inverse_cumulative_to( 0.5 * (self.draw_probability + 1), 0, 1) * sqrt(1 + 1) * self.beta) except ValueError: raise ValueError("TrueSkillGameInfo arguments must be numeric")
def update_helper(self, weights, weights_squared, messages, variables): message0 = copy(messages[0].value) marginal0 = copy(variables[0].value) inverse_of_new_precision_sum = 0.0 another_inverse_of_new_precision_sum = 0.0 weighted_mean_sum = 0.0 another_weighted_mean_sum = 0.0 for i in range(len(weights_squared)): inverse_of_new_precision_sum += weights_squared[i] / (variables[i + 1].value.precision - messages[i + 1].value.precision) diff = variables[i + 1].value / messages[i + 1].value another_inverse_of_new_precision_sum += weights_squared[i] / diff.precision weighted_mean_sum += (weights[i] * (variables[i + 1].value.precision_mean - messages[i + 1].value.precision_mean) / (variables[i + 1].value.precision - messages[i + 1].value.precision)) another_weighted_mean_sum += weights[i] * diff.precision_mean / diff.precision new_precision = 1.0 / inverse_of_new_precision_sum # another_new_precision = 1.0 / another_inverse_of_new_precision_sum new_precision_mean = new_precision * weighted_mean_sum # another_new_precision_mean = another_new_precision * another_weighted_mean_sum new_message = Gaussian.from_precision_mean(new_precision_mean, new_precision) old_marginal_without_message = marginal0 / message0 new_marginal = old_marginal_without_message * new_message messages[0].value = new_message variables[0].value = new_marginal final_diff = new_marginal - marginal0 return final_diff
def v_exceeds_margin(team_performance_difference, draw_margin): denominator = Gaussian.cumulative_to(team_performance_difference - draw_margin) if (denominator < 2.22275874e-162): return -team_performance_difference + draw_margin return Gaussian.at(team_performance_difference - draw_margin) / denominator
def send_message_variable(self, message, variable): marginal = variable.value message_value = message.value log_z = Gaussian.log_product_normalization(marginal, message_value) variable.value = marginal * message_value return log_z
def testCumulativeTo(self): expected = 0.691462461274013 answer = Gaussian.cumulative_to(0.5) self.assertAlmostEqual(expected, answer, None, "testCumulativeTo expected %.15f, got %.15f" % (expected, answer), GaussianDistributionTest.ERROR_TOLERANCE)
def log_normalization(self): return Gaussian.log_ratio_normalization(self.variables[0].value, self.messages[0].value)
def testAt(self): expected = 0.352065326764300 answer = Gaussian.at(0.5) self.assertAlmostEqual(expected, answer, None, "testAt expected %.15f, got %.15f" % (expected, answer), GaussianDistributionTest.ERROR_TOLERANCE)
def __init__(self, mean, variance, variable): GaussianFactor.__init__(self, "Prior value going to %s" % variable) self.new_message = Gaussian(mean, sqrt(variance)) new_message = Message(Gaussian.from_precision_mean(0, 0), "message from %s to %s" % (self, variable)) self.create_variable_to_message_binding_with_message(variable, new_message)
def log_normalization(self): return Gaussian.log_ratio_normalization( self.variables[0].value, self.messages[0].value )