1
1
from bisect import bisect
2
- from math import pi , sqrt , tanh
2
+ from math import inf , pi , sqrt , tanh
3
3
from operator import attrgetter , itemgetter
4
4
5
5
from django .db import transaction
19
19
VAR_LIM = (sqrt (VAR_PER_CONTEST ** 2 + 4 * BETA2 * VAR_PER_CONTEST ) - VAR_PER_CONTEST ) / 2
20
20
SD_LIM = sqrt (VAR_LIM )
21
21
TANH_C = sqrt (3 ) / pi
22
+ PERF_CEILING_INCREMENT = 400
22
23
23
24
24
25
def tie_ranker (iterable , key = attrgetter ('points' )):
@@ -77,17 +78,19 @@ def get_var(times_ranked, cache=[VAR_INIT]):
77
78
return cache [times_ranked ]
78
79
79
80
80
- def recalculate_ratings (ranking , old_mean , times_ranked , historical_p ):
81
+ def recalculate_ratings (ranking , old_mean , times_ranked , historical_p , perf_ceiling ):
81
82
n = len (ranking )
82
83
new_p = [0. ] * n
83
84
new_mean = [0. ] * n
84
85
86
+ updated_bounds = [VALID_RANGE [0 ], min (VALID_RANGE [1 ], perf_ceiling )]
87
+
85
88
# Note: pre-multiply delta by TANH_C to improve efficiency.
86
89
delta = [TANH_C * sqrt (get_var (t ) + VAR_PER_CONTEST + BETA2 ) for t in times_ranked ]
87
90
p_tanh_terms = [(m , d , 1 ) for m , d in zip (old_mean , delta )]
88
91
89
92
# Calculate performance at index i.
90
- def solve_idx (i , bounds = VALID_RANGE ):
93
+ def solve_idx (i , bounds ):
91
94
r = ranking [i ]
92
95
y_tg = 0
93
96
for d , s in zip (delta , ranking ):
@@ -111,8 +114,8 @@ def divconq(i, j):
111
114
new_mean = list (old_mean )
112
115
else :
113
116
# Calculate performance.
114
- solve_idx (0 )
115
- solve_idx (n - 1 )
117
+ solve_idx (0 , updated_bounds )
118
+ solve_idx (n - 1 , updated_bounds )
116
119
divconq (0 , n - 1 )
117
120
118
121
# Calculate mean.
@@ -160,6 +163,9 @@ def rate_contest(contest):
160
163
users = users .exclude (last_rating__lt = contest .rating_floor )
161
164
if contest .rating_ceiling is not None :
162
165
users = users .exclude (last_rating__gt = contest .rating_ceiling )
166
+ perf_ceiling = contest .rating_ceiling + PERF_CEILING_INCREMENT
167
+ else :
168
+ perf_ceiling = inf
163
169
164
170
users = list (users )
165
171
participation_ids = list (map (itemgetter ('id' ), users ))
@@ -176,7 +182,7 @@ def rate_contest(contest):
176
182
idx = user_id_to_idx [h ['user_id' ]]
177
183
historical_p [idx ].append (h ['performance' ])
178
184
179
- rating , mean , performance = recalculate_ratings (ranking , old_mean , times_ranked , historical_p )
185
+ rating , mean , performance = recalculate_ratings (ranking , old_mean , times_ranked , historical_p , perf_ceiling )
180
186
181
187
now = timezone .now ()
182
188
ratings = [Rating (user_id = i , contest = contest , rating = r , mean = m , performance = perf ,
0 commit comments