///////////////////////////////////////////////////////////////////////////// // ELOstat way of computing confidence intervals ///////////////////////////////////////////////////////////////////////////// void CBradleyTerry::ELOstatIntervals(double *peloLower, double *peloUpper) const { // // Loop over players to compute confidence intervals // for (int j = crs.GetPlayers(); --j >= 0;) { // // Loop over opponents // double TotalGames = 0; double TotalScore = 0; for (int k = crs.GetOpponents(j); --k >= 0;) { const CCondensedResult &cr = crs.GetCondensedResult(j, k); TotalGames += cr.Games(); TotalScore += cr.Score(); } double MeanScore = TotalScore / TotalGames; // // Loop again for variance // double TotalVariance = 0; for (int k = crs.GetOpponents(j); --k >= 0;) { const CCondensedResult &cr = crs.GetCondensedResult(j, k); TotalVariance += (cr.w_ij + cr.l_ji)*(1 - MeanScore)*(1 - MeanScore) + (cr.d_ij + cr.d_ji)*(0.5 - MeanScore)*(0.5 - MeanScore) + (cr.w_ji + cr.l_ij)*(0 - MeanScore)*(0 - MeanScore); } if (TotalVariance < 0) TotalVariance = 0; double Variance = TotalVariance / (TotalGames * TotalGames); double StandardDeviation = std::sqrt(Variance); double pLower = ELOstatBound(MeanScore - 1.95996 * StandardDeviation); double pUpper = ELOstatBound(MeanScore + 1.95996 * StandardDeviation); double p = ELOstatBound(MeanScore); double DeltaLower = 400 * std::log10(pLower / (1 - pLower)); double DeltaUpper = 400 * std::log10(pUpper / (1 - pUpper)); double Delta = 400 * std::log10(p / (1 - p)); peloLower[j] = Delta - DeltaLower; peloUpper[j] = DeltaUpper - Delta; } }
///////////////////////////////////////////////////////////////////////////// // ELOstat algorithm ///////////////////////////////////////////////////////////////////////////// void CBradleyTerry::ELOstat(double Epsilon) { double *pElo = &v1[0]; double *pNextElo = &v2[0]; for (int i = crs.GetPlayers(); --i >= 0;) pElo[i] = 0; for (int i = 0; i < 10000; i++) { // // Start by copying ratings // for (int j = crs.GetPlayers(); --j >= 0;) pNextElo[j] = pElo[j]; // // Loop over players to compute their new ratings // double TotalElo = 0; double GrandTotalGames = 0; for (int j = crs.GetPlayers(); --j >= 0;) { double TotalGames = 0; double TotalScore = 0; double TotalOpponentElo = 0; // // Loop over opponents // for (int k = crs.GetOpponents(j); --k >= 0;) { const CCondensedResult &cr = crs.GetCondensedResult(j, k); double Games = cr.Games(); TotalGames += Games; TotalScore += cr.Score(); TotalOpponentElo += Games * pElo[cr.Opponent]; } double p = ELOstatBound(TotalScore / TotalGames); double Delta = 400 * std::log10(p / (1 - p)); pNextElo[j] = TotalOpponentElo / TotalGames + Delta; TotalElo += TotalGames * pNextElo[j]; GrandTotalGames += TotalGames; } // // Normalize and swap // for (int j = crs.GetPlayers(); --j >= 0;) pNextElo[j] -= TotalElo / GrandTotalGames; { double *pd = pElo; pElo = pNextElo; pNextElo = pd; } // // Compute difference // double MaxDiff = 0; for (int j = crs.GetPlayers(); --j >= 0;) { double Diff = std::fabs(pNextElo[j] - pElo[j]); if (Diff > MaxDiff) MaxDiff = Diff; } if (MaxDiff < Epsilon) { std::cout << i + 1 << " iterations\n"; break; } } // // Store computed Elo ratings into vElo // for (int i = crs.GetPlayers(); --i >= 0;) velo[i] = pElo[i]; }