Skip to content

Commit 874ebc5

Browse files
authored
Fix PlackettLuce rating adjustment for ties. (#176)
1 parent d5226bc commit 874ebc5

File tree

4 files changed

+56
-23
lines changed

4 files changed

+56
-23
lines changed

changes/176.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix PlackettLuce rating adjustment for ties.

openskill/models/weng_lin/plackett_luce.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ def _compute(
848848
delta += (
849849
i_mu_over_ce_over_sum_q * (1 - i_mu_over_ce_over_sum_q) / a[q]
850850
)
851-
if team_q.rank == team_i.rank:
851+
if q == i:
852852
omega += (1 - i_mu_over_ce_over_sum_q) / a[q]
853853
else:
854854
omega -= i_mu_over_ce_over_sum_q / a[q]

tests/models/data/plackettluce.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,21 @@
8686
],
8787
"team_2": [
8888
{
89-
"mu": 23.083700519022745,
89+
"mu": 20.599656070925114,
9090
"sigma": 8.222674397835641
9191
},
9292
{
93-
"mu": 21.717476072569045,
93+
"mu": 20.47545384852023,
9494
"sigma": 8.277466291367071
9595
}
9696
],
9797
"team_3": [
9898
{
99-
"mu": 21.717476072569045,
99+
"mu": 20.47545384852023,
100100
"sigma": 8.277466291367071
101101
},
102102
{
103-
"mu": 23.083700519022745,
103+
"mu": 20.599656070925114,
104104
"sigma": 8.222674397835641
105105
}
106106
],
@@ -160,7 +160,7 @@
160160
"ties": {
161161
"team_1": [
162162
{
163-
"mu": 23.241111866333558,
163+
"mu": 21.63766806988004,
164164
"sigma": 8.310709773172306
165165
}
166166
],
@@ -176,15 +176,15 @@
176176
],
177177
"team_3": [
178178
{
179-
"mu": 21.479966996534408,
179+
"mu": 19.87652320008089,
180180
"sigma": 8.237522411103104
181181
},
182182
{
183-
"mu": 21.479966996534408,
183+
"mu": 19.87652320008089,
184184
"sigma": 8.237522411103104
185185
},
186186
{
187-
"mu": 21.479966996534408,
187+
"mu": 19.87652320008089,
188188
"sigma": 8.237522411103104
189189
}
190190
]
@@ -261,4 +261,4 @@
261261
}
262262
]
263263
}
264-
}
264+
}

tests/models/weng_lin/test_common.py

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -205,20 +205,52 @@ def test_ladder_pairs():
205205

206206
@pytest.mark.parametrize("model", MODELS)
207207
@pytest.mark.parametrize("tie_score", [-1, 0, 0.1, 10, 13.4])
208-
def test_ties(model, tie_score):
208+
@pytest.mark.parametrize("num_teams", [2, 5, 10])
209+
@pytest.mark.parametrize("team_size", [1, 2, 5, 10])
210+
@pytest.mark.parametrize("tie_type", ["score", "rank"])
211+
def test_ties(model, tie_score, num_teams, team_size, tie_type) -> None:
209212
model_instance = model()
213+
teams = [
214+
[model_instance.rating() for _ in range(team_size)] for _ in range(num_teams)
215+
]
216+
player_mu_before = [player.mu for team in teams for player in team]
217+
assert all(
218+
mu == player_mu_before[0] for mu in player_mu_before
219+
), f"Model {model.__name__} with score {tie_score}: All players should start with equal mu"
220+
221+
player_sigma_before = [player.sigma for team in teams for player in team]
222+
assert all(
223+
sigma == player_sigma_before[0] for sigma in player_sigma_before
224+
), f"Model {model.__name__} with score {tie_score}: All players should start with equal sigma"
225+
226+
if tie_type == "score":
227+
scores = [tie_score for _ in range(num_teams)]
228+
new_teams = model_instance.rate(teams, scores=scores)
229+
else: # rank
230+
ranks = [tie_score for _ in range(num_teams)]
231+
new_teams = model_instance.rate(teams, ranks=ranks)
232+
233+
player_mu_after = [player.mu for team in new_teams for player in team]
234+
assert all(
235+
mu_after == mu_before
236+
for mu_after, mu_before in zip(player_mu_after, player_mu_before)
237+
), f"Model {model.__name__} with score {tie_score}: All players should end with equal mu"
238+
player_sigma_after = [player.sigma for team in new_teams for player in team]
239+
assert all(
240+
sigma_after <= sigma_before
241+
for sigma_after, sigma_before in zip(player_sigma_after, player_sigma_before)
242+
), f"Model {model.__name__} with score {tie_score}: All players should end with lower or equal sigma"
210243

211-
player_1 = model_instance.rating()
212-
player_2 = model_instance.rating()
213244

214-
result = model_instance.rate(
215-
[[player_1], [player_2]], scores=[tie_score, tie_score]
216-
)
245+
@pytest.mark.parametrize("model", MODELS)
246+
def test_ties_with_close_ratings(model) -> None:
247+
model_instance = model()
248+
249+
player_1 = model_instance.rating(mu=30)
250+
player_2 = model_instance.rating(mu=20)
251+
252+
new_teams = model_instance.rate([[player_1], [player_2]], ranks=[0, 0])
217253

218-
# Both players should have the same rating change
219-
assert (
220-
result[0][0].mu == result[1][0].mu
221-
), f"Model {model.__name__} with score {tie_score}: Players should have equal mu after tie"
222-
assert (
223-
result[0][0].sigma == result[1][0].sigma
224-
), f"Model {model.__name__} with score {tie_score}: Players should have equal sigma after tie"
254+
# ratings should converge on ties.
255+
assert new_teams[0][0].mu < 30
256+
assert new_teams[1][0].mu > 20

0 commit comments

Comments
 (0)