Skip to content
Browse files

added skills to performances layer

  • Loading branch information...
1 parent e8b928c commit 67feff30377f84d1cff95dcc6762d762452ff153 @larskuhnt larskuhnt committed Apr 15, 2010
View
16 lib/saulabs/gauss/distribution.rb
@@ -17,11 +17,13 @@ class << self
def with_deviation(mean, deviation)
dist = Distribution.new
- dist.mean = mean
- dist.deviation = deviation
- dist.variance = deviation * deviation
- dist.precision = 1 / dist.variance.to_f
- dist.precision_mean = dist.precision * mean
+ if !mean.to_f.nan? and !deviation.to_f.nan? and deviation != 0.0
+ dist.mean = mean
+ dist.deviation = deviation
+ dist.variance = deviation * deviation
+ dist.precision = 1 / dist.variance.to_f
+ dist.precision_mean = dist.precision * mean
+ end
return dist
end
@@ -37,14 +39,14 @@ def absolute_difference(x, y)
[(x.precision_mean - y.precision_mean).abs, Math.sqrt((x.precision - y.precision).abs)].max
end
- def log_product_normalisation(x, y)
+ def log_product_normalization(x, y)
return 0.0 if x.precision == 0.0 || y.precision == 0.0
variance_sum = x.variance + y.variance
mean_diff = x.mean - y.mean
-Functions::LOG_SQRT_2PI - (Math.log(variance_sum) / 2.0) - (mean_diff**2 / 2.0 * variance_sum)
end
- def log_ratio_normalisation(x, y)
+ def log_ratio_normalization(x, y)
return 0.0 if x.precision == 0.0 || y.precision == 0.0
variance_diff = y.variance - x.variance
return 0.0 if variance_diff == 0.0
View
33 lib/saulabs/trueskill/factor_graph.rb
@@ -15,30 +15,31 @@ def initialize(teams, options = {})
@prior_layer = Layers::PriorToSkills.new(self, teams)
@layers = [
- @prior_layer
+ @prior_layer,
+ Layers::SkillsToPerformances.new(self)
]
end
def evaluate
build_layers
run_schedule
+ puts "#{@layers.last.output.flatten.map(&:to_s).join(", ")}<br>"
[ranking_probability, updated_skills]
end
private
def ranking_probability
- factor_list = []
- sum_log_z = 0.0
- sum_log_s = 0.0
- @layers.each do |layer|
- layer.factors.each do |factor|
- factor.reset_marginals
- factor.messages.each_index { |i| sum_log_z += factor.send_message_at(i) }
- sum_log_s += factor.log_normalisation
- end
- end
- Math.exp(sum_log_z + sum_log_s)
+ # factor_list = []
+ # sum_log_z, sum_log_s = 0.0
+ # @layers.each do |layer|
+ # layer.factors.each do |factor|
+ # factor.reset_marginals
+ # factor.messages.each_index { |i| sum_log_z += factor.send_message_at(i) }
+ # sum_log_s += factor.log_normalization
+ # end
+ # end
+ # Math.exp(sum_log_z + sum_log_s)
end
def updated_skills
@@ -55,13 +56,7 @@ def build_layers
end
def run_schedule
- schedules = []
- @layers.each do |layer|
- schedules << layer.create_prior_schedule
- end
- @layers.reverse.each do |layer|
- schedules << layer.create_posterior_schedule
- end
+ schedules = @layers.map(&:prior_schedule) + @layers.reverse.map(&:posterior_schedule)
Schedules::Sequence.new(schedules.compact).visit
end
View
19 lib/saulabs/trueskill/factors/base.rb
@@ -12,21 +12,12 @@ def initialize
@priors = []
end
- def update_message_at(idx)
- raise "illegal message index: #{idx}" if idx < 0 || idx > message_count-1
- update_message(@messages[idx], @bindings[@messages[idx]])
+ def update_message_at(index)
+ raise "Abstract method Factors::Base#update_message_at(index) called"
end
- def update_message(message, variable)
- raise "Abstract method Factors::Base#update_message(message, variable) called"
- end
-
- def message_count
- 0
- end
-
- def log_normalisation
- 0.0
+ def log_normalization
+ raise "Abstract method Factors::Base#log_normalization called"
end
def reset_marginals
@@ -38,7 +29,7 @@ def send_message_at(idx)
end
def send_message(message, variable)
- log_z = Gauss::Distribution.log_product_normalisation(message, variable)
+ log_z = Gauss::Distribution.log_product_normalization(message, variable)
variable.replace(message * variable)
return log_z
end
View
46 lib/saulabs/trueskill/factors/likelihood.rb
@@ -0,0 +1,46 @@
+module Saulabs
+ module TrueSkill
+ module Factors
+
+ class Likelihood < Base
+
+ def initialize(beta_squared, variable1, variable2)
+ super()
+ @precision = 1.0 / beta_squared
+ bind(variable1)
+ bind(variable2)
+ end
+
+ def update_message_at(index)
+ raise "illegal message index: #{index}" if index < 0 || index > 1
+ case index
+ when 0 then update_helper(@messages[0], @messages[1], @bindings[@messages[0]], @bindings[@messages[1]])
+ when 1 then update_helper(@messages[1], @messages[0], @bindings[@messages[1]], @bindings[@messages[0]])
+ end
+ end
+
+ def log_normalization
+ Gauss::Distribution.log_ratio_normalization(@bindings[@messages[0]], @messages[0])
+ end
+
+ private
+
+ def update_helper(message1, message2, variable1, variable2)
+ a = @precision / (@precision + variable2.precision - message2.precision)
+ # puts "#{a}<br>"
+ new_message = Gauss::Distribution.with_precision(
+ a * (variable2.precision_mean - message2.precision_mean),
+ a * (variable2.precision - message2.precision)
+ )
+ new_marginal = (variable1 / message1) * new_message
+ diff = new_marginal - variable1
+ message1.replace(new_message)
+ variable1.replace(new_marginal)
+ return diff
+ end
+
+ end
+
+ end
+ end
+end
View
10 lib/saulabs/trueskill/factors/prior.rb
@@ -4,14 +4,16 @@ module Factors
class Prior < Base
- #
def initialize(mean, variance, variable)
super()
@message = Gauss::Distribution.with_variance(mean, variance)
bind(variable)
end
- def update_message(message, variable)
+ def update_message_at(index)
+ raise "illegal message index: #{index}" if index < 0 || index > 0
+ message = @messages[index]
+ variable = @bindings[@messages[index]]
new_marginal = Gauss::Distribution.with_precision(
variable.precision_mean + @message.precision_mean - message.precision_mean,
variable.precision + @message.precision - message.precision
@@ -22,8 +24,8 @@ def update_message(message, variable)
return diff
end
- def message_count
- 1
+ def log_normalization
+ 0.0
end
end
View
4 lib/saulabs/trueskill/layers/base.rb
@@ -17,11 +17,11 @@ def build
raise "Abstract method Layers::Base#build called"
end
- def create_prior_schedule
+ def prior_schedule
nil
end
- def create_posterior_schedule
+ def posterior_schedule
nil
end
View
2 lib/saulabs/trueskill/layers/prior_to_skills.rb
@@ -21,7 +21,7 @@ def build
end
end
- def create_prior_schedule
+ def prior_schedule
Schedules::Sequence.new(@factors.map { |f| Schedules::Step.new(f, 0) })
end
View
31 lib/saulabs/trueskill/layers/skills_to_performances.rb
@@ -0,0 +1,31 @@
+module Saulabs
+ module TrueSkill
+ module Layers
+
+ class SkillsToPerformances < Base
+
+ def build
+ @input.each do |team|
+ team_performances = []
+ team.each do |skill|
+ variable = Gauss::Distribution.new
+ @factors << Factors::Likelihood.new(@graph.beta_squared, skill, variable)
+ team_performances << variable
+ end
+ @output << team_performances
+ end
+ end
+
+ def prior_schedule
+ Schedules::Sequence.new(@factors.map { |f| Schedules::Step.new(f, 0) })
+ end
+
+ def posterior_schedule
+ Schedules::Sequence.new(@factors.map { |f| Schedules::Step.new(f, 1) })
+ end
+
+ end
+
+ end
+ end
+end
View
18 lib/saulabs/trueskill/rating.rb
@@ -0,0 +1,18 @@
+module Saulabs
+ module TrueSkill
+
+ class Rating
+
+ attr_accessor :skill, :activity, :tau, :tau_squared
+
+ def initialize(mean, deviation, activity, inactive_since)
+ @skill = Gauss::Distribution.with_deviation(mean, deviation)
+ @activity = activity
+ @tau = 0.1
+ @tau_squared = @tau**2
+ end
+
+ end
+
+ end
+end
View
2 spec/saulabs/trueskill/factor_graph_spec.rb
@@ -4,7 +4,7 @@
before :each do
@teams = create_teams
- @graph = TrueSkill::FactorGraph.new(@teams, :tau => 0.1, :beta => 20, :draw_probability => 0.0)
+ @graph = TrueSkill::FactorGraph.new(@teams, :tau => 0.5, :beta => 0.1, :draw_probability => 0.0)
end
describe "#evaluate" do
View
4 spec/saulabs/trueskill/layers/prior_to_skills_spec.rb
@@ -24,14 +24,14 @@
end
- describe "#create_prior_schedule" do
+ describe "#prior_schedule" do
before :each do
@layer.build
end
it "should return a sequence-schedule" do
- @layer.create_prior_schedule.should be_kind_of(TrueSkill::Schedules::Sequence)
+ @layer.prior_schedule.should be_kind_of(TrueSkill::Schedules::Sequence)
end
end

0 comments on commit 67feff3

Please sign in to comment.
Something went wrong with that request. Please try again.