Class: Glicko2::Rating

Inherits:
NormalDistribution show all
Defined in:
lib/glicko2/rating.rb

Constant Summary collapse

GLICKO_GRADIENT =
173.7178
GLICKO_INTERCEPT =
DEFAULT_GLICKO_RATING
MIN_SD =
DEFAULT_GLICKO_RATING_DEVIATION / GLICKO_GRADIENT
TOLERANCE =
0.0000001

Instance Attribute Summary collapse

Attributes inherited from NormalDistribution

#mean, #standard_deviation

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from NormalDistribution

#+, #-, #<=>, #cdf, #pdf, #variance

Constructor Details

#initialize(mean, sd, volatility = nil, config = nil) ⇒ Rating

Returns a new instance of Rating.



10
11
12
13
14
15
# File 'lib/glicko2/rating.rb', line 10

def initialize(mean, sd, volatility=nil, config=nil)
  super(mean, sd)
  @volatility = volatility || DEFAULT_VOLATILITY
  @config = config || DEFAULT_CONFIG
  @e = {}
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



8
9
10
# File 'lib/glicko2/rating.rb', line 8

def config
  @config
end

#volatilityObject (readonly)

Returns the value of attribute volatility.



8
9
10
# File 'lib/glicko2/rating.rb', line 8

def volatility
  @volatility
end

Class Method Details

.from_glicko_rating(r, rd, volatility = nil, config = nil) ⇒ Object



17
18
19
20
# File 'lib/glicko2/rating.rb', line 17

def self.from_glicko_rating(r, rd, volatility=nil, config=nil)
  new((r - GLICKO_INTERCEPT) / GLICKO_GRADIENT, rd / GLICKO_GRADIENT,
      volatility, config)
end

Instance Method Details

#delta(others, scores) ⇒ Numeric

Calculate the estimated improvement in rating by comparing the pre-period rating to the performance rating based only on game outcomes.

Parameters:

  • others (Array<Player>)

    list of opponent players

  • scores (Array<Numeric>)

    list of correlating scores (‘0` for a loss, `0.5` for a draw and `1` for a win).

Returns:

  • (Numeric)


62
63
64
65
66
# File 'lib/glicko2/rating.rb', line 62

def delta(others, scores)
  others.zip(scores).reduce(0) do |d, (other, score)|
    d + other.gravity * (score - expected_fractional_score(other))
  end * estimated_variance(others)
end

#estimated_variance(others) ⇒ Numeric

Calculate the estimated variance of the team’s/player’s rating based only on the game outcomes.

Parameters:

  • others (Array<Player>)

    other participating players.

Returns:

  • (Numeric)


47
48
49
50
51
52
53
# File 'lib/glicko2/rating.rb', line 47

def estimated_variance(others)
  return 0.0 if others.length < 1
  others.reduce(0) do |v, other|
    e_other = expected_fractional_score(other)
    v + other.gravity ** 2 * e_other * (1 - e_other)
  end ** -1
end

#expected_fractional_score(other) ⇒ Numeric

Calculate ‘E(mu, mu_j, phi_j)` as defined in the Glicko2 paper

Parameters:

  • other (Player)

    the ‘j` player

Returns:

  • (Numeric)


38
39
40
# File 'lib/glicko2/rating.rb', line 38

def expected_fractional_score(other)
  @e[other] ||= 1 / (1 + Math.exp(-other.gravity * (mean - other.mean)))
end

#f(x, d, v) ⇒ Numeric

Calculate ‘f(x)` as defined in the Glicko2 paper

Parameters:

Returns:

  • (Numeric)


74
75
76
# File 'lib/glicko2/rating.rb', line 74

def f(x, d, v)
  f_part1(x, d, v) - f_part2(x)
end

#gravityNumeric

Calculate ‘g(phi)` as defined in the Glicko2 paper

Returns:

  • (Numeric)


30
31
32
# File 'lib/glicko2/rating.rb', line 30

def gravity
  @gravity ||= 1 / Math.sqrt(1 + 3 * variance / Math::PI ** 2)
end

#next_mean(others, scores, next_sd) ⇒ Object



114
115
116
117
118
# File 'lib/glicko2/rating.rb', line 114

def next_mean(others, scores, next_sd)
  others.zip(scores).reduce(0) { |x, (other, score)|
    x + other.gravity * (score - expected_fractional_score(other))
  } * next_sd ** 2.0 + mean
end

#next_standard_deviation(v) ⇒ Object



110
111
112
# File 'lib/glicko2/rating.rb', line 110

def next_standard_deviation(v)
  1 / Math.sqrt(1 / standard_deviation_pre ** 2 + 1 / v)
end

#next_volatility(others, scores, v) ⇒ Numeric

Calculate the new value of the volatility

Parameters:

Returns:

  • (Numeric)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/glicko2/rating.rb', line 91

def next_volatility(others, scores, v)
  d, a, b = next_volatility_setup(others, scores, v)
  fa = f(a, d, v)
  fb = f(b, d, v)
  while (b - a).abs > TOLERANCE
    c = a + (a - b) * fa / (fb - fa)
    fc = f(c, d, v)
    if fc * fb < 0
      a = b
      fa = fb
    else
      fa /= 2.0
    end
    b = c
    fb = fc
  end
  Math.exp(a / 2.0)
end

#standard_deviation_preObject

Calculate the pre-game standard deviation

This slightly increases the standard deviation in case the player has been stagnant for a rating period.



82
83
84
# File 'lib/glicko2/rating.rb', line 82

def standard_deviation_pre
  [Math.sqrt(variance + volatility ** 2), MIN_SD].min
end

#to_glicko_ratingObject



22
23
24
25
# File 'lib/glicko2/rating.rb', line 22

def to_glicko_rating
  NormalDistribution.new(GLICKO_GRADIENT * mean + GLICKO_INTERCEPT,
                         GLICKO_GRADIENT * sd)
end

#to_sObject



120
121
122
# File 'lib/glicko2/rating.rb', line 120

def to_s
  "#<Rating mean=#{mean}, sd=#{sd}, volatility=#{volatility}>"
end