1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# frozen_string_literal: true
# Port of https://github.com/philihp/openskill.js/blob/main/src/models/plackett-luce.ts
module OpenSkill
class PlackettLuce
#: (Model model) -> void
def initialize(model)
@beta_sq = model.beta_sq
@epsilon = model.epsilon
end
#: (Game game) -> Array[Array[Rating]]
def rate(game)
return game.teams if game.teams.length <= 1
team_ratings = game.team_ratings
c = Util.util_c(team_ratings, @beta_sq)
sum_q = Util.util_sum_q(team_ratings, c)
a = Util.util_a(team_ratings)
team_ratings.map.with_index { |tr, i|
mu_over_ce = Math.exp(tr.mu / c)
omega_sum = 0.0
delta_sum = 0.0
team_ratings.each.with_index
.select {|qr, _| qr.rank <= tr.rank }
.each do |_, q|
quotient = mu_over_ce / sum_q[q]
omega_sum += ((i == q ? 1 : 0) - quotient) / a[q]
delta_sum += (quotient * (1 - quotient)) / a[q]
end
g = Util.gamma(c, team_ratings.length, tr)
omega = omega_sum * (tr.sigma_sq / c)
delta = g * delta_sum * (tr.sigma_sq / c**2)
tr.team.map { |player|
share = player.sigma**2 / tr.sigma_sq
new_mu = player.mu + share * omega
new_sigma = player.sigma * Math.sqrt([1 - share * delta, @epsilon].max)
Rating.new(new_mu, new_sigma)
}
}
end
end
end