import math
import numpy as np

# Constants
ELO_INITIAL_SCORE = 2000
ELO_SCALE_FACTOR = 400
ELO_MAX_UPDATES = 1000
ELO_CONVERGENCE_THRESHOLD = 1
MIN_COMPARISONS_PER_USER = 1  # Minimum number of comparisons required per user

# Gamma prior parameters for skill values
GAMMA_PRIOR_SHAPE = 5  # a
GAMMA_PRIOR_RATE = 0.1   # b

BETA_PRIOR_ALPHA = 10
BETA_PRIOR_BETA = 2

# Utility functions
def skill_to_elo(skill, offset=0):
    return (np.log(skill) / np.log(10)) * ELO_SCALE_FACTOR + offset

def elo_to_skill(elo, offset=0):
    return np.power(10, (elo - offset) / ELO_SCALE_FACTOR)

# Data models
class QuerySet:
    def __init__(self, items):
        self._items = items
        
    def all(self):
        return self._items
        
    def count(self):
        return len(self._items)
        
    def __iter__(self):
        return iter(self._items)

class Metric:
    def __init__(self):
        self.state = {
            'scores': {},
            'qualities': {},
            'methods': [],
            'raters': [],
            'wins': []
        }

class Session:
    def __init__(self, slates, rater=None):
        self._slates = slates
        self.id = 0  # Dummy ID since we don't need it
        self.rater = rater
        
    @property
    def slates(self):
        return QuerySet(self._slates)

class Slate:
    def __init__(self, ratings):
        self._ratings = ratings
        self.id = 0  # Dummy ID since we don't need it
        
    @property
    def ratings(self):
        return QuerySet(self._ratings)

class Rating:
    def __init__(self, score, stimulus):
        self.score = score
        self.stimulus = stimulus

class Stimulus:
    def __init__(self, name):
        self.name = name 