trueskill-ranked 0.9b
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/TrueSkill.rb +33 -0
- data/lib/TrueSkill/Array.rb +0 -0
- data/lib/TrueSkill/FactorGraph/Factor.rb +17 -0
- data/lib/TrueSkill/FactorGraph/LikelihoodFactor.rb +27 -0
- data/lib/TrueSkill/FactorGraph/PriorFactor.rb +17 -0
- data/lib/TrueSkill/FactorGraph/SumFactor.rb +65 -0
- data/lib/TrueSkill/FactorGraph/TruncateFactor.rb +28 -0
- data/lib/TrueSkill/FactorGraph/Variable.rb +47 -0
- data/lib/TrueSkill/Mathematics/general.rb +24 -0
- data/lib/TrueSkill/Mathematics/guassian.rb +38 -0
- data/lib/TrueSkill/Rating.rb +23 -0
- data/lib/TrueSkill/TrueSkill.rb +235 -0
- data/lib/TrueSkill/core_ext.rb +0 -0
- data/lib/TrueSkill/general.rb +71 -0
- metadata +59 -0
data/lib/TrueSkill.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
%w(
|
5
|
+
general
|
6
|
+
guassian
|
7
|
+
).each do |name|
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "TrueSkill", "Mathematics", "#{name}.rb"))
|
9
|
+
end
|
10
|
+
|
11
|
+
%w(
|
12
|
+
Factor
|
13
|
+
LikelihoodFactor
|
14
|
+
PriorFactor
|
15
|
+
SumFactor
|
16
|
+
TruncateFactor
|
17
|
+
Variable
|
18
|
+
).each do |name|
|
19
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "TrueSkill", "FactorGraph", "#{name}.rb"))
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
%w(
|
26
|
+
Array
|
27
|
+
core_ext
|
28
|
+
general
|
29
|
+
Rating
|
30
|
+
TrueSkill
|
31
|
+
).each do |name|
|
32
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "TrueSkill", "#{name}.rb"))
|
33
|
+
end
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
class LikelihoodFactor < Factor
|
3
|
+
@mean=nil
|
4
|
+
@value=nil
|
5
|
+
@variance=nil
|
6
|
+
def initialize(mean_var,value_var,variance)
|
7
|
+
super([mean_var,value_var])
|
8
|
+
@mean=mean_var
|
9
|
+
@value=value_var
|
10
|
+
@variance=variance
|
11
|
+
end
|
12
|
+
|
13
|
+
def down
|
14
|
+
val=@mean
|
15
|
+
msg=val/@mean[self]
|
16
|
+
pi=1.0/@variance
|
17
|
+
a=pi/(pi+val.pi)
|
18
|
+
return @value.update_message(self,a*msg.pi,a*msg.tau)
|
19
|
+
end
|
20
|
+
|
21
|
+
def up
|
22
|
+
val=@value
|
23
|
+
msg=val/@value[self]
|
24
|
+
a=1.0/(1.0+@variance*msg.pi)
|
25
|
+
return @mean.update_message(self,a*msg.pi,a*msg.tau)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require_relative 'Factor'
|
3
|
+
class PriorFactor < Factor
|
4
|
+
@val=nil
|
5
|
+
@dynamic=0
|
6
|
+
def initialize(var,val,dynamic=0)
|
7
|
+
super([var])
|
8
|
+
@val=val
|
9
|
+
@dynamic=dynamic
|
10
|
+
end
|
11
|
+
|
12
|
+
def down
|
13
|
+
sigma=Math.sqrt(@val.sigma**2 + @dynamic ** 2)
|
14
|
+
value=Gaussian.new @val.mu,sigma
|
15
|
+
var.update_value self,0,0,value
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
class SumFactor < Factor
|
3
|
+
@sum=nil
|
4
|
+
@terms=nil
|
5
|
+
@coeffs=nil
|
6
|
+
def initialize(sum_var,term_vars,coeffs)
|
7
|
+
super([sum_var]+term_vars)
|
8
|
+
@sum=sum_var
|
9
|
+
@terms=term_vars
|
10
|
+
@coeffs=coeffs
|
11
|
+
end
|
12
|
+
|
13
|
+
def down
|
14
|
+
vals=@terms
|
15
|
+
msgs=[]
|
16
|
+
vals.each do |var|
|
17
|
+
msgs << var[self]
|
18
|
+
end
|
19
|
+
update(@sum,vals,msgs,@coeffs)
|
20
|
+
end
|
21
|
+
|
22
|
+
def up(index=0)
|
23
|
+
coeff=@coeffs[index]
|
24
|
+
x=0
|
25
|
+
coeffs=[]
|
26
|
+
@coeffs.each do |c|
|
27
|
+
if x!=index
|
28
|
+
coeffs << -c/coeff
|
29
|
+
end
|
30
|
+
x+=1
|
31
|
+
end
|
32
|
+
coeffs.insert(index,1.0/coeff)
|
33
|
+
vals=@terms.dup
|
34
|
+
vals[index]=@sum
|
35
|
+
msgs=[]
|
36
|
+
vals.each do |var|
|
37
|
+
msgs << var[self]
|
38
|
+
end
|
39
|
+
return update(@terms[index],vals,msgs,coeffs)
|
40
|
+
end
|
41
|
+
|
42
|
+
def update(var,vals,msgs,coeffs)
|
43
|
+
size=coeffs.length-1
|
44
|
+
divs=[]
|
45
|
+
(0..size).each do |x|
|
46
|
+
vl=vals[x]
|
47
|
+
ms=msgs[x]
|
48
|
+
divs << vl/ms
|
49
|
+
end
|
50
|
+
pisum=[]
|
51
|
+
(0..size).each do |x|
|
52
|
+
pisum << coeffs[x]**2/divs[x].pi
|
53
|
+
end
|
54
|
+
pi=1.0/pisum.inject{|sum,x| sum + x }
|
55
|
+
|
56
|
+
tausum=[]
|
57
|
+
(0..size).each do |x|
|
58
|
+
tausum << coeffs[x]*divs[x].mu
|
59
|
+
end
|
60
|
+
tau=pi*tausum.inject{|sum,x| sum + x }
|
61
|
+
return var.update_message(self,pi,tau)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class TruncateFactor < Factor
|
2
|
+
@v_func=nil
|
3
|
+
@w_func=nil
|
4
|
+
@draw_margin=nil
|
5
|
+
|
6
|
+
def initialize(var,v_func,w_func,draw_margin)
|
7
|
+
super([var])
|
8
|
+
@v_func=v_func
|
9
|
+
@w_func=w_func
|
10
|
+
@draw_margin=draw_margin
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def up()
|
15
|
+
val=var
|
16
|
+
msg=var[self]
|
17
|
+
div=val/msg
|
18
|
+
sqrt_pi=Math.sqrt(div.pi)
|
19
|
+
|
20
|
+
v=@v_func.call(div.tau/sqrt_pi,@draw_margin*sqrt_pi)
|
21
|
+
w=@w_func.call(div.tau/sqrt_pi,@draw_margin*sqrt_pi)
|
22
|
+
|
23
|
+
denom=(1.0-w)
|
24
|
+
pi=div.pi/denom
|
25
|
+
tau=(div.tau+sqrt_pi*v)/denom
|
26
|
+
return var.update_value(self,pi,tau)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
class Variable < Gaussian
|
3
|
+
|
4
|
+
|
5
|
+
@delta=nil
|
6
|
+
def initialize()
|
7
|
+
super()
|
8
|
+
@messages={}
|
9
|
+
end
|
10
|
+
|
11
|
+
def set(val)
|
12
|
+
@delta=delta(val)
|
13
|
+
@pi=val.pi
|
14
|
+
@tau=val.tau
|
15
|
+
end
|
16
|
+
def delta(other)
|
17
|
+
return [(@tau-other.tau).abs,Math.sqrt((@pi-other.pi).abs)].max
|
18
|
+
end
|
19
|
+
|
20
|
+
def update_message(factor,pi=0,tau=0,message=nil)
|
21
|
+
if message.nil?
|
22
|
+
message=Gaussian.new(nil,nil,pi,tau)
|
23
|
+
end
|
24
|
+
old_message=self[factor]
|
25
|
+
self[factor]=message
|
26
|
+
return set(self/old_message*message)
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_value(factor,pi=0,tau=0,value=nil)
|
30
|
+
if value.nil?
|
31
|
+
value=Gaussian.new(nil,nil,pi,tau)
|
32
|
+
end
|
33
|
+
old_message=self[factor]
|
34
|
+
self[factor]=value*old_message/self
|
35
|
+
return set(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def [](y)
|
39
|
+
@messages[y]
|
40
|
+
end
|
41
|
+
|
42
|
+
def []=(y,value)
|
43
|
+
@messages[y]=value
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
def ierfcc(p)
|
4
|
+
return -100 if p >= 2.0
|
5
|
+
return 100 if p <= 0.0
|
6
|
+
pp = p < 1.0 ? p : 2 - p
|
7
|
+
t = Math.sqrt(-2*Math.log(pp/2.0)) # Initial guess
|
8
|
+
x = -0.70711*((2.30753 + t*0.27061)/(1.0 + t*(0.99229 + t*0.04481)) - t)
|
9
|
+
[0,1].each do |j|
|
10
|
+
err = Math.erfc(x) - pp
|
11
|
+
x += err/(1.12837916709551257*Math.exp(-(x*x)) - x*err)
|
12
|
+
end
|
13
|
+
p < 1.0 ? x : -x
|
14
|
+
end
|
15
|
+
|
16
|
+
def cdf(x,mu=0,sigma=1)
|
17
|
+
return 0.5*Math.erfc(-(x-mu)/(sigma*Math.sqrt(2)))
|
18
|
+
end
|
19
|
+
def pdf(x,mu=0,sigma=1)
|
20
|
+
return (1/Math.sqrt(2*Math::PI)*sigma.abs)*Math.exp(-(((x-mu)/sigma.abs)**2/2))
|
21
|
+
end
|
22
|
+
def ppf(x,mu=0,sigma=1)
|
23
|
+
return mu-sigma*Math.sqrt(2)*ierfcc(2*x)
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Gaussian
|
2
|
+
attr_accessor :pi,:tau,:mu,:sigma
|
3
|
+
@pi=nil
|
4
|
+
@tau=nil
|
5
|
+
def initialize(mu=nil,sigma=nil,pi=0,tau=0)
|
6
|
+
if not mu.nil?
|
7
|
+
if sigma.nil? or sigma==0.0
|
8
|
+
raise "a variance(sigma^2) should be greater than 0"
|
9
|
+
end
|
10
|
+
pi=sigma**-2
|
11
|
+
tau=pi*mu
|
12
|
+
end
|
13
|
+
@pi=pi
|
14
|
+
@tau=tau
|
15
|
+
end
|
16
|
+
|
17
|
+
def mu
|
18
|
+
@tau/@pi
|
19
|
+
end
|
20
|
+
|
21
|
+
def sigma
|
22
|
+
if @pi.nil? or @pi==0
|
23
|
+
return 1.0/0
|
24
|
+
end
|
25
|
+
return Math.sqrt(1/@pi)
|
26
|
+
end
|
27
|
+
def *(y)
|
28
|
+
pi=@pi+y.pi
|
29
|
+
tau=@tau+y.tau
|
30
|
+
return Gaussian.new(nil,nil,pi,tau)
|
31
|
+
end
|
32
|
+
def /(y)
|
33
|
+
pi=@pi-y.pi
|
34
|
+
tau=@tau-y.tau
|
35
|
+
return Gaussian.new(nil,nil,pi,tau)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
class Rating < Gaussian
|
3
|
+
attr_accessor :exposure
|
4
|
+
def initialize(mu=nil,sigma=nil)
|
5
|
+
if mu.kind_of?(Array)
|
6
|
+
mu,sigma=mu
|
7
|
+
end
|
8
|
+
if mu.nil?
|
9
|
+
mu=g().mu
|
10
|
+
end
|
11
|
+
if sigma.nil?
|
12
|
+
sigma=g().sigma
|
13
|
+
end
|
14
|
+
super(mu,sigma)
|
15
|
+
end
|
16
|
+
|
17
|
+
def exposure
|
18
|
+
return mu-3*sigma
|
19
|
+
end
|
20
|
+
def to_s
|
21
|
+
return "[mu="+mu.to_s+",sigma="+sigma.to_s+"]"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
|
2
|
+
class TrueSkillObject
|
3
|
+
|
4
|
+
attr_accessor :mu,:sigma,:beta,:tau,:draw_probability
|
5
|
+
|
6
|
+
@mu=nil
|
7
|
+
@sigma=nil
|
8
|
+
@beta=nil
|
9
|
+
@tau=nil
|
10
|
+
@draw_probability=nil
|
11
|
+
|
12
|
+
def initialize(mu=MU, sigma=SIGMA, beta=BETA, tau=TAU,draw_probability=DRAW_PROBABILITY)
|
13
|
+
@mu=mu
|
14
|
+
@sigma=sigma
|
15
|
+
@beta=beta
|
16
|
+
@tau=tau
|
17
|
+
@draw_probability=draw_probability
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def Rating(mu=nil,sigma=nil)
|
22
|
+
if mu.nil?
|
23
|
+
mu=@mu
|
24
|
+
end
|
25
|
+
if sigma.nil?
|
26
|
+
sigma=@sigma
|
27
|
+
end
|
28
|
+
return Rating.new mu,sigma
|
29
|
+
end
|
30
|
+
|
31
|
+
def make_as_global
|
32
|
+
return setup(nil,nil,nil,nil,nil,self)
|
33
|
+
end
|
34
|
+
def validate_rating_groups(rating_groups)
|
35
|
+
rating_groups.each do |group|
|
36
|
+
if group.is_a? Rating
|
37
|
+
group=[group,]
|
38
|
+
end
|
39
|
+
if group.length==0
|
40
|
+
raise "each group must contain multiple ratings"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
if rating_groups.length<2
|
44
|
+
raise "need multiple rating groups"
|
45
|
+
end
|
46
|
+
return rating_groups
|
47
|
+
end
|
48
|
+
def build_factor_graph(rating_groups,ranks)
|
49
|
+
ratings=rating_groups.flatten
|
50
|
+
size=ratings.length
|
51
|
+
group_size=rating_groups.length
|
52
|
+
rating_vars=[]
|
53
|
+
size.times { rating_vars << Variable.new}
|
54
|
+
|
55
|
+
perf_vars=[]
|
56
|
+
size.times { perf_vars << Variable.new}
|
57
|
+
|
58
|
+
teamperf_vars=[]
|
59
|
+
group_size.times { teamperf_vars << Variable.new}
|
60
|
+
|
61
|
+
teamdiff_vars=[]
|
62
|
+
(group_size-1).times { teamdiff_vars << Variable.new}
|
63
|
+
|
64
|
+
team_sizes=_team_sizes(rating_groups)
|
65
|
+
get_perf_vars_by_team=lambda do |team|
|
66
|
+
if team > 0
|
67
|
+
start=team_sizes[team-1]
|
68
|
+
else
|
69
|
+
start=0
|
70
|
+
end
|
71
|
+
endv=team_sizes[team]
|
72
|
+
return perf_vars[start,endv]
|
73
|
+
end
|
74
|
+
|
75
|
+
build_rating_layer=lambda do
|
76
|
+
Enumerator.new do |yielder|
|
77
|
+
|
78
|
+
rating_vars.zip(ratings).each do |rating_var,rating|
|
79
|
+
yielder.yield(PriorFactor.new(rating_var,rating,@tau))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
build_perf_layer=lambda do
|
84
|
+
Enumerator.new do |yielder|
|
85
|
+
|
86
|
+
rating_vars.zip(perf_vars).each do |rating_var,perf_var|
|
87
|
+
yielder.yield(LikelihoodFactor.new(rating_var,perf_var,@beta**2))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
build_teamperf_layer=lambda do
|
92
|
+
Enumerator.new do |yielder|
|
93
|
+
teamperf_vars.each_with_index do |teamperf_var,team|
|
94
|
+
child_perf_vars = get_perf_vars_by_team.call(team)
|
95
|
+
yielder.yield(SumFactor.new(teamperf_var,child_perf_vars,[1]*child_perf_vars.length))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
build_teamdiff_layer=lambda do
|
100
|
+
Enumerator.new do |yielder|
|
101
|
+
teamdiff_vars.each_with_index do |teamdiff_var,team|
|
102
|
+
yielder.yield(SumFactor.new(teamdiff_var,teamperf_vars[team,team=2],[+1,-1]))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
build_trunc_layer=lambda do
|
107
|
+
Enumerator.new do |yielder|
|
108
|
+
teamdiff_vars.each_with_index do |teamdiff_var,x|
|
109
|
+
size=0
|
110
|
+
rating_groups[x,x+2].each do |group|
|
111
|
+
size+=group.length
|
112
|
+
end
|
113
|
+
draw_margin=calc_draw_margin(@draw_probability,@beta,size)
|
114
|
+
|
115
|
+
if ranks[x]==ranks[x+1]
|
116
|
+
v_func,w_func=$v_drawFunc,$w_drawFunc
|
117
|
+
else
|
118
|
+
v_func,w_func=$vFunc,$wFunc
|
119
|
+
end
|
120
|
+
yielder.yield(TruncateFactor.new(teamdiff_var,v_func,w_func,draw_margin))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
return Array(build_rating_layer.call),Array(build_perf_layer.call),Array(build_teamperf_layer.call),Array(build_teamdiff_layer.call),Array(build_trunc_layer.call)
|
126
|
+
end
|
127
|
+
|
128
|
+
def run_schedule(rating_layer, perf_layer, teamperf_layer,teamdiff_layer, trunc_layer, min_delta=DELTA)
|
129
|
+
[rating_layer,perf_layer,teamperf_layer].flatten.each do |f|
|
130
|
+
f.down
|
131
|
+
end
|
132
|
+
teamdiff_len=teamdiff_layer.length
|
133
|
+
(10).times do |x|
|
134
|
+
if teamdiff_len==1
|
135
|
+
teamdiff_layer[0].down
|
136
|
+
delta=trunc_layer[0].up
|
137
|
+
else
|
138
|
+
delta=0
|
139
|
+
(teamdiff_len-1).times do |x2|
|
140
|
+
teamdiff_layer[x2].down
|
141
|
+
delta=[delta,trunc_layer[x].up].max
|
142
|
+
teamdiff_layer[x].up(1)
|
143
|
+
end
|
144
|
+
(teamdiff_len-1).step(0,-1) do |x2|
|
145
|
+
teamdiff_layer[x2].down
|
146
|
+
delta=[delta,trunc_layer[x].up].max
|
147
|
+
teamdiff_layer[x].up(0)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
if delta<=min_delta
|
151
|
+
break
|
152
|
+
end
|
153
|
+
end
|
154
|
+
teamdiff_layer.first.up(0)
|
155
|
+
teamdiff_layer.last.up(1)
|
156
|
+
teamperf_layer.each do |f|
|
157
|
+
(f.vars.length-1).times do |x|
|
158
|
+
f.up(x)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
perf_layer.each do |f|
|
162
|
+
f.up
|
163
|
+
end
|
164
|
+
end
|
165
|
+
def transform_ratings(rating_groups, ranks=nil, min_delta=DELTA)
|
166
|
+
rating_groups=validate_rating_groups(rating_groups)
|
167
|
+
group_size=rating_groups.length
|
168
|
+
if ranks.nil?
|
169
|
+
ranks=Array(0..group_size-1)
|
170
|
+
end
|
171
|
+
sorting=ranks.zip(rating_groups).each_with_index.to_a.map {|x| x.reverse}.sort { |x,y| x[1][0] <=> y[1][0]}
|
172
|
+
sorted_groups=[]
|
173
|
+
sorting.each do |x,g|
|
174
|
+
sorted_groups << g[1]
|
175
|
+
end
|
176
|
+
sorted_ranks=ranks.sort()
|
177
|
+
unsorting_hint=[]
|
178
|
+
sorting.each do |x,g|
|
179
|
+
unsorting_hint << x
|
180
|
+
end
|
181
|
+
layers=build_factor_graph(sorted_groups,sorted_ranks)
|
182
|
+
run_schedule(layers[0],layers[1],layers[2],layers[3],layers[4])
|
183
|
+
rating_layer,team_sizes=layers[0],_team_sizes(sorted_groups)
|
184
|
+
transformed_groups=[]
|
185
|
+
([0]+team_sizes.take(team_sizes.size - 1)).zip(team_sizes).each do |start,ending|
|
186
|
+
group=[]
|
187
|
+
rating_layer[start,ending].each do |f|
|
188
|
+
group << Rating.new(f.var.mu,f.var.sigma)
|
189
|
+
end
|
190
|
+
transformed_groups << Array(group)
|
191
|
+
end
|
192
|
+
unsorting=unsorting_hint.zip(transformed_groups).sort { |x,y| x[0]<=>y[0]}
|
193
|
+
output=[]
|
194
|
+
unsorting.each do |x,g|
|
195
|
+
output << g
|
196
|
+
end
|
197
|
+
return output
|
198
|
+
end
|
199
|
+
#def match_quality(rating_groups)
|
200
|
+
#rating_groups=validate_rating_groups(rating_groups)
|
201
|
+
#ratings=rating_groups.flatten
|
202
|
+
#length=ratings.length
|
203
|
+
#mean_rows=[]
|
204
|
+
#ratings.each {|r| mean_rows << [r.mu] }
|
205
|
+
#mean_matrix=Matrix[*mean_rows]
|
206
|
+
#variance_rows=[]
|
207
|
+
#ratings.each {|r| variance_rows << r.sigma**2 }
|
208
|
+
#variance_matrix=Matrix.diagonal *variance_rows
|
209
|
+
#rotated_a_matrix=lambda do
|
210
|
+
# mat=[]
|
211
|
+
# t=0
|
212
|
+
# rating_groups.clip.zip(rating_groups.drop(1)).each_with_index do |y,r|
|
213
|
+
# rline=[]
|
214
|
+
# cur=y[0]
|
215
|
+
# nex=y[1]
|
216
|
+
# z=0
|
217
|
+
# (t..t+cur.length).each do |x|
|
218
|
+
# rline << 1
|
219
|
+
# t+=1
|
220
|
+
# z=x
|
221
|
+
# end
|
222
|
+
# z+=1
|
223
|
+
# (z..z+nex.length).each do |x|
|
224
|
+
# rline << -1
|
225
|
+
# end
|
226
|
+
# mat << rline
|
227
|
+
# end
|
228
|
+
# mat
|
229
|
+
#end
|
230
|
+
#rotated_a_matrix=Matrix[rotated_a_matrix.call]
|
231
|
+
#a_matrix = rotated_a_matrix.transpose()
|
232
|
+
#_ata = (@beta ** 2) * rotated_a_matrix * a_matrix
|
233
|
+
#pp _ata
|
234
|
+
#end
|
235
|
+
end
|
File without changes
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
MU=25.0
|
3
|
+
SIGMA=MU/3
|
4
|
+
BETA=SIGMA/2
|
5
|
+
TAU=SIGMA/100
|
6
|
+
DRAW_PROBABILITY=0.10
|
7
|
+
DELTA=0.001
|
8
|
+
|
9
|
+
|
10
|
+
$vFunc=Proc.new do |diff,draw_margin|
|
11
|
+
x=diff-draw_margin
|
12
|
+
pdf(x)/cdf(x)
|
13
|
+
end
|
14
|
+
|
15
|
+
$wFunc=Proc.new do |diff,draw_margin|
|
16
|
+
x=diff-draw_margin
|
17
|
+
v=$vFunc.call(diff,draw_margin)
|
18
|
+
v*(v+x)
|
19
|
+
end
|
20
|
+
|
21
|
+
$v_drawFunc=Proc.new do |diff,draw_margin|
|
22
|
+
abs_diff=diff.abs
|
23
|
+
a=draw_margin-abs_diff
|
24
|
+
b=-draw_margin-abs_diff
|
25
|
+
denom=cdf(a)-cdf(b)
|
26
|
+
numer=pdf(b)-pdf(a)
|
27
|
+
numer/denom*((diff<0)?-1:1)
|
28
|
+
end
|
29
|
+
$w_drawFunc=Proc.new do |diff,draw_margin|
|
30
|
+
abs_diff=diff.abs
|
31
|
+
a=draw_margin-abs_diff
|
32
|
+
b=-draw_margin-abs_diff
|
33
|
+
denom=cdf(a)-cdf(b)
|
34
|
+
v=$v_drawFunc.call(abs_diff,draw_margin)
|
35
|
+
(v**2)+(a*pdf(a)-b*pdf(b))/denom
|
36
|
+
end
|
37
|
+
|
38
|
+
def calc_draw_probability(draw_margin,beta,size)
|
39
|
+
return 2*cdf(draw_margin*(Math.sqrt(size)*beta))-1
|
40
|
+
end
|
41
|
+
|
42
|
+
def calc_draw_margin(draw_probability, beta, size)
|
43
|
+
return ppf((draw_probability+1)/2.0)*Math.sqrt(size)*beta
|
44
|
+
end
|
45
|
+
|
46
|
+
def _team_sizes(rating_groups)
|
47
|
+
team_sizes=[0]
|
48
|
+
rating_groups.each do |group|
|
49
|
+
team_sizes << group.length+team_sizes.last
|
50
|
+
end
|
51
|
+
team_sizes.delete_at(0)
|
52
|
+
return team_sizes
|
53
|
+
end
|
54
|
+
$global=[]
|
55
|
+
|
56
|
+
def g()
|
57
|
+
if $global.length==0
|
58
|
+
setup()
|
59
|
+
end
|
60
|
+
return $global[0]
|
61
|
+
end
|
62
|
+
def setup(mu=MU, sigma=SIGMA, beta=BETA, tau=TAU,draw_probability=DRAW_PROBABILITY, env=nil)
|
63
|
+
$global.pop
|
64
|
+
if env.nil?
|
65
|
+
$global << TrueSkillObject.new(mu, sigma, beta, tau, draw_probability)
|
66
|
+
else
|
67
|
+
$global << env
|
68
|
+
end
|
69
|
+
return g()
|
70
|
+
end
|
71
|
+
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trueskill-ranked
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9b
|
5
|
+
prerelease: 3
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Katrina Swales
|
9
|
+
- Heungsub Lee
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-06-13 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description: A improved TrueSkill with correct ranking order
|
16
|
+
email: kat.swales@nekokittygames.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/TrueSkill.rb
|
22
|
+
- lib/TrueSkill/Array.rb
|
23
|
+
- lib/TrueSkill/core_ext.rb
|
24
|
+
- lib/TrueSkill/Rating.rb
|
25
|
+
- lib/TrueSkill/general.rb
|
26
|
+
- lib/TrueSkill/TrueSkill.rb
|
27
|
+
- lib/TrueSkill/FactorGraph/Factor.rb
|
28
|
+
- lib/TrueSkill/FactorGraph/LikelihoodFactor.rb
|
29
|
+
- lib/TrueSkill/FactorGraph/PriorFactor.rb
|
30
|
+
- lib/TrueSkill/FactorGraph/SumFactor.rb
|
31
|
+
- lib/TrueSkill/FactorGraph/TruncateFactor.rb
|
32
|
+
- lib/TrueSkill/FactorGraph/Variable.rb
|
33
|
+
- lib/TrueSkill/Mathematics/general.rb
|
34
|
+
- lib/TrueSkill/Mathematics/guassian.rb
|
35
|
+
homepage: http://rubygems.org/gems/trueskill-ranked
|
36
|
+
licenses: []
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>'
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.3.1
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.8.11
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Ranked TrueSkill
|
59
|
+
test_files: []
|