Skip to content

Commit f61fb9b

Browse files
committed
Move ReliabilityCalculator class to a separate file
1 parent 383e215 commit f61fb9b

File tree

7 files changed

+87
-87
lines changed

7 files changed

+87
-87
lines changed

core/elo.py

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,4 @@
11
# core/elo.py
2-
import math
3-
4-
import math
5-
6-
import math
7-
8-
9-
class ReliabilityCalculator:
10-
"""
11-
Provides improved reliability metrics for ELO-based ranking systems.
12-
13-
The improved model uses a combination of:
14-
- Quick initial gains (logarithmic component)
15-
- Steady improvement (linear component)
16-
- Asymptotic approach to perfect reliability
17-
18-
The formula is designed to match observed behavior of ELO and Glicko2 systems.
19-
"""
20-
21-
@staticmethod
22-
def calculate_reliability(n: int, v: int) -> float:
23-
"""
24-
Calculate current reliability percentage of the ranking system.
25-
26-
Args:
27-
n: Number of media items in the system (n > 0)
28-
v: Total number of votes cast (v >= 0)
29-
30-
Returns:
31-
float: Reliability percentage between 0-100
32-
"""
33-
if n <= 0 or v < 0:
34-
return 0.0
35-
36-
# Start from 50% (random ordering)
37-
base_reliability = 50.0
38-
39-
# Quick initial gains component
40-
votes_per_item = v / n
41-
initial_gain = 25.0 * (1 - math.exp(-votes_per_item / 2))
42-
43-
# Steady improvement component
44-
steady_gain = 20.0 * (1 - math.exp(-votes_per_item / 10))
45-
46-
# Asymptotic final approach
47-
final_gain = 5.0 * (1 - math.exp(-votes_per_item / 50))
48-
49-
reliability = base_reliability + initial_gain + steady_gain + final_gain
50-
51-
# Cap at 100%
52-
return min(100.0, reliability)
53-
54-
@staticmethod
55-
def calculate_required_votes(n: int, target_reliability: float) -> int:
56-
"""
57-
Calculate votes needed to reach a desired reliability level.
58-
59-
Args:
60-
n: Number of media items in the system (n > 0)
61-
target_reliability: Desired reliability percentage (0 < R < 100)
62-
63-
Returns:
64-
int: Minimum votes required (rounded up to nearest integer)
65-
"""
66-
if n <= 0 or target_reliability <= 50 or target_reliability >= 100:
67-
return 0
68-
69-
# Using binary search to find required votes
70-
low, high = 0, n * 1000
71-
while low < high:
72-
mid = (low + high) // 2
73-
reliability = ReliabilityCalculator.calculate_reliability(n, mid)
74-
75-
if abs(reliability - target_reliability) < 0.1:
76-
return mid
77-
elif reliability < target_reliability:
78-
low = mid + 1
79-
else:
80-
high = mid - 1
81-
82-
return low
832

843

854
class Rating:

core/reliability_calculator.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import math
2+
3+
4+
class ReliabilityCalculator:
5+
"""
6+
Provides improved reliability metrics for ELO-based ranking systems.
7+
8+
The improved model uses a combination of:
9+
- Quick initial gains (logarithmic component)
10+
- Steady improvement (linear component)
11+
- Asymptotic approach to perfect reliability
12+
13+
The formula is designed to match observed behavior of ELO and Glicko2 systems.
14+
"""
15+
16+
@staticmethod
17+
def calculate_reliability(n: int, v: int) -> float:
18+
"""
19+
Calculate current reliability percentage of the ranking system.
20+
21+
Args:
22+
n: Number of media items in the system (n > 0)
23+
v: Total number of votes cast (v >= 0)
24+
25+
Returns:
26+
float: Reliability percentage between 0-100
27+
"""
28+
if n <= 0 or v < 0:
29+
return 0.0
30+
31+
# Start from 50% (random ordering)
32+
base_reliability = 50.0
33+
34+
# Quick initial gains component
35+
votes_per_item = v / n
36+
initial_gain = 25.0 * (1 - math.exp(-votes_per_item / 2))
37+
38+
# Steady improvement component
39+
steady_gain = 20.0 * (1 - math.exp(-votes_per_item / 10))
40+
41+
# Asymptotic final approach
42+
final_gain = 5.0 * (1 - math.exp(-votes_per_item / 50))
43+
44+
reliability = base_reliability + initial_gain + steady_gain + final_gain
45+
46+
# Cap at 100%
47+
return min(100.0, reliability)
48+
49+
@staticmethod
50+
def calculate_required_votes(n: int, target_reliability: float) -> int:
51+
"""
52+
Calculate votes needed to reach a desired reliability level.
53+
54+
Args:
55+
n: Number of media items in the system (n > 0)
56+
target_reliability: Desired reliability percentage (0 < R < 100)
57+
58+
Returns:
59+
int: Minimum votes required (rounded up to nearest integer)
60+
"""
61+
if n <= 0 or target_reliability <= 50 or target_reliability >= 100:
62+
return 0
63+
64+
# Using binary search to find required votes
65+
low, high = 0, n * 1000
66+
while low < high:
67+
mid = (low + high) // 2
68+
reliability = ReliabilityCalculator.calculate_reliability(n, mid)
69+
70+
if abs(reliability - target_reliability) < 0.1:
71+
return mid
72+
elif reliability < target_reliability:
73+
low = mid + 1
74+
else:
75+
high = mid - 1
76+
77+
return low

db/database.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from pathlib import Path
66
from typing import List, Tuple, Optional
77

8-
from core.elo import ReliabilityCalculator
8+
from core.reliability_calculator import ReliabilityCalculator
9+
910
logger = logging.getLogger(__name__)
1011

1112

gui/albums_tab.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from PyQt6.QtCore import pyqtSignal, Qt, QSortFilterProxyModel, QSize
99
import math
1010

11-
from core.elo import ReliabilityCalculator
11+
from core.reliability_calculator import ReliabilityCalculator
1212

1313

1414
class AlbumsTab(QWidget):

gui/voting_tab.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
66
QLabel, QFrame, QSizePolicy)
77

8-
from core.elo import Rating, ReliabilityCalculator
8+
from core.elo import Rating
9+
from core.reliability_calculator import ReliabilityCalculator
910
from core.media_utils import set_file_info, handle_video_single_click, handle_video_events
1011
from core.preview_handler import MediaPreview
1112
from core.media_utils import AspectRatioWidget

tests/test_glicko2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import numpy as np
66
import pytest
77

8-
from core.elo import ReliabilityCalculator, Rating
8+
from core.elo import Rating
9+
from core.reliability_calculator import ReliabilityCalculator
910
from core.glicko2 import Glicko2Rating
1011

1112

@@ -118,7 +119,7 @@ def simulate_and_plot(n: int, seed: int) -> dict:
118119
total_votes += 1
119120

120121
# Record data every 1 votes
121-
if total_votes % 1 == 0:
122+
if total_votes % 10 == 0:
122123
votes_data.append(total_votes)
123124
calc_reliability_data.append(current_calc)
124125

tests/test_reliability.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import matplotlib.pyplot as plt
44
import pytest
55

6-
from core.elo import ReliabilityCalculator, Rating
6+
from core.elo import Rating
7+
from core.reliability_calculator import ReliabilityCalculator
78

89

910
class Media:

0 commit comments

Comments
 (0)