add comments, change constant name, add ProbWin()
This commit is contained in:
1 parent
f4b06ae191
commit
73bc8ffa23
1 file changed
+37
-16
+37
-16
@@ -16,7 +16,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dvolatility float64 = 0.3
|
// system constant, determines delta volatility over time; should be [0.3,1.2]
|
||||||
|
const kDVOL float64 = 0.3
|
||||||
|
|
||||||
// Glicko2 state reprensentation (Glicko2 uses different scales from Glicko)
|
// Glicko2 state reprensentation (Glicko2 uses different scales from Glicko)
|
||||||
type Glicko2 struct {
|
type Glicko2 struct {
|
||||||
@@ -47,6 +48,11 @@ func newGlicko2(rating float64, deviation float64, volatility float64) *Glicko2
|
|||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the probability of beating opponent
|
||||||
|
func (g *Glicko2) ProbWin(opponent *Glicko2) float64 {
|
||||||
|
return 1.0 / (1.0 + math.Pow(10.0, ((opponent.Rating()-g.Rating())/(400.0*math.Sqrt(1.0+0.0000100723986*((g.Deviation()*g.Deviation())+(opponent.Deviation()*opponent.Deviation())))))))
|
||||||
|
}
|
||||||
|
|
||||||
// Get the current rating. This rating is a Glicko rating, not a Glicko2 rating.
|
// Get the current rating. This rating is a Glicko rating, not a Glicko2 rating.
|
||||||
// For details, please see http://www.glicko.com/
|
// For details, please see http://www.glicko.com/
|
||||||
func (g *Glicko2) Rating() float64 {
|
func (g *Glicko2) Rating() float64 {
|
||||||
@@ -127,12 +133,12 @@ func (g *Glicko2) Print() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// util func
|
// util func 'g'
|
||||||
func calcG(deviation float64) float64 {
|
func calcG(deviation float64) float64 {
|
||||||
return 1.0 / (math.Sqrt(1.0 + 3.0*(deviation*deviation)/(math.Pi*math.Pi)))
|
return 1.0 / (math.Sqrt(1.0 + 3.0*(deviation*deviation)/(math.Pi*math.Pi)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// util func
|
// util func 'E'
|
||||||
func calcE(rating float64, rating_opponent float64, deviation_opponent float64) float64 {
|
func calcE(rating float64, rating_opponent float64, deviation_opponent float64) float64 {
|
||||||
return 1.0 / (1.0 + math.Exp(-calcG(deviation_opponent)*(rating-rating_opponent)))
|
return 1.0 / (1.0 + math.Exp(-calcG(deviation_opponent)*(rating-rating_opponent)))
|
||||||
}
|
}
|
||||||
@@ -143,13 +149,26 @@ func (g *Glicko2) Update() {
|
|||||||
// merge wins, losses, draws slices for convenience
|
// merge wins, losses, draws slices for convenience
|
||||||
results := append(append(g.wins, g.losses...), g.draws...)
|
results := append(append(g.wins, g.losses...), g.draws...)
|
||||||
|
|
||||||
// bail if no opponents set
|
// Note that if a player does not compete during the rating period, then
|
||||||
|
// only Step 6 applies.
|
||||||
if len(results) == 0 {
|
if len(results) == 0 {
|
||||||
g.deviation = math.Sqrt((g.deviation * g.deviation) + (g.volatility * g.volatility))
|
g.deviation = math.Sqrt((g.deviation * g.deviation) + (g.volatility * g.volatility))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute variance
|
// Step 1. Determine a rating and RD for each player at the onset of the
|
||||||
|
// rating period. The system constant which constrains the change in
|
||||||
|
// volatility over time, needs to be set prior to application of the system.
|
||||||
|
// Reasonable choices are between 0.3 and 1.2, though the system should be
|
||||||
|
// tested to decide which value results in greatest predictive accuracy
|
||||||
|
// ... (ratings already stored in instance)
|
||||||
|
|
||||||
|
// Step 2. For each player, convert the ratings and RD's onto the Glicko-2
|
||||||
|
// scale.
|
||||||
|
// ... (ratings already stored in G2 format)
|
||||||
|
|
||||||
|
// Step 3. Compute the quantity v. This is the estimated variance of the
|
||||||
|
// team's/player's rating based only on game outcomes.
|
||||||
variance := 0.0
|
variance := 0.0
|
||||||
for _, r := range results {
|
for _, r := range results {
|
||||||
g_i := calcG(r.deviation)
|
g_i := calcG(r.deviation)
|
||||||
@@ -158,7 +177,9 @@ func (g *Glicko2) Update() {
|
|||||||
}
|
}
|
||||||
variance = 1.0 / variance
|
variance = 1.0 / variance
|
||||||
|
|
||||||
// compute delta
|
// Step 4. Compute the quantity 'delta', the estimated improvement in rating
|
||||||
|
// by comparing the pre-period rating to the performance rating based only
|
||||||
|
// on game outcomes.
|
||||||
delta := 0.0
|
delta := 0.0
|
||||||
for _, r := range g.wins {
|
for _, r := range g.wins {
|
||||||
delta += calcG(r.deviation) * (1.0 - calcE(g.rating, r.rating, r.deviation))
|
delta += calcG(r.deviation) * (1.0 - calcE(g.rating, r.rating, r.deviation))
|
||||||
@@ -171,7 +192,7 @@ func (g *Glicko2) Update() {
|
|||||||
}
|
}
|
||||||
delta *= variance
|
delta *= variance
|
||||||
|
|
||||||
// determine new volatility
|
// Step 5. Determine the new value of the volatility.
|
||||||
new_volatility := 0.0
|
new_volatility := 0.0
|
||||||
a := math.Log((g.volatility * g.volatility))
|
a := math.Log((g.volatility * g.volatility))
|
||||||
x := 0.0
|
x := 0.0
|
||||||
@@ -179,17 +200,17 @@ func (g *Glicko2) Update() {
|
|||||||
for math.Abs(x-x_new) > 0.0000001 {
|
for math.Abs(x-x_new) > 0.0000001 {
|
||||||
x = x_new
|
x = x_new
|
||||||
d := (g.deviation * g.deviation) + variance + math.Exp(x)
|
d := (g.deviation * g.deviation) + variance + math.Exp(x)
|
||||||
h1 := -(x-a)/(dvolatility*dvolatility) - 0.5*math.Exp(x)/d + 0.5*math.Exp(x)*(delta/d)*(delta/d)
|
h1 := -(x-a)/(kDVOL*kDVOL) - 0.5*math.Exp(x)/d + 0.5*math.Exp(x)*(delta/d)*(delta/d)
|
||||||
h2 := -1.0/(dvolatility*dvolatility) - 0.5*math.Exp(x)*((g.deviation*g.deviation)+variance)/(d*d) + 0.5*(delta*delta)*math.Exp(x)*((g.deviation*g.deviation)+variance-math.Exp(x))/(d*d*d)
|
h2 := -1.0/(kDVOL*kDVOL) - 0.5*math.Exp(x)*((g.deviation*g.deviation)+variance)/(d*d) + 0.5*(delta*delta)*math.Exp(x)*((g.deviation*g.deviation)+variance-math.Exp(x))/(d*d*d)
|
||||||
x_new = x - h1/h2
|
x_new = x - h1/h2
|
||||||
}
|
}
|
||||||
new_volatility = math.Exp(x_new / 2.0)
|
new_volatility = math.Exp(x_new / 2.0)
|
||||||
|
|
||||||
// update the rating deviation to the new pre-rating period value
|
// Step 6. Update the rating deviation to the new pre-rating period value.
|
||||||
pre_deviation := math.Sqrt((g.deviation * g.deviation) + (new_volatility * new_volatility))
|
pre_deviation := math.Sqrt((g.deviation * g.deviation) + (new_volatility * new_volatility))
|
||||||
|
|
||||||
// update the rating and deviation
|
// Step 7. Update the rating and RD to the new values.
|
||||||
new_deviation := 1.0 / (math.Sqrt(1.0/(pre_deviation * pre_deviation) + 1.0/variance))
|
new_deviation := 1.0 / (math.Sqrt(1.0/(pre_deviation*pre_deviation) + 1.0/variance))
|
||||||
new_rating := 0.0
|
new_rating := 0.0
|
||||||
for _, r := range g.wins {
|
for _, r := range g.wins {
|
||||||
new_rating += calcG(r.deviation) * (1.0 - calcE(g.rating, r.rating, r.deviation))
|
new_rating += calcG(r.deviation) * (1.0 - calcE(g.rating, r.rating, r.deviation))
|
||||||
@@ -203,11 +224,11 @@ func (g *Glicko2) Update() {
|
|||||||
new_rating = new_rating * (new_deviation * new_deviation)
|
new_rating = new_rating * (new_deviation * new_deviation)
|
||||||
new_rating += g.rating
|
new_rating += g.rating
|
||||||
|
|
||||||
// wipe our result lists
|
// Step 8. Convert ratings and RD's back to original scale.
|
||||||
g.ClearResults()
|
|
||||||
|
|
||||||
// copy new values
|
|
||||||
g.deviation = new_deviation
|
g.deviation = new_deviation
|
||||||
g.volatility = new_volatility
|
g.volatility = new_volatility
|
||||||
g.rating = new_rating
|
g.rating = new_rating
|
||||||
|
|
||||||
|
// wipe our result lists
|
||||||
|
g.ClearResults()
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user