diff --git a/changes/174.bugfix.rst b/changes/174.bugfix.rst new file mode 100644 index 0000000..8398258 --- /dev/null +++ b/changes/174.bugfix.rst @@ -0,0 +1 @@ +Fix rank calculation for ties. diff --git a/openskill/models/weng_lin/bradley_terry_full.py b/openskill/models/weng_lin/bradley_terry_full.py index 9a9efb6..1066cf1 100644 --- a/openskill/models/weng_lin/bradley_terry_full.py +++ b/openskill/models/weng_lin/bradley_terry_full.py @@ -1071,7 +1071,7 @@ def _calculate_rankings( if ranks: team_scores = [] for index, _ in enumerate(game): - team_scores.append(ranks[index] or index) + team_scores.append(ranks[index] if ranks[index] is not None else index) else: team_scores = [i for i, _ in enumerate(game)] diff --git a/openskill/models/weng_lin/bradley_terry_part.py b/openskill/models/weng_lin/bradley_terry_part.py index db50085..284db1e 100644 --- a/openskill/models/weng_lin/bradley_terry_part.py +++ b/openskill/models/weng_lin/bradley_terry_part.py @@ -1067,7 +1067,7 @@ def _calculate_rankings( if ranks: team_scores = [] for index, _ in enumerate(game): - team_scores.append(ranks[index] or index) + team_scores.append(ranks[index] if ranks[index] is not None else index) else: team_scores = [i for i, _ in enumerate(game)] diff --git a/openskill/models/weng_lin/plackett_luce.py b/openskill/models/weng_lin/plackett_luce.py index df02399..44c8e4d 100644 --- a/openskill/models/weng_lin/plackett_luce.py +++ b/openskill/models/weng_lin/plackett_luce.py @@ -1132,7 +1132,7 @@ def _calculate_rankings( if ranks: team_scores = [] for index, _ in enumerate(game): - team_scores.append(ranks[index] or index) + team_scores.append(ranks[index] if ranks[index] is not None else index) else: team_scores = [i for i, _ in enumerate(game)] diff --git a/openskill/models/weng_lin/thurstone_mosteller_full.py b/openskill/models/weng_lin/thurstone_mosteller_full.py index 413cb39..1f09e59 100644 --- a/openskill/models/weng_lin/thurstone_mosteller_full.py +++ b/openskill/models/weng_lin/thurstone_mosteller_full.py @@ -1119,7 +1119,7 @@ def _calculate_rankings( if ranks: team_scores = [] for index, _ in enumerate(game): - team_scores.append(ranks[index] or index) + team_scores.append(ranks[index] if ranks[index] is not None else index) else: team_scores = [i for i, _ in enumerate(game)] diff --git a/openskill/models/weng_lin/thurstone_mosteller_part.py b/openskill/models/weng_lin/thurstone_mosteller_part.py index c54afc3..cb07500 100644 --- a/openskill/models/weng_lin/thurstone_mosteller_part.py +++ b/openskill/models/weng_lin/thurstone_mosteller_part.py @@ -1110,7 +1110,7 @@ def _calculate_rankings( if ranks: team_scores = [] for index, _ in enumerate(game): - team_scores.append(ranks[index] or index) + team_scores.append(ranks[index] if ranks[index] is not None else index) else: team_scores = [i for i, _ in enumerate(game)] diff --git a/tests/models/weng_lin/test_common.py b/tests/models/weng_lin/test_common.py index b0b9399..44e8cd7 100644 --- a/tests/models/weng_lin/test_common.py +++ b/tests/models/weng_lin/test_common.py @@ -81,7 +81,7 @@ def test_calculate_rankings(model) -> None: assert model._calculate_rankings([]) == [] assert model._calculate_rankings([], []) == [] assert model._calculate_rankings([a, b, c, d]) == [0, 1, 2, 3] - assert model._calculate_rankings([a, b], [0, 0]) == [0, 1] + assert model._calculate_rankings([a, b], [0, 0]) == [0, 0] assert model._calculate_rankings([a, b, c, d], [1, 2, 3, 4]) == [0, 1, 2, 3] assert model._calculate_rankings([a, b, c, d], [1, 1, 3, 4]) == [0, 0, 2, 3] assert model._calculate_rankings([a, b, c, d], [1, 2, 3, 3]) == [0, 1, 2, 2] @@ -201,3 +201,24 @@ def test_ladder_pairs(): assert _ladder_pairs([1, 2]) == [[2], [1]] assert _ladder_pairs([1, 2, 3]) == [[2], [1, 3], [2]] assert _ladder_pairs([1, 2, 3, 4]) == [[2], [1, 3], [2, 4], [3]] + + +@pytest.mark.parametrize("model", MODELS) +@pytest.mark.parametrize("tie_score", [-1, 0, 0.1, 10, 13.4]) +def test_ties(model, tie_score): + model_instance = model() + + player_1 = model_instance.rating() + player_2 = model_instance.rating() + + result = model_instance.rate( + [[player_1], [player_2]], scores=[tie_score, tie_score] + ) + + # Both players should have the same rating change + assert ( + result[0][0].mu == result[1][0].mu + ), f"Model {model.__name__} with score {tie_score}: Players should have equal mu after tie" + assert ( + result[0][0].sigma == result[1][0].sigma + ), f"Model {model.__name__} with score {tie_score}: Players should have equal sigma after tie"